我正在研究以下java程序的反汇编问题
public class ASMPlayground {
private String bar;
public String getBar(){
return bar;
}
public void setBar(String bar) throws IllegalAccessException, InstantiationException {
String name = String.class.newInstance();
System.out.println(name);
}
public static void main(String[] args) {
}
}下面的字节码片段吸引了我的眼球,看起来不太理想。
LDC Ljava/lang/String;.class
INVOKEVIRTUAL java/lang/Class.newInstance ()Ljava/lang/Object;
CHECKCAST java/lang/String问题:
当要执行的方法依赖于对象引用时,将使用InvokeVirtual。既然“类”是最终的,而newInstance()只存在于“类”中,为什么不使用InvokeSpecial而不是InvokeVirtual呢?会不会更有表现力呢?
发布于 2017-03-05 16:28:36
InvokeSpecial用于指定以下调用
超类、私有和实例初始化方法调用
规格:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial
Class.newInstance既不是超类方法调用,也不是私有方法调用,也不是调用初始化方法。它也不是一个动态的方法,InvokeDynamic在这里没有什么可做的。这两种指令都不能在这里使用,因为它将面对jvms。在创建jvms时,允许用“更好的”指令替代某些指令,但正如我在jvms中所看到的,它还没有完成。
会不会更有表现力呢?
JIT非常聪明,可以理解在这种情况下不需要遍历虚拟方法表,所以它不应该减慢执行速度。实际的性能应该通过实际的测试来比较,但是我认为没有理由期望有显著的差异。
发布于 2017-03-06 09:19:08
目标方法或类是final这一事实不会使用另一个类/调用该方法来更改已编译的类的形式。
这是JLS第13章规定的。“二进制兼容性”, methods
将声明为
final的方法更改为不再声明为final并不会破坏与现有二进制文件的兼容性。
同样地, Classes
将声明为
final的类更改为不再声明为final并不会破坏与现有二进制文件的兼容性。
显然,依赖于目标方法的final性质的调用指令将违反此规范。
没有预期的相关性能影响。当符号引用必须解析到实际方法时(根据JVM的运行时表示),总是存在第一次开销。此时,JVM还可以记录这个方法或它的声明类实际上是调用指令的final (如果有好处的话)。现代JVM甚至更进一步,例如,利用一个非final方法实际上没有被覆盖的事实,尽管如果一个子类被加载和实例化(它有一个覆盖的方法),则需要对这些调用进行去优化。因此,唯一的区别是,final修饰符可以保证这样的去优化是不必要的。
https://stackoverflow.com/questions/42610150
复制相似问题