有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java构造函数是由默认构造函数生成的吗?

有没有办法通过反射来确定构造函数是否是编译器生成的默认构造函数?还是有别的办法

令人惊讶的是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) 个答案

  1. # 1 楼答案

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

    在大多数情况下,编译器生成的构造函数和方法在生成的字节码中用ACC_SYNTHETIC标志或Synthetic属性进行标记。然而,根据第13.1条第7项,从Java Language Spec到第4.7.8条从jvm-spec,有一些明显的例外情况

    以下是JLS中的相关位:

    Any constructs introduced by a Java compiler that do not have a corresponding construct in the source code must be marked as synthetic, except for default constructors, the class initialization method, and the values and valueOf methods of the Enum class

    据我所知,javap不显示ACC_SYNTHETIC标志,但如果设置了isSynthetic,您可以通过isSynthetic读取它

  2. # 2 楼答案

    否,编译器将生成它们:

    我创建了文件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       
    }
    

    一模一样。我正在使用Java7和64位OpenJDK,但我敢打赌所有版本都是一样的

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