Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java语言中构造函数的调用_Java_Oop_Constructor - Fatal编程技术网

Java语言中构造函数的调用

Java语言中构造函数的调用,java,oop,constructor,Java,Oop,Constructor,在《Java:完整参考》一书中 // Demonstrate when constructors are called. // Create a super class. class A { A() { System.out.println("Inside A's constructor."); } } // Create a subclass by extending class A. class B extends A { B() {

在《Java:完整参考》一书中

// Demonstrate when constructors are called.
// Create a super class.
class A {
     A() {
        System.out.println("Inside A's constructor.");
     }
}
// Create a subclass by extending class A.
class B extends A {
      B() {
             System.out.println("Inside B's constructor.");
      }
 }
// Create another subclass by extending B.
class C extends B {
    C() {
        System.out.println("Inside C's constructor.");
    }
}
class CallingCons {
    public static void main(String args[]) {
        C c = new C();
    }
}
输出: 在A的构造函数中 B的构造函数内部 在C的构造函数中

它演示了如何调用子类的构造函数。但是为什么在没有super()构造函数的情况下调用超类的构造函数呢


为什么java语言设计者认为有必要这么做?

每个构造函数调用它的超类构造函数。super()调用作为构造函数中的第一行进行。从javadoc:

如果构造函数没有显式调用超类构造函数,Java编译器会自动插入对 没有超类的参数构造函数。如果超级类没有 如果没有参数构造函数,则会出现编译时错误。 对象确实有这样的构造函数,所以如果对象是唯一的 超类,没有问题

更多

因为它在

如果构造函数体不是以显式构造函数调用开始,并且所声明的构造函数不是原始类对象的一部分,则构造函数体隐式地以超类构造函数调用“super();”开始,这是对其直接超类的构造函数的调用,不带任何参数

“Java编程语言”说“子类中的构造函数可以初始化其单独的状态,然而,作为契约,只有超类知道如何初始化超类的状态”

因此,必须调用超类的构造函数。构造函数处理的顺序如下:

  • 调用超类构造函数
  • 使用初始值设定项和初始化块初始化字段
  • 构造函数的执行体

有关更多详细信息,请参阅本书的“3.2”部分。

正如其他人所指出的,如果您不使用
super(…)
调用启动构造函数,编译器将为您调用
super()

至于为什么,您必须首先记住构造函数的用途:初始化对象。这具体是什么意思?实际上,这意味着为对象的字段赋值,并建立不变量

如果不调用
super()
B
a
类就没有机会对它们包含的任何字段执行此操作。如果这些字段是私有的,您甚至不能让
C()
构造函数为它们执行此操作,因为私有字段在您的类之外是不可访问的(甚至您的超类的字段也不可访问)。即使你可以,这也不是一个好主意;这也会破坏封装。例如,想象一下,如果一个超级类(可能是一个复杂的类,其内部您不是专家)突然决定更改其实现细节,就必须更改代码

为了说明这一点,考虑一组非常简单的类:

public class Super {
    private final String name;

    Super() {
        name = "default";
    }

    public String name() {
        return name.toUpperCase();
    }
}

public class Sub extends Super {
    public Sub() {
        // don't do anything
    }
}
当您实例化
Sub
时,它将首先调用
Super
的构造函数。如果没有,则
名称
字段将为空(引用类型的默认值)。但是
name()
方法不检查null;它假定引用为非null,因为构造函数建立了该不变量。因此,在不调用超级构造函数的伪Java中,
super.name
必须变得更复杂一点——它必须检查
name==null


您可以想象,随着类获得更多的字段和更多有趣的不变量,这个玩具示例可能会变得越来越复杂。强制您调用超级构造函数(显式或隐式)可以让该超类的作者建立其不变量,从而生成更简单、更可维护的代码。

继承基本上是继承父类的所有属性。因此,如果调用了子类构造函数,它肯定会默认继承其所有父类属性。在下面的代码中,
class A
的所有属性也应该在
class B
中可用,因此如果我只调用B的构造函数,所有class A的属性(private除外)也会初始化并可用,这意味着B继承了A的属性

class A {
    protected int a;
    A() {
        a=12;
       System.out.println("Inside A's constructor.");
    }
}

class B extends A {
     B() {
            System.out.println("Inside B's constructor.");
            System.out.println(a);
     }
}

public class ConstructorInheritance {
   public static void main(String args[]) {
       B b=new B();
   }
}

output:
Inside A's constructor.
Inside B's constructor.
12

假设类C访问类B或A的单位化变量。隐式调用类B的构造函数-->类A确保始终访问继承类(A或B)的初始化变量,即使它也具有抽象类的角色。我们无法初始化抽象类的对象。但是抽象类的子类默认调用super()方法。因此抽象类构造函数可以初始化其实例变量。
例如:

公共抽象类TestA{
私人INTA;
公共遗嘱
{
a=10;
}
公共int displayA()
{
返回a;
}
抽象空显示();
}
公共类TestB扩展了TestA{
@凌驾
无效显示(){
System.out.println(“这是B类”);
}
}
包摘要;
公共类TestMain{
公共静态void main(字符串[]args){
TestA obj=新的TestB();
System.out.println(obj.displayA());
}
}
输出为:10
在这里您可以看到,当我们初始化类TestB的对象时,默认情况下超级构造函数正在调用,而TestA的构造函数正在分配a的值。如果super在默认情况下不被调用,我们就不能分配抽象类的实例变量

除非在子构造函数的第一条语句中显式调用
super(…)
,否则JVM会自动添加对默认父构造函数的调用。这就是所谓的构造器链接。你比我先做到了。。。有趣的是,教程与标准相比,使用了不同的措辞。为什么java语言设计者认为D是必要的?