15

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

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

4

2 回答 2

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,但我敢打赌所有版本都一样。

编辑:事实上,单独的相同字节码并不能保证信息不作为元数据存在。使用十六进制编辑器,该程序可以看到有两个字节不同,并且对应于行号(用于打印堆栈跟踪),因此在这种情况下信息不存在。

于 2013-07-12T16:12:30.037 回答
5

不,字节码中没有元数据可以让您区分编译器生成的默认构造函数和非生成的构造函数。

在大多数情况下,编译器生成的构造函数和方法在生成的字节码中用ACC_SYNTHETIC标志或属性进行标记。Synthetic但是,根据Java Language Spec的 13.1 item 7 和jvm-spec的 4.7.8有一些值得注意的例外

以下是 JLS 的相关内容:

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

据我所知,javap不显示标志,但如果已设置ACC_SYNTHETIC,您将能够阅读它。isSynthetic

于 2013-07-12T16:46:15.077 回答