【问题标题】:Final field value not working in bytecode generation最终字段值在字节码生成中不起作用
【发布时间】:2013-06-23 23:20:43
【问题描述】:

我正在尝试了解课程的运作方式。我正在尝试使用此代码向我的班级添加最终字段

    dout.writeShort(1);//field count
    dout.writeShort(Modifier.PUBLIC|Modifier.STATIC|Modifier.FINAL);//modifiers
    dout.writeShort(utfConstant("jjj"));//name
    dout.writeShort(utfConstant("I"));//signature
    dout.writeShort(1);//attribute count
    dout.writeShort(utfConstant("ConstantValue"));//constant value attribute
    dout.writeShort(2);//size of attribute
    dout.writeShort(intConstant(8));//value

但是当我尝试编译时出现此错误

Exception in thread "main" java.lang.ClassFormatError: Invalid ConstantValue field attribute length 131082 in class file Test
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
    at Bytecode.BytecodeTest$BytecodeClassLoader.buildClass(BytecodeTest.java:161)
    at Bytecode.BytecodeTest.makeClass(BytecodeTest.java:39)
    at Bytecode.BytecodeTest.buildClass(BytecodeTest.java:24)
    at Bytecode.BytecodeTest.main(BytecodeTest.java:17)

这是我的其他代码

private void writeConstantPool(DataOutputStream dout) throws IOException
    {
        dout.writeShort(poolIndex);

        for (Data data : poolMap) 
        {
            int tag = (byte) data.getData()[0];
            dout.writeByte(tag);

            switch (tag) 
            {
            case CONSTANT_Utf8:
                dout.writeUTF((String) data.getData()[1]);
                break;
            case CONSTANT_Class:
                dout.writeShort((Integer) data.getData()[1]);
                break;
            case CONSTANT_Integer:
                dout.writeInt((Integer) data.getData()[1]);
                break;
            default:
                throw new RuntimeException();
            }
        }
    }

    private int utfConstant(String s)
    {
        return constant(CONSTANT_Utf8, s);
    }   

    private int intConstant(int i)
    {
        return constant(CONSTANT_Integer, i);
    }

    private int classConstant(String s) 
    {
        int classNameIndex = utfConstant(s.replace('.', '/'));
        return constant(CONSTANT_Class, classNameIndex);
    }

    private int constant(Object... data) 
    {
        Data constantData = new Data(data);

        if (poolMap.contains(constantData))
            return poolMap.indexOf(constantData)+1;

        poolMap.add(poolIndex-1, constantData);
        return poolIndex++;
    }

    private final Stack<Data> poolMap = new Stack<Data>();
    private int poolIndex = 1;

    private static class Data
    {
        private Object[] data;

        public Data(Object... data)
        {
            this.data = data;
        }

        public Object[] getData()
        {
            return data;
        }

        public boolean equals(Object o)
        {           
            if(o instanceof Data)
            {
                Data other = (Data) o;
                return Arrays.equals(data, other.getData());
            }

            return false;
        }
    }

我这样做的方法是生成所有方法和字段,然后生成常量池,然后我将常量池放在方法和字段之前的字节数组中。

谁能告诉我我做错了什么,如有必要,我可以显示更多代码,另外我认为问题可能出在 intConstant 或常量值属性上。

在使用字节码编辑器查看此内容后,intConstant 方法似乎工作正常,所以我认为这是不起作用的字段代码。我还在字节码编辑器中查看了一个常量,我很困惑。

【问题讨论】:

  • 我曾经不得不处理字节码操作,而我所做的是编写一个简单的 java 类,其中包含与我想要在字节码中执行的源代码等价的源代码。我编译了那个类,然后使用 javap 查看字节码是什么。 JVM 规范也很有帮助。
  • 我知道我已经尝试了这两种方法,并且我查看了字节码中的常量值属性,但我仍然看不出我做错了什么。
  • 你能发布类文件本身吗?我可以看看有什么问题。

标签: java bytecode bytecode-manipulation


【解决方案1】:

我相信属性的length 应该是 32 位整数,而不是 16 位短整数。

【讨论】:

  • 好收获。即使有经验,也很难发现这些东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-23
  • 2017-11-19
  • 1970-01-01
  • 2012-11-29
  • 1970-01-01
相关资源
最近更新 更多