2013-07-12 242 views
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#

+5

我想答案与C#的答案相同:) – PermGenError

+1

自动默认构造函数绝对是一种语言设计错误。在理想的世界中,它不存在,所以为什么你甚至在乎:)什么特性取决于检测到默认的构造函数? – ZhongYu

+0

自动默认构造函数非常棒!这是为了做静态分析。如果我知道一个构造函数是我所知的默认构造函数,那么只需查看该类的声明,它就是空的,例如不会在任何地方泄漏'this'指针。 – Lii

回答

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

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

+0

它合理地说,一个生成的默认构造函数和一个空的构造函数产生相同的字节码。但是仍然可能有一些关于这方面信息的元数据。 – Lii

+0

啊,在原始数据编辑器中检查类文件应该解决它!谢谢。 – Lii

5

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

在大多数情况下,编译器生成的构造函数和方法在生成的字节码中用ACC_SYNTHETIC标志或Synthetic属性标记。不过,也有从jvm-spec

这里Java Language Spec和4.7.8除少数例外按13.1项目7从JLS的相关位:

任何构建由Java编译器介绍,没有在源代码中的相应构造必须被标记为合成的,除了默认构造,类的初始化方法,该值和Enum类的的valueOf方法

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

+0

'javap -verbose'显示标志,包括'ACC_SYNTHETIC'。 –

相关问题