由于每个方法调用都包含目标方法签名,在我看来,类验证步骤可以通过分析目标来判断它是否调用静态,虚拟等并做正确的事情?
4字节代码是浪费3字节代码还是仅仅是自我记录,如果使用javap转储类文件?
答案 0 :(得分:3)
如果您正在谈论invokeinterface
,invokespecial
,invokestatic
和invokevirtual
,则 之间存在差异。开始时对堆栈的影响。
答案 1 :(得分:2)
假设您只调用虚拟和静态操作码。我们假设在编译时你有
Test {
public static void test(Test t) {
// static method
}
}
在某处用伪字节码调用此静态
push t
jmp Test.test(T)V
现在让我们假设有人在运行时使用另一个Test类
Test {
public void test(Test t) {
// obj call
}
}
在这种情况下,jmp Test.test(T)V
仍然有效。问题是它会弄乱堆栈。两个不同的操作码允许捕获此问题的链接时间。
答案 2 :(得分:0)
这是可能的。但是,每次解释其中一条指令时,它会增加额外的成本。所以表现会受到很大的好处。
有人认为,单独的指令可以减少混淆VM的可能性,从而提高安全性。不确定我是否相信。
答案 3 :(得分:0)
您需要此操作码,因为在布置方法的字节码引用时,它们仅包含对常量池中条目的符号引用。要解析这些引用,您需要知道需要解析的类型:例如,invokespecial和invokevirtual之间的区别是静态绑定和动态绑定。对于invokespecial,您可以解析引用的类型,而不是对象的类。如果没有编译器输入特殊操作码来区分方法,则无法收集此信息。在java中,代码通常是动态链接的,这就是强制这些操作码的原因。
答案 4 :(得分:0)
至少需要invokespecial
作为单独的指令,因为java允许显式调用重写方法的超级实现:
class Super {
public void m() { }
}
class Sub {
public void m() {
super.m();
}
}
Sub
中的来电必须是invokespecial
,否则只会自行调用并耗尽堆栈。
答案 5 :(得分:0)
我认为这场辩论是不必要的,因为java有这个设计决定。不确定,但您可能希望再查看一下他们称之为用户定义的数据端点:invokedynamic