【问题标题】:Initialization of variables if user defined constructors are present in Java如果 Java 中存在用户定义的构造函数,则初始化变量
【发布时间】:2014-12-09 09:27:28
【问题描述】:

在下面的代码中,我有一个用户定义的构造函数(无 arg 构造函数)和一个参数化构造函数。

我的理解是,如果我至少有一个构造函数,编译器不会添加默认/隐式构造函数。

我的问题:

在主方法中,我通过调用参数化构造函数来创建Employee 对象。在参数化构造函数中,我只设置了empId 属性。

当我尝试打印 name 的值时,它会将其打印为 null(即默认值)。

什么将 name 初始化为 NULL(即其默认值)? 它不能是编译器生成的隐式/默认构造函数,因为我们在类中至少有一个构造函数。

public class Employee {

    String name;
    int empId;

    public Employee() {
        System.out.println("Calling User Defined Constructor");
    }

    @Override
    public String toString() {

        return "name=" + name + " empId=" + empId;

    }

    public Employee(String name, int empId) {
        this.empId = empId;
    }

    public static void main(String[] args) {

      Employee e = new Employee("test",123);

        System.out.println(e);
    }

}

【问题讨论】:

  • 字段的默认值不是由任何Java代码分配的;它是虚拟机在开始执行构造函数之前本机初始化对象的内存。如果不这样做,可能会从已经 gc'ed 的对象中读取虚假数据,这将是一种安全风险,尤其是对于对象引用。
  • '我只是在设置 empId 属性' - 如果没有 setter 和 getter,你如何设置 empId 值?
  • this.empId = empId; :)
  • 我的假设是在任何构造函数调用之后变量被初始化为默认值。所以你的意思是即使在构造函数被调用之前,VM 也会将实例变量默认为某个值??

标签: java constructor


【解决方案1】:

引用类型的类变量的默认值为 null(与没有默认值的局部变量相反)。同样,原始类型的类变量也有自己的默认值。

您的代码相当于:

public class Employee {

    String name = null;
    int empId = 0;
    ...
}

【讨论】:

  • 我的假设是构造函数将变量初始化为默认值。从您的解释看来,VM 在构造函数调用之前将它们初始化为默认值。是这样吗?
  • @ankurlu 没错。它们在构造函数执行之前被初始化。当然,构造函数可以更改这些默认值。
  • 非常感谢。这回答了我的问题
【解决方案2】:

JLS 救援,JLS 4.12.5. Initial Values of Variables:

对于所有引用类型 (§4.3),默认值为 null。

而且由于String 是一个引用 类型,所以它得到null 作为默认值:

ReferenceType:
    ClassOrInterfaceType
    TypeVariable
    ArrayType

考虑在构造函数中分配它:

public Employee(String name, int empId) {
    this.empId = empId;
    this.name = name;
}

【讨论】:

    【解决方案3】:
    public Employee(String name, int empId) {
        this.name = name; // You are missing this line
        this.empId = empId;
    }
    
    public static void main(String[] args)
    {
        Employee e = new Employee("test",123);
        System.out.println(e);
    }
    


    Employee 类中的String name 在声明时隐式为空,即

    String name = null;


    任何引用类型变量(例如本例中的 String)都被赋予默认值 null。

    Variable initialization and default values

    【讨论】:

      【解决方案4】:

      构造函数执行如下:

      • 所有字段都“归零”; null, 0, 0.0, '\u0000'
      • 调用超级构造函数,或者显式调用隐式super();
      • 所有字段初始化发生;那只是那些带有= ... 的字段。
      • 其余的构造函数代码被执行。

      您可能会发现以下谜题(打印了什么?)很有启发性。

      class A {
          A() {
              terrible();
          }
          protected void terrible() {
              System.out.println("A.terrible - " + this);
          }
      
      }
      
      class C extends A {
          C() {
              System.out.println("C.terrible - " + this);
          }
      
          String a;
          String b = null;
          String c = "c";
      
          @Override
          protected void terrible() {
              System.out.println("C.terrible - " + this);
              a = "aa";
              b = "bb";
              c = "cc";
              System.out.println("C.terrible (2) - " + this);
          }
      
          @Override
          public String toString() {
              return String.format("a=%s, b=%s, c=%s", a, b, c);
          }
      }
      

      【讨论】:

        【解决方案5】:
        public Employee(String name, int empId) {
        
            this.empId = empId;
        }
        
        
        public Employee() {
            System.out.println("Calling User Defined Constructor");
        }
        

        根据您的实例,构造函数将在运行时加载。

        构造函数在初始化对象本身时设置值。

        因此,在您的情况下,只创建了一个实例。它传递了两个值。但只分配一个值。所以名称默认设置为空.....

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-23
          • 2020-09-27
          • 2015-02-19
          • 1970-01-01
          • 2017-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多