我正在使用ASM Java庫替換一些反射。我生成該方法的主體:使用ASM Java庫進行拆箱
void set(Object object, int fieldIndex, Object value);
利用這種方法產生的,我可以在運行時在對象上設置的字段,而無需使用反射。它效果很好。但是,我發現原始字段失敗。以下是我設置方法的相關部分:
for (int i = 0, n = cachedFields.length; i < n; i++) {
mv.visitLabel(labels[i]);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, targetClassName);
mv.visitVarInsn(ALOAD, 3);
Field field = cachedFields[i].field;
Type fieldType = Type.getType(field.getType());
mv.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldType.getDescriptor());
mv.visitInsn(RETURN);
}
此代碼爲選擇生成案例標籤。它適用於物體,但對於原始圖像我得到這個錯誤:
Expecting to find float on stack
好的,這是有道理的,我需要做拆箱自己。我實現了以下內容:
for (int i = 0, n = cachedFields.length; i < n; i++) {
mv.visitLabel(labels[i]);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, targetClassName);
mv.visitVarInsn(ALOAD, 3);
Field field = cachedFields[i].field;
Type fieldType = Type.getType(field.getType());
switch (fieldType.getSort()) {
case Type.BOOLEAN:
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
break;
case Type.BYTE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
break;
case Type.CHAR:
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
break;
case Type.SHORT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
break;
case Type.INT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
break;
case Type.FLOAT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
break;
case Type.LONG:
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
break;
case Type.DOUBLE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
break;
case Type.ARRAY:
mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor());
break;
case Type.OBJECT:
mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName());
break;
}
mv.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldType.getDescriptor());
mv.visitInsn(RETURN);
}
我已經通過追查,它肯定會進入「案例Type.FLOAT」爲適當的領域,但是,我得到這個錯誤:
Expecting to find object/array on stack
這是我卡住了。對於我的生活,我無法弄清楚爲什麼拆箱不起作用。 「ALOAD,3」將set方法的第三個參數放在堆棧上,應該是Float。有任何想法嗎?
我發現asm-commons庫有一個具有unbox方法的GeneratorAdapter類。但是,我並不想真的想再包括另一個JAR來實現那麼簡單的事情。我查看了GeneratorAdapter的源代碼,它正在做一些非常相似的事情。我試圖修改我的代碼來使用GeneratorAdapter,只是爲了看看它是否工作,但沒有發現它很容易轉換。
謝謝,但我不想依賴額外的asm-commons JAR需要使用GeneratorAdapter。 – NateS 2011-02-09 07:42:40