繁体   English   中英

如果父类具有带参数的构造函数,为什么需要在父类中使用默认构造函数?

[英]Why default constructor is required in a parent class if it has an argument-ed constructor?

如果父类具有带参数的构造函数,为什么在父类中需要(显式)默认构造函数

class A {    
  A(int i){    
  }
}

class B extends A {
}

class Main {    
  public static void main(String a[]){
    B b_obj = new B();
  }
}

这将是一个错误。

这里有两个方面在起作用:

  • 如果您确实明确指定了构造函数(如在A ),则 Java 编译器不会为您创建无参数构造函数。

  • 如果您没有显式指定构造函数(如在B ),Java 编译器将为您创建一个无参数构造函数,如下所示:

     B() { super(); }

(可访问性取决于类本身的可访问性。)

那是试图调用超类无参数构造函数 - 所以它必须存在。 您有三个选择:

  • A显式提供无参数构造函数
  • B中显式提供无参数构造函数,该构造函数使用适当的int参数显式调用基类构造函数。
  • B提供一个参数化构造函数,它调用基类构造函数

如果父类具有带参数的构造函数,为什么在父类中需要(显式)默认构造函数

我会说这种说法并不总是正确的。 理想情况下它不是必需的

规则是:如果您显式提供了带参数的构造函数,则该类无法使用默认构造函数(无参数)。

For Example :   
class A {    
  A(int i){    
  }
}

class B extends A {
}

所以当你写

B obj_b = new B();

它实际上调用了java提供的隐式构造函数给B,B又调用了super(),理想情况下应该是A()。 但是由于您为 A 提供了带参数的构造函数,因此默认构造函数 i:e A() 对 B() 不可用。

这就是您需要为 B() 专门声明 A() 以调用 super() 的原因。

如果子类构造函数没有显式调用超类的其他构造函数,则每个子类构造函数都会调用超类的默认构造函数。 因此,如果您的子类构造函数显式调用您提供的超类构造函数(带参数),则超类中不需要无参数构造函数。 因此,将编译以下内容:

class B extends A{
     B(int m){
        super(m);
     }
}

但是以下不会编译,除非您在超类中明确提供没有 args 构造函数:

class B extends A{
     int i; 
     B(int m){
        i=m;
     }
}

假设您打算编写class B extends A

每个构造函数都必须调用超类构造函数; 如果不是,则隐式调用无参数超类构造函数。

如果(且仅当)一个类没有声明构造函数,Java 编译器会给它一个默认构造函数,它不带参数并调用超类的无参数构造函数。 在您的示例中, A声明了一个构造函数,因此没有这样的默认构造函数。 B没有声明构造函数,但无法获得默认构造函数,因为它的超类没有可调用的无参数构造函数。 由于类必须始终具有构造函数,因此这是编译器错误。

Why default constructor is required(explicitly) in a parent class if it 
has an argumented constructor

不必要!

现在在你的 B 班

class B extends A {
}

您尚未在 B 类中提供任何构造函数,因此将放置默认构造函数。 现在的规则是每个构造函数都必须调用它的超类构造函数之一。 在您的情况下,B 类中的默认构造函数将尝试调用 A 类(它的父类)中的默认构造函数,但由于您在 A 类中没有默认构造函数(因为您在 A 类中明确提供了一个带参数的构造函数,因此您将在 A 类中没有默认构造函数)你会得到一个错误。

你可能会做的是

在 A 类中不提供 args 构造函数。

A()
{
  //no arg default constructor in Class A
}

要么

明确地在 B 中写入 no args 构造函数,并使用一些默认的 int 参数调用您的 super。

B()
{
    super(defaultIntValue);
}

底线是,要创建一个对象,必须调用继承层次结构中每个父级的完全构造函数。 调用哪个实际上是您的设计选择。 但是,如果您没有明确提供任何 java 会将默认构造函数 super() 调用作为每个子类构造函数的第一行,现在如果您在超类中没有它,那么您将收到错误。

使用构造函数时需要注意一些事项,以及如何在基类和超类中声明它们。 这可能会变得有些混乱,因为超类或基类中构造函数的可用性或存在性可能有很多。 我将尝试深入研究所有可能性:

  • 如果您在任何类(基类/超类)中显式定义构造函数,Java 编译器将不会在相应的类中为您创建任何其他构造函数。

  • 如果您没有在任何类(基类/超类)中显式定义构造函数,Java 编译器将在相应的类中为您创建一个无参数的构造函数。

  • 如果您的类是从超类继承的基类,并且您没有在该基类中显式定义构造函数,则编译器不仅会为您创建无参数构造函数(如上点),而且还会从超类隐式调用无参数构造函数。

     class A { A() { super(); } }
  • 现在,如果您没有明确键入 super()、(或 super(parameters)),编译器会在您的代码中为您放入 super()。
  • 如果 super() 被调用(由编译器显式或隐式调用),编译器将期望您的超类具有不带参数的构造函数。 如果它在你的超类中没有找到任何没有参数的构造函数,它会给你一个编译器错误。

  • 类似地,如果调用 super(parameters) ,编译器将期望您的超类具有带参数的构造函数(参数的数量和类型应匹配)。 如果它在你的超类中找不到这样的构造函数,它会给你一个编译器错误。 ( Super(parameters) 永远不能被编译器隐式调用。如果需要,它必须显式地放入你的代码中。)

我们可以从上面的规则中总结出一些东西

  • 如果您的超类只有一个带参数的构造函数而没有无参数的构造函数,则您的构造函数中必须有一个显式的 super(parameters) 语句。 这是因为如果您不这样做, super() 语句将隐式放入您的代码中,并且由于您的超类没有无参数构造函数,它将显示编译器错误。
  • 如果你的超类有一个带参数的构造函数和另一个无参数的构造函数,那么你的构造函数中就没有必要有一个显式的 super(parameters) 语句。 这是因为编译器会隐式地将 super() 语句放入您的代码中,并且由于您的超类具有无参数构造函数,因此它可以正常工作。
  • 如果你的超类只有一个无参数的构造函数,你可以参考上面的观点,因为它是一样的。

另一件要注意的事情是,如果您的超类有一个私有构造函数,那么在您编译子类时会产生错误。 这是因为如果您不在子类中编写构造函数,它将调用超类构造函数,而隐式 super() 将尝试在超类中查找无参数构造函数但找不到。

说这个编译,你希望它打印什么?

class A{
  A(int i){
    System.out.println("A.i= "+i);
  }
}

class B extends A {
  public static void main(String... args) {
    new B();
  }
}

当 A 被构造为i ,必须传递一个值,但是编译器不知道它应该是什么,因此您必须在构造函数中明确指定它(任何构造函数,它都不必是默认的)

当我们有参数构造函数时。 我们通过设计明确绑定到消费者。 他不能在没有参数的情况下创建该类的对象。 有时我们需要强制用户提供价值。 对象只能通过提供参数(默认值)来创建。

class Asset
{
    private int id;
    public Asset(int id)
    {
        this.id = id;
    }
}

class Program
{
    static void Main(string[] args)
    {
        /* Gives Error - User can not create object. 
         * Design bound
         */
        Asset asset1 = new Asset();/* Error */
    }
}

连子类都不能创建。 因此,这是良好设计的行为。

扩展类时,会自动添加默认的超类构造函数。

public class SuperClass {
}

public class SubClass extends SuperClass {
   public SubClass(String s, Product... someProducts) {
      //super(); <-- Java automatically adds the default super constructor
   }
}

但是,如果您重载了超类构造函数,这将取代默认值,因此调用super()将导致编译错误,因为它不再可用。 然后,您必须显式添加重载的构造函数或创建一个无参数的构造函数。 请参阅以下示例:

public class SuperClass {
   public SuperClass(String s, int x) {
     // some code
   }
}

public class SubClass extends SuperClass {
   public SubClass(String s, Product... someProducts) {
      super("some string", 1);
   }
}

要么...

public class SuperClass {
   public SuperClass() {
     // can be left empty.
   }
}

public class SubClass extends SuperClass {
   public SubClass(String s, Product... someProducts) {
      //super(); <-- Java automatically adds the no-parameter super constructor
   }
}

因为如果您想阻止创建没有任何数据的对象,这是一种好方法。

当然,如果这样写它是一个错误,它不是JAVA。

如果您将使用 JAVA 语法,则不会出错。

如果在单独的文件/包中,A 类和 B 类对彼此一无所知。

A 类根本不需要默认构造函数,它只使用参数构造函数就可以正常工作。

如果 B 扩展了 A,您只需在 B 的构造函数中调用 super(int a) ,一切都很好。 对于不调用扩展超类的 super(空/或不)的构造函数,编译器将添加对 super() 的调用。

如需进一步阅读,请参阅使用关键字超级

我猜这是因为当您有一个空参数列表时,无法实例化超级变量。 对于空参数列表,我的意思是如果超类具有非参数构造函数,编译器可以添加隐式 super() 。

例如,如果您键入:

int a;
System.out.print(a);

你会得到一个错误,我认为是相同的逻辑错误。

暂无
暂无

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

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