Java中的大量常量
我需要在Java应用程序中包含大约1Mbyte的数据,以便在其余的源代码中快速方便地访问。我的主要背景不是java,所以我的最初想法是直接把数据转换成java源代码,定义常数数组的1MbEy,类(而不是C++结构)等等,类似这样的:Java中的大量常量,java,android,Java,Android,我需要在Java应用程序中包含大约1Mbyte的数据,以便在其余的源代码中快速方便地访问。我的主要背景不是java,所以我的最初想法是直接把数据转换成java源代码,定义常数数组的1MbEy,类(而不是C++结构)等等,类似这样的: public final/immutable/const MyClass MyList[] = { { 23012, 22, "Hamburger"} , { 28375, 123, "Kieler"} }; 然而,Java似乎不支持这种构造。这是正确
public final/immutable/const MyClass MyList[] = {
{ 23012, 22, "Hamburger"} ,
{ 28375, 123, "Kieler"}
};
然而,Java似乎不支持这种构造。这是正确的吗?如果是,这个问题的最佳解决方案是什么
注:数据由2个表组成,每个表约有50000条数据记录,需要以各种方式进行搜索。这以后可能需要一些索引,以这种方式保存更多的记录,可能有100万条记录。我希望应用程序能够快速启动,而无需遍历这些记录。一个想法是使用枚举数,但我不确定这是否适合您的实现,这还取决于您计划如何使用数据
public enum Stuff {
HAMBURGER (23012, 22),
KIELER (28375, 123);
private int a;
private int b;
//private instantiation, does not need to be called explicitly.
private Stuff(int a, int b) {
this.a = a;
this.b = b;
}
public int getAvalue() {
return this.a;
}
public int getBvalue() {
return this.b;
}
}
然后可以通过以下方式访问:
Stuff someThing = Stuff.HAMBURGER;
int hamburgerA = Stuff.HAMBURGER.getA() // = 23012
另一个想法是使用初始值设定项来设置类的私有字段。您还可以声明一个静态类(或一组静态类),将指定的值作为方法公开。毕竟,您希望代码能够找到给定名称的值,而不希望该值发生更改 所以:location=MyLibOfConstants.returnHamburgerLocation().zipcode 你可以用lazyinitialization将这些东西存储在一个哈希表中,如果你认为动态计算会浪费时间的话。我个人不会把它放在源代码中 相反,在jar文件中包含一些适当的原始格式的数据(我假设您将打包应用程序或库),并使用或加载它
您可能非常希望使用一个类来封装加载、缓存和提供这些数据,但我看不出将其转换为源代码有什么好处。由于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;
}
}
import java.io.*;
导入java.util.*;
公开课考试{
公共静态void main(字符串…参数)引发IOException{
列表记录=新的ArrayList();
BufferedReader br=新的BufferedReader(新文件读取器(“data.txt”);
字符串s;
而((s=br.readLine())!=null){
字符串[]arr=s.split(“”);
int i=Integer.parseInt(arr[0]);
int j=Integer.parseInt(arr[1]);
添加(新的数据记录(i,j,arr[0]);
}
}
}
类数据记录{
公共最终int i,j;
公共最终字符串s;
公共数据记录(int i、int j、字符串s){
这个。i=i;
这个。j=j;
这个.s=s;
}
}
(注意:扫描仪速度非常慢,所以不要仅仅因为它有一个简单的界面就尝试使用它。请使用某种形式的BufferedReader和split,或StringTokenizer。)
当然,如果将数据转换为二进制格式,效率会得到提高。在这种情况下,您可以使用DataInputStream
(但不要忘记浏览一些BufferedInputStream
或BufferedReader
)
根据您希望访问数据的方式,最好将记录存储在哈希映射(HashMap
)中(使用i
或j
作为键)
如果您希望在JVM加载类文件本身的同时加载数据(大致!),您可以不在方法中进行读取/初始化,而是封装在static{…}
中
对于内存映射方法,请查看java中的
java.nio.channels
-包。尤其是方法
可以找到完整的代码示例
Dan Bornstein(DalvikVM的首席开发人员)在(0:30:00左右)中解释了问题的解决方案。然而,我怀疑这个解决方案是否适用于一兆字节那么多的数据 将数据直接转换为Java源代码,定义1字节的常量数组、类
请注意,类及其结构的大小有严格的限制[ref.缓存不是您所需要的吗? 作为类,它被加载到内存中,而不限于定义的大小,应该和使用常量一样快。。。 实际上,它甚至可以使用某种索引搜索数据(例如使用对象hashcode…) 例如,您可以创建所有数据数组(例如{23012,22,“Hamburger”}),然后创建3个hashmap: map1.put(23012,汉堡市); map2.put(22,汉堡里坦); 地图3.put(“汉堡包”,汉堡包); 这样,您可以根据您拥有的参数在其中一个地图中快速搜索。。。 (但这只有在你的钥匙在地图上是唯一的情况下才有效……这只是一个可以启发你的例子) 在工作中,我们有一个非常大的webapp(80个weblogic实例),它几乎就是我们所做的:到处缓存。从数据库中的countrylist,创建一个缓存 有许多不同类型的缓存,你应该检查链接,选择你需要的。。。
如果我了解您的目标,您可以用Java来定义它:
public final Object[][] myList = {
{ 23012, 22, "Hamburger"} ,
{ 28375, 123, "Kieler"}
};
将数据放入源代码实际上可能不是最快的解决方案,从长远来看也不是。加载Java类相当复杂且缓慢(至少在进行字节码验证的平台上是如此,对Android不太确定) 最快的方法是定义您自己的二进制索引格式。然后您可以将其读取为
字节[]
(可能使用内存映射)甚至是一个RandomAccessFile
,在您开始访问它之前,不以任何方式解释它。这样做的代价是访问它的代码的复杂性。对于固定大小的记录,通过二进制searc访问的记录的排序列表
class MyDataStore
{
FileChannel fc = null;
Map<Integer,Entry> mychace = new HashMap<Integer, Entry>();
int chaceSize = 50000;
ArrayList<Integer> queue = new ArrayList();
static final int entryLength = 100;//byte
void open(File f)throws Exception{fc = f.newByteChannel()}
void close()throws Exception{fc.close();fc = null;}
Entry getEntryAt(int index)
{
if(mychace.contains(index))return mychace.get(index);
long pos = index * entryLength; fc.seek(pos);ByteBuffer
b = new ByteBuffer(100);
fc.read(b);
Entry a = new Entry(b);
queue.add(index);
mychace.put(index,a);
if(queue.size()>chacesize)mychace.remove(queue.remove(0));
return a;
}
}
class Entry{
int a; int b; String s;
public Entry(Bytebuffer bb)
{
a = bb.getInt();
b = bb.getInt();
int size = bb.getInt();
byte[] bin = new byte[size];
bb.get(bin);
s = new String(bin);
}
}