我在想,如果有分析构造函数的字节码的时候,以确定其中的一个明显和快速的方式super()
代码结束。
更具体地说,并形成鲜明对比的Java,其中在构造函数中的任何一个调用super()
构造方法是可选的(或者说,当不存在-隐含的),在字节码的世界里总是需要。
对于黑魔法的目的,我需要知道的只是字节码分析和可用的最简单的方法,有什么的INVOKESPECIAL
对应于Java世界的召唤super()
调用。
在这里我要离开你用硬例如:
public static class A {
public A(Object o, Object b) {
}
}
public static class B extends A {
public B() {
//the below super is in bold just to signal that's the one
//I'm looking for
SUPER(new A(new Object(), new Integer(2)), new Integer(1));
System.out.println(new A(new Object(), new Integer(2)));
}
}
与对应的字节代码:
实际上,对于字节码构造的规则比Java的规则更为宽松。
唯一的规则是,只有一个构造函数必须正常返回,如果一个构造函数调用抛出一个异常,那么你必须抛出一个异常过任何路径上调用。
别的不说,这意味着一个构造函数可以包含对其他构造函数或根本多个呼叫。
不管怎样,唯一可以保证的方法来确定是否一个给定的invokespecial
调用初始化当前对象是做数据流分析,因为它可以初始化同一类,它会混淆天真探测器的其他对象。
编辑:这是一个完全有效的类的实例(使用喀拉喀托汇编语法),显示出一些你可能会遇到的问题。 除其他事项外,它在同一类调用其他构造函数,构造函数的递归调用,并构建在构造函数中同一类的其他对象。
.class public ctors
.super java/lang/Object
; A normal constructor
.method public <init> : ()V
.limit locals 1
.limit stack 1
aload_0
invokespecial java/lang/Object <init> ()V
return
.end method
; A weird constructor
.method public <init> : (I)V
.limit locals 2
.limit stack 5
iload_1
ifne LREST
aload_0
invokespecial ctors <init> ()V
return
LREST:
aload_0
new ctors
iinc 1 -1
iload_1
LFAKE_START:
invokespecial ctors <init> (I)V
LFAKE_END:
iconst_0
invokespecial ctors <init> (I)V
return
.catch [0] from LFAKE_START to LFAKE_END using LCATCH
LCATCH:
aload_0
invokespecial java/lang/Object <init> ()V
return
.end method
.method public static main : ([Ljava/lang/String;)V
.limit locals 1
.limit stack 2
new ctors
iconst_5
invokespecial ctors <init> (I)V
return
.end method
一个简单的解决方法是计数数量new A
的对象和数量A.<init>
当有更多init
比new
已被称为超级构造函数。 你必须做相同的检查new B
和B.<init>
的情况下, this(...)
被调用。
你必须找出在该调用操作码操作数栈包含this
引用将被用来作为第一个参数。 对于这一点,你只需要知道的是,不同的操作码有操作数栈上的影响。 在您的例子中,你开始aload_0
(这是this
参考),然后做了相当多的神奇高于基准(更新操作数栈所有的时间)。 过了一会儿,你正在寻找的invoke操作码是存在的,这消耗了this
参考(和对参数一些参考)。 然后,这是super
调用。
这个问题的答案超()的调用是线上没有。 31。
我发现很容易通过Eclipse的类文件编辑器。 看看下面附卡。
这里有一点要记住的是,前缀“A”指操作码操作对象的引用。 前缀的“i”表示操作码操作的整数。
因此,由线解释的路线如下,
12 new java.lang.Integer //Create a new java.lang.Integer
15 dup //Make a extra reference to the same Integer
16 iconst_2 // this means opcode is manipulating Integer as Integer(2)
17 invokespecial java.lang.Integer(int) //Integer(2) is invoked
20 invokespecial A(java.lang.Object, java.lang.Object) //new A(new Object(), new Integer(2) is invoked
23 new java.lang.Integer //Create a new java.lang.Integer
26 dup //Make a extra reference to the same Integer
27 iconst_1 // this means opcode is manipulating Integer as Integer(1)
28 invokespecial java.lang.Integer(int) //Integer(1) is invoked
31 invokespecial A(java.lang.Object, java.lang.Object) **//super(new A(new Object(), new Integer(2)), new Integer(1)) is invoked**
我希望以后很容易理解。 :)
56 - this invoke is for the sysout related A(object,object) invocation.
文章来源: Determining in the bytecode where is the super() method call all constructors must do on the JVM