gpt4 book ai didi

java - 对字节码和对象的澄清

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:21:32 25 4
gpt4 key购买 nike

我正在编写一个字节码工具。现在,我正试图找出如何在存在物体的情况下做到这一点。我想对我在 JVMS(第 4.9.4 节)中阅读的两行内容进行一些说明:

1) "The verifier rejects code that uses the new object before it has been initialized."

我的问题是,这里的“使用”是什么意思?我猜这意味着:将其作为方法属性传递,调用 GETFIELDPUTFIELD在其上,或在其上调用任何实例方法。他们的其他禁止用途是什么?而且我相信它遵循其他指令,例如 DUP , LOADSTORE是允许的。

2) "Before that method invokes another instance initialization method of myClass or its direct superclass on this, the only operation the method can perform on this is assigning fields declared within myClass."

这意味着在 <init>方法,GETFIELD 和 PUTFIELD 在另一个之前被允许 <init>叫做。但是,在 Java 中,在调用 super() 之前对实例字段执行任何操作或 this()导致编译错误。有人可以澄清一下吗?

3) 我还有一个问题。对象引用何时被初始化,并因此准备好被自由使用?通过阅读 JVMS,我得出了一个答案,即是否初始化一个对象取决于每个方法。在某个时间点,可以为一个方法初始化对象,但不能为另一个方法初始化对象。具体来说,对象在 <init> 时为方法初始化。由该方法调用返回。

例如,考虑 main()方法创建了一个对象并调用了 <init>然后调用父类(super class)的 <init> .从super()回来后, 该对象现在被认为由 <init> 初始化, 但尚未为 main() 初始化.这是否意味着,在 <init>super() 之后,我可以将对象作为参数传递给方法,甚至在从 main() 返回之前。

有人可以确认整个分析是真实的吗?感谢您的时间。

ps:我实际上已经在 Sun 论坛上发布了同样的问题,但没有回应。我希望我能在这里有更多的运气。谢谢。

更新

首先感谢您的回答和时间。虽然我没有得到明确的答案(我有很多问题,其中一些有点模糊),但是您的答案和示例以及随后的实验对我更深入地了解 JVM 的工作原理非常有用。

我发现的主要事情是 Verifier 的行为随着不同的实现和版本而不同(这使得字节码操作的工作变得更加复杂)。问题在于不符合 JVMS,或者缺乏来自验证者开发人员的文档,或者 JVMS 在验证者领域有一些微妙的模糊。

最后一件事,太棒了!!!我在 Sun JVM Specifications 官方论坛上发了同样的问题,到现在还是没有答案。

最佳答案

与 java 语言指定的相反,在字节码级别,可以在调用父类(super class)构造函数之前访问构造函数中的类的字段。下面的代码使用 asm 库来创建这样一个类:

package asmconstructortest;

import java.io.FileOutputStream;
import org.objectweb.asm.*;
import org.objectweb.asm.util.CheckClassAdapter;
import static org.objectweb.asm.Opcodes.*;

public class Main {

public static void main(String[] args) throws Exception {
//ASMifierClassVisitor.main(new String[]{"/Temp/Source/asmconstructortest/build/classes/asmconstructortest/Test.class"});
ClassWriter cw = new ClassWriter(0);
CheckClassAdapter ca = new CheckClassAdapter(cw);

ca.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "asmconstructortest/Test2", null, "java/lang/Object", null);

{
FieldVisitor fv = ca.visitField(ACC_PUBLIC, "property", "I", null, null);
fv.visitEnd();
}

{
MethodVisitor mv = ca.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ICONST_1);
mv.visitFieldInsn(PUTFIELD, "asmconstructortest/Test2", "property", "I");
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}

ca.visitEnd();

FileOutputStream out = new FileOutputStream("/Temp/Source/asmconstructortest/build/classes/asmconstructortest/Test2.class");
out.write(cw.toByteArray());
out.close();
}
}

实例化这个类工作正常,没有任何验证错误:

package asmconstructortest;

public class Main2 {
public static void main(String[] args) {
Test2 test2 = new Test2();
System.out.println(test2.property);
}
}

关于java - 对字节码和对象的澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3278865/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com