Java中的大量常量

2022-09-03 09:28:18

我需要在Java应用程序中包含大约1 MByte的数据,以便在其余的源代码中非常快速和轻松地访问。我的主要背景不是Java,所以我最初的想法是将数据直接转换为Java源代码,定义1MByte的常量数组,类(而不是C++结构)等,如下所示:

public final/immutable/const MyClass MyList[] = { 
  { 23012, 22, "Hamburger"} , 
  { 28375, 123, "Kieler"}
};

但是,Java似乎不支持这样的结构。这是正确的吗?如果是,那么此问题的最佳解决方案是什么?

注意:数据由2个表组成,每个表约有50000条数据记录,可通过各种方式进行搜索。这可能需要稍后使用一些索引,以这种方式保存的记录(可能是 100 万条记录)。我希望应用程序启动得非常快,而无需循环访问这些记录。


答案 1

我个人不会把它放在源形式。

相反,在 jar 文件中以某种适当的原始格式包含数据(我假设您将打包应用程序或库),并使用 Class.getResourceAsStreamClassLoader.getResourceAsStream 来加载它。

您可能非常希望有一个类来封装加载,缓存和提供这些数据 - 但我看不到将其转换为源代码的好处。


答案 2

由于java字节码文件的限制,类文件不能大于64k iirc。(它们根本不适用于此类数据。

我会在启动程序时加载数据,使用类似于以下代码行的内容:

import java.io.*;
import java.util.*;

public class Test {
    public static void main(String... args) throws IOException {
        List<DataRecord> records = new ArrayList<DataRecord>();
        BufferedReader br = new BufferedReader(new FileReader("data.txt"));
        String s;
        while ((s = br.readLine()) != null) {
            String[] arr = s.split(" ");
            int i = Integer.parseInt(arr[0]);
            int j = Integer.parseInt(arr[1]);
            records.add(new DataRecord(i, j, arr[0]));
        }
    }
}


class DataRecord {
    public final int i, j;
    public final String s;
    public DataRecord(int i, int j, String s) {
        this.i = i;
        this.j = j;
        this.s = s;
    }
}

(铌:扫描仪非常慢,所以不要仅仅因为它有一个简单的界面就试图使用它。坚持使用某种形式的 BufferedReader 和 split,或 StringTokenizer。

当然,如果将数据转换为二进制格式,则可以提高效率。在这种情况下,您可以使用(但不要忘记通过一些或DataInputStreamBufferedInputStreamBufferedReader)

根据您希望访问数据的方式,最好将记录存储在哈希映射()中(具有或作为键)。HashMap<Integer, DataRecord>ij

如果您希望在JVM加载类文件本身的同时加载数据(大致上!),则可以执行读取/初始化,不是在方法中,而是在.static { ... }


对于内存映射方法,请查看 java 中的 -package。特别是方法java.nio.channels

public abstract MappedByteBuffer map(FileChannel.MapMode mode, long position,long size) throws IOException

在此处找到完整的代码示例。


Dan Bornstein(DalvikVM的首席开发人员)在本次演讲中解释了您的问题的解决方案(请看0:30:00)。但是,我怀疑该解决方案适用于与一兆字节一样多的数据。


推荐