有没有办法通过反射找出构造函数是否是编译器生成的默认构造函数?或者还有其他方式吗?
令人惊讶的是isSynthetic
方法没有提供此信息,因此无法使用。并且没有Generated
注释。
public class JavaTest {
public void run() throws Exception {
out.println(JavaTest.class.getConstructors()[0].isSynthetic()); // Prints false
out.println(Arrays.asList(JavaTest.class.getConstructors()[0].getAnnotations())); // Prints []
}
}
这个问题同样适用于C#:Detect compiler generated default constructor using reflection in C#
答案 0 :(得分:8)
不,编译器会生成它们:
我创建了文件A.java
:
public class A{
public String t(){return "";}
}
然后:
javac A.java
并运行javap -c A
以查看内容:
Compiled from "A.java"
public class A {
public A();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.String t();
Code:
0: ldc #2 // String
2: areturn
}
如果我添加构造函数:
public A(){}
结果是:
Compiled from "A.java"
public class A {
public A();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.String t();
Code:
0: ldc #2 // String
2: areturn
}
它是完全相同的。我正在使用带有64位OpenJDK的Java 7,但我敢打赌它与所有版本的相同。
EDIT :实际上,单独使用相同的字节码并不能保证信息不会作为元数据出现。使用十六进制编辑器和this program可以看到有两个字节不同,并且对应于行号(用于打印堆栈跟踪),因此在这种情况下不存在信息。
答案 1 :(得分:5)
不,字节码中没有元数据可以区分编译器生成的默认构造函数和非生成的默认构造函数。
在大多数情况下,编译器生成的构造函数和方法在生成的字节码中标有ACC_SYNTHETIC
标志或Synthetic
属性。但是,根据Java Language Spec的13.1项目7和jvm-spec
以下是JLS的相关位:
Java编译器引入的源代码中没有相应构造的构造必须标记为合成,除了默认构造函数,类初始化方法,以及值和valueOf方法Enum类
据我所知,javap
未显示ACC_SYNTHETIC
标记,但如果已设置,则可以通过isSynthetic
阅读。