Java 海关;“哈希表”;实施:为什么这么慢?(字节码生成)
今天,我回答了一些Java初学者的一个普通问题。过了一会儿,我觉得认真对待他的问题会很有趣,所以我实现了他想要的 我创建了一个用于生成运行时类的简单代码。大部分代码取自模板,唯一可能的更改是声明一些字段。生成的代码可以写成:Java 海关;“哈希表”;实施:为什么这么慢?(字节码生成),java,hashtable,code-generation,bytecode,Java,Hashtable,Code Generation,Bytecode,今天,我回答了一些Java初学者的一个普通问题。过了一会儿,我觉得认真对待他的问题会很有趣,所以我实现了他想要的 我创建了一个用于生成运行时类的简单代码。大部分代码取自模板,唯一可能的更改是声明一些字段。生成的代码可以写成: public class Container implements Storage { private int foo; // user defined (runtime generated) private Object boo; // user d
public class Container implements Storage {
private int foo; // user defined (runtime generated)
private Object boo; // user defined (runtime generated)
public Container() {
super();
}
}
然后使用自定义类加载器将生成的类文件加载到JVM中
然后我实现了类似“静态哈希表”的东西。程序员输入所有可能的键,然后生成一个类(其中每个键作为一个字段)。当我们拥有这个类的实例时,我们还可以使用反射来保存或读取这些生成的字段
下面是一个完整的代码:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Random;
class ClassGenerator extends ClassLoader {
private ArrayList<FieldInfo> fields = new ArrayList<ClassGenerator.FieldInfo>();
public static class FieldInfo {
public final String name;
public final Class<?> type;
public FieldInfo(String name, Class<?> type) {
this.name = name;
this.type = type;
}
}
private static class ComponentTypeInfo {
private final Class<?> type;
private final int arrayDimensions;
public ComponentTypeInfo(Class<?> type, int arrayDimensions) {
this.type = type;
this.arrayDimensions = arrayDimensions;
}
}
private static ComponentTypeInfo getComponentType(Class<?> type) {
Class<?> tmp = type;
int array = 0;
while (tmp.isArray()) {
tmp = tmp.getComponentType();
array++;
}
return new ComponentTypeInfo(tmp, array);
}
public static String getFieldDescriptor(Class<?> type) {
ComponentTypeInfo componentTypeInfo = getComponentType(type);
Class<?> componentTypeClass = componentTypeInfo.type;
int componentTypeArray = componentTypeInfo.arrayDimensions;
String result = "";
for (int i = 0; i < componentTypeArray; i++) {
result += "[";
}
if (componentTypeClass.isPrimitive()) {
if (componentTypeClass.equals(byte.class)) return result + "B";
if (componentTypeClass.equals(char.class)) return result + "C";
if (componentTypeClass.equals(double.class)) return result + "D";
if (componentTypeClass.equals(float.class)) return result + "F";
if (componentTypeClass.equals(int.class)) return result + "I";
if (componentTypeClass.equals(long.class)) return result + "J";
if (componentTypeClass.equals(short.class)) return result + "S";
if (componentTypeClass.equals(boolean.class)) return result + "Z";
throw new RuntimeException("Unknown primitive type.");
} else {
return result + "L" + componentTypeClass.getCanonicalName().replace('.', '/') + ";";
}
}
public void addField(String name, Class<?> type) {
this.fields.add(new FieldInfo(name, type));
}
private Class<?> defineClass(byte[] data) {
return this.defineClass(null, data, 0, data.length);
}
private byte[] toBytes(short[] data) {
byte[] result = new byte[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = (byte) data[i];
}
return result;
}
private byte[] toBytes(short value) {
return new byte[]{(byte) (value >> 8), (byte) (value & 0xFF)};
}
public Class<?> getResult() throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(toBytes(new short[]{
0xCA, 0xFE, 0xBA, 0xBE, // magic
0x00, 0x00, 0x00, 0x33, // version
}));
// constantPoolCount
outputStream.write(toBytes((short) (0x0C + (this.fields.size() * 2))));
// constantPool
outputStream.write(toBytes(new short[]{
0x01, 0x00, 0x09, 'C', 'o', 'n', 't', 'a', 'i', 'n', 'e', 'r',
0x01, 0x00, 0x10, 'j', 'a', 'v', 'a', '/', 'l', 'a', 'n', 'g', '/', 'O', 'b', 'j', 'e', 'c', 't',
0x01, 0x00, 0x06, '<', 'i', 'n', 'i', 't', '>',
0x01, 0x00, 0x03, '(', ')', 'V',
0x01, 0x00, 0x04, 'C', 'o', 'd', 'e',
0x07, 0x00, 0x01, // class Container
0x07, 0x00, 0x02, // class java/lang/Object
0x0C, 0x00, 0x03, 0x00, 0x04, // nameAndType
0x0A, 0x00, 0x07, 0x00, 0x08, // methodRef
0x01, 0x00, 0x07, 'S', 't', 'o', 'r', 'a', 'g', 'e',
0x07, 0x00, 0x0A, // class Storage
}));
for (FieldInfo field : fields) {
String name = field.name;
String descriptor = getFieldDescriptor(field.type);
byte[] nameBytes = name.getBytes();
byte[] descriptorBytes = descriptor.getBytes();
outputStream.write(0x01);
outputStream.write(toBytes((short) nameBytes.length));
outputStream.write(nameBytes);
outputStream.write(0x01);
outputStream.write(toBytes((short) descriptorBytes.length));
outputStream.write(descriptorBytes);
}
outputStream.write(toBytes(new short[]{
0x00, 0x01, // accessFlags,
0x00, 0x06, // thisClass
0x00, 0x07, // superClass
0x00, 0x01, // interfacesCount
0x00, 0x0B // interface Storage
}));
// fields
outputStream.write(toBytes((short) this.fields.size()));
for (int i = 0; i < fields.size(); i++) {
outputStream.write(new byte[]{0x00, 0x01});
outputStream.write(toBytes((short) (12 + 2 * i)));
outputStream.write(toBytes((short) (12 + 2 * i + 1)));
outputStream.write(new byte[]{0x00, 0x00});
}
// methods and rest of the class file
outputStream.write(toBytes(new short[]{
0x00, 0x01, // methodsCount
// void <init>
0x00, 0x01, // accessFlags
0x00, 0x03, // nameIndex
0x00, 0x04, // descriptorIndex,
0x00, 0x01, // attributesCount
0x00, 0x05, // nameIndex
0x00, 0x00, 0x00, 0x11, // length
0x00, 0x01, // maxStack
0x00, 0x01, // maxLocals,
0x00, 0x00, 0x00, 0x05, // codeLength
0x2A, // aload_0
0xB7, 0x00, 0x09, // invokespecial #9
0xB1, // return
0x00, 0x00, // exceptionTableLength
0x00, 0x00, // attributesCount
0x00, 0x00, // attributesCount
}));
return defineClass(outputStream.toByteArray());
}
}
class SuperTable<T> {
private Class<?> generatedClass = null;
private Storage container = null;
public SuperTable(String[] keys, Class<T> type) {
ClassGenerator classGenerator = new ClassGenerator();
for (String key : keys) {
classGenerator.addField(key, type);
}
try {
this.generatedClass = classGenerator.getResult();
this.container = (Storage) generatedClass.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void put(String name, Object value) {
try {
this.generatedClass.getDeclaredField(name).set(container, value);
} catch (Exception e) {
throw new RuntimeException("Such a field doesn't exist or is not accessible.");
}
}
public Object get(String name) {
try {
return this.generatedClass.getDeclaredField(name).get(container);
} catch (Exception e) {
throw new RuntimeException("Such a field doesn't exist or is not accessible.");
}
}
}
public class Test {
private static final String[] keys = new String[(int) Math.pow(26, 3)];
private static final Random randomizer = new Random();
static {
int index = 0;
for (char a = 'a'; a <= 'z'; a++) {
for (char b = 'a'; b <= 'z'; b++) {
for (char c = 'a'; c <= 'z'; c++) {
keys[index] = new String(new char[]{a, b, c});
index++;
}
}
}
}
public static float test1(Hashtable<String, Integer> table, long count) {
long time0 = System.currentTimeMillis();
for (long i = 0; i < count; i++) {
boolean step = randomizer.nextBoolean();
String key = keys[randomizer.nextInt(keys.length)];
if (step) {
table.put(key, randomizer.nextInt());
} else {
table.get(key);
}
}
return System.currentTimeMillis() - time0;
}
public static float test2(SuperTable<Integer> table, long count) {
long time0 = System.currentTimeMillis();
for (long i = 0; i < count; i++) {
boolean step = randomizer.nextBoolean();
String key = keys[randomizer.nextInt(keys.length)];
if (step) {
table.put(key, randomizer.nextInt());
} else {
table.get(key);
}
}
return System.currentTimeMillis() - time0;
}
public static void main(String[] args) throws Exception {
Hashtable<String, Integer> table = new Hashtable<String, Integer>();
SuperTable<Integer> table2 = new SuperTable<Integer>(keys, Integer.class);
long count = 500000;
System.out.printf("Hashtable: %f ms\n", test1(table, count));
System.out.printf("SuperTable: %f ms\n", test2(table2, count));
}
}
import java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.util.ArrayList;
导入java.util.Hashtable;
导入java.util.Random;
类生成器扩展了类加载器{
私有ArrayList字段=新ArrayList();
公共静态类FieldInfo{
公共最终字符串名;
公共期末班类型;
公共字段信息(字符串名称、类类型){
this.name=名称;
this.type=type;
}
}
私有静态类ComponentTypeInfo{
私有最终类类型;
私有最终整数数组维数;
公共组件类型信息(类类型,int-arrayDimensions){
this.type=type;
this.arrayDimensions=arrayDimensions;
}
}
私有静态ComponentTypeInfo getComponentType(类类型){
类别tmp=类型;
int数组=0;
while(tmp.isArray()){
tmp=tmp.getComponentType();
数组++;
}
返回新的ComponentTypeInfo(tmp,数组);
}
公共静态字符串getFieldDescriptor(类类型){
ComponentTypeInfo ComponentTypeInfo=getComponentType(类型);
Class componentTypeClass=componentTypeInfo.type;
int componentTypeArray=componentTypeInfo.arrayDimensions;
字符串结果=”;
对于(int i=0;i>8),(字节)(值&0xFF)};
}
公共类getResult()引发IOException{
ByteArrayOutputStream outputStream=新建ByteArrayOutputStream();
outputStream.write(以字节为单位)(新短[]{
0xCA,0xFE,0xBA,0xBE,//魔法
0x00,0x00,0x00,0x33,//版本
}));
//恒菌落数
write(toBytes((短)(0x0C+(this.fields.size()*2));
//康斯坦普勒
outputStream.write(以字节为单位)(新短[]{
0x01、0x00、0x09、C、o、n、t、a、i、n、e、r、,
0x01,0x00,0x10,'j','a','v','a','/','l','a','n','g','/','O','b','j','e','c','t',',
0x01、0x00、0x06、,
0x01,0x00,0x03,“(”,“)”,“V”,
0x01、0x00、0x04、C、o、d、e、,
0x07,0x00,0x01,//类容器
0x07,0x00,0x02,//类java/lang/Object
0x0C、0x00、0x03、0x00、0x04、//名称和类型
0x0A,0x00,0x07,0x00,0x08,//methodRef
0x01、0x00、0x07、S、t、o、r、a、g、e、,
0x07,0x00,0x0A,//类存储
}));
用于(字段信息字段:字段){
字符串名称=field.name;
字符串描述符=getFieldDescriptor(field.type);
byte[]nameBytes=name.getBytes();
字节[]描述符字节=描述符.getBytes();
outputStream.write(0x01);
write(toBytes((short)nameBytes.length));
outputStream.write(nameBytes);
outputStream.write(0x01);
write(toBytes((短)描述符rbytes.length));
outputStream.write(描述符字节);
}
outputStream.write(以字节为单位)(新短[]{
0x00,0x01,//accessFlags,
0x00,0x06,//这个类
0x00,0x07,//超类
0x00,0x01,//接口计数
0x00,0x0B//接口存储
}));
//田地
write(toBytes((短)this.fields.size());
对于(int i=0;iprivate Field searchFields(Field[] fields, String name) {
String internedName = name.intern();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName() == internedName) {
return getReflectionFactory().copyField(fields[i]);
}
}
return null;
}