繁体   English   中英

Java中的默认构造函数和继承

[英]Default constructors and inheritance in Java

我有一个关于Java中的默认构造函数和继承的问题。

通常,如果你编写一个类并且不包含任何构造函数,Java会自动为你提供一个默认构造函数(一个没有参数),它初始化类的所有实例变量(如果有的话)都有一些默认值(0,null或者是假的。 但是,如果使用某些参数编写构造函数,并且不编写任何默认构造函数,则Java不提供默认构造函数。 我的问题是:类继承自其他类的情况是什么 - 如果我编写一个带有一些参数的构造函数,但是不包含默认构造函数,它们是否继承了超类的默认构造函数?

  1. 如果不创建构造函数, 则会自动创建默认的空构造函数

  2. 如果任何构造函数没有显式调用super或this构造函数作为其第一个语句, 则会自动添加对super()的调用

总是。

构造函数不是继承的。

此外,字段的初始化由虚拟机完成,而不是默认构造函数。 默认构造函数只调用超类的默认构造函数,而Object的默认构造函数为空。 这种设计的优点是无法访问未初始化的字段。

除非你使用super(...),否则构造函数会调用其父级的空构造函数。 注意:它在所有类上执行此操作,甚至是扩展Object的类。

这不是继承,子类不会获得具有相同参数的相同构造函数。 但是,您可以添加调用超类的构造函数之一的构造函数。

基本规则是对构造函数的调用(或调用)应该是JVM需要执行的第一个语句,

所以当你有一个只有参数化构造函数且没有默认构造函数的超类,并且基类没有对超类的参数化构造函数的显式调用时,JVM提供了super(); 由于没有超类的默认构造函数,因此抛出错误的调用,所以我们要么在超类中提供默认构造函数,要么在基类构造函数中显式调用超类的参数化构造函数。 当我们给出显式调用时,那么JVM就懒得把行放到super(); 因为构造函数调用应该是方法的第一个语句,这是不可能发生的(因为我们的显式调用)。

Java语言规范的第8.8.9节详细解释了发生了什么:

如果类不包含构造函数声明,则隐式声明默认构造函数。 顶级类,成员类或本地类的默认构造函数的形式如下:

  • 默认构造函数具有与类相同的可访问性(第6.6节)。
  • 默认构造函数没有形式参数,除非在非私有内部成员类中,默认构造函数隐式声明一个形式参数,表示该类的直接封闭实例(§8.8.1,§15.9.2,§15.9.3) )。
  • 默认构造函数没有throws子句。
  • 如果声明的类是原始类Object,则默认构造函数具有空体。 否则,默认构造函数只调用不带参数的超类构造函数。

你可以看到这里没有继承:所有它都是带有隐式声明的默认构造函数的“编译魔术”。 规范还明确指出,只有当类根本没有构造函数时才添加默认构造函数,这意味着你的问题的答案是“否”:一旦你给一个类一个构造函数,就可以访问它的默认构造函数超类失去了。

如果您提供构造函数,那么Java将不会为您生成默认的空构造函数。 因此,派生类只能调用构造函数。

默认构造函数不会将您的私有变量初始化为默认值。 证据是可以编写一个没有默认构造函数的类,并将其私有成员初始化为默认值。 这是一个例子:

public class Test {

    public String s;
    public int i;

    public Test(String s, int i) {
        this.s = s;
        this.i = i;
    }

    public Test(boolean b) {
        // Empty on purpose!
    }

    public String toString() {
        return "Test (s = " + this.s + ", i = " +  this.i + ")";
    }

    public static void main (String [] args) {
        Test test_empty = new Test(true);
        Test test_full = new Test("string", 42);
        System.out.println("Test empty:" + test_empty);
        System.out.println("Test full:"  + test_full);
    }
}

你的问题的答案很简单。 隐式(不可见),任何构造函数中的第一个语句是'super();' 即调用超类的无参数构造函数,直到您将其显式更改为'this();','this(int)','this(String)','super(int)','super(String) )'等'这个();' 是当前类的构造函数。

Thumb Rule是Sub Class应该从基类调用任何构造函数。 因此,如果您没有默认的const,则从子类调用现有的const。 另外明智地在基类中实现空const以避免编译问题

会有编译时错误...因为编译器查找默认的构造函数他超类,如果它不存在......它是一个错误...并且程序将不会编译...

当我们不创建构造函数时,Java会自动创建一个默认构造函数。 但是当我们使用参数创建一个或多个自定义构造函数时,Java不会创建任何默认构造函数。 如果我们创建一个或多个构造函数并且我们想要创建一个没有任何构造函数参数的对象,我们必须声明一个空构造函数。

子类中的任何构造函数都将调用父类的无参数构造函数(或默认构造函数)。 如果在父类中定义参数化构造函数,则必须使用super关键字显式调用父类构造函数,否则会产生编译错误。

class Alpha 
{ 
    Alpha(int s, int p) 
    { 
        System.out.println("base");
    }

} 

public class SubAlpha extends Alpha 
{ 
    SubAlpha() 
    { 
        System.out.println("derived"); 
    } 
    public static void main(String[] args) 
    { 
        new SubAlpha(); 
    } 
}

上面的代码将给出编译错误:

prog.java:13: error: constructor Alpha in class Alpha cannot be applied to given types;
    { 
    ^
  required: int,int
  found: no arguments
  reason: actual and formal argument lists differ in length
1 error

发生上述错误是因为我们在父类中都没有任何参数构造函数/默认构造函数,也没有从子类调用参数化构造函数。

现在要解决这个问题,或者像这样调用参数化构造函数:

class Alpha 
{ 
    Alpha(int s, int p) 
    { 
        System.out.println("base");
    }

} 

public class SubAlpha extends Alpha 
{ 
    SubAlpha() 
    { 
        super(4, 5); // calling the parameterized constructor of parent class
        System.out.println("derived"); 
    } 
    public static void main(String[] args) 
    { 
        new SubAlpha(); 
    } 
}

产量

base
derived

要么

在父类中定义一个无参数构造函数,如下所示:

class Alpha 
{ 
    Alpha(){

    }
    Alpha(int s, int p) 
    { 
        System.out.println("base");
    }

} 

public class SubAlpha extends Alpha 
{ 
    SubAlpha() 
    { 
        System.out.println("derived"); 
    } 
    public static void main(String[] args) 
    { 
        new SubAlpha(); 
    } 
}

产量

derived 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM