构造函数是否生成了默认构造函数?

时间:2013-07-12 15:57:48

标签: java reflection

有没有办法通过反射找出构造函数是否是编译器生成的默认构造函数?或者还有其他方式吗?

令人惊讶的是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#

2 个答案:

答案 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

的4.7.8,有一些值得注意的例外情况。

以下是JLS的相关位:

  

Java编译器引入的源代码中没有相应构造的构造必须标记为合成,除了默认构造函数,类初始化方法,以及值和valueOf方法Enum类

据我所知,javap未显示ACC_SYNTHETIC标记,但如果已设置,则可以通过isSynthetic阅读。