【问题标题】:Default constructors and inheritance in JavaJava中的默认构造函数和继承
【发布时间】:2010-10-06 05:58:23
【问题描述】:

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

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

【问题讨论】:

  • 帖子是否需要对假设“构造函数使用一些默认值(0、null 或 false)初始化类的所有实例变量(如果有)的行进行编辑。”误导读者?

标签: java inheritance initialization default-constructor


【解决方案1】:
  1. 如果不做构造函数,the default empty constructor is automatically created

  2. 如果任何构造函数没有显式调用 super 或 this 构造函数作为其第一条语句,a call to super() is automatically added

总是。

【讨论】:

【解决方案2】:

构造函数不会被继承。

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

【讨论】:

  • 是的,我刚刚明白这一点,下面的potyl已经指出了这一点。但是这些字段是如何(以及何时)初始化的呢? (请参阅我对potyl答案的评论)。
  • 是不是在我创建对象的时候,Java会自动给出默认值?但是话又说回来,我们确实使用构造函数创建对象,对吧?
  • 是的,研究 w.r.t. 花了一些时间。初始化。
  • 谢谢,我还找到了一篇关于这个的好文章——Java 中的初始化,这里:javaworld.com/javaworld/jw-03-1998/…
  • 注意Object的默认构造函数不是empty,它是native。构造函数通常负责诸如内存分配之类的事情。
【解决方案3】:

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

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

【讨论】:

  • “空构造函数”是指默认构造函数,对吧?
  • 如果父级没有默认构造函数怎么办?
  • 这里我的意思是一个没有参数的构造函数。通常,默认构造函数是一个根本没有定义的构造函数。你可以定义一个不带参数的构造函数。
  • 如果父类没有不带参数的构造函数,则必须调用 super(...) 以获得超类中的有效构造函数。
  • 您的意思是“SUB(派生)类中的“有效构造函数”?
【解决方案4】:

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

所以当你有一个只有参数化构造函数而没有默认构造函数的超类,并且基类没有显式调用超类的参数化构造函数时,JVM 提供了 super(); call 抛出错误,因为超类没有默认构造函数,因此我们要么在超类中提供默认构造函数,要么在基类构造函数中显式调用超类的参数化构造函数。当我们进行显式调用时,JVM 不会费心放置 super(); 行。因为构造函数调用应该是方法的第一条语句,这是不可能发生的(因为我们显式调用)。

【讨论】:

  • 如果你想“超载”构造函数,我想总是把默认构造函数放在那里应该是一个好习惯。
【解决方案5】:

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

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

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

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

【讨论】:

【解决方案6】:

如果你提供了一个构造函数,那么 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);
    }
}

【讨论】:

  • 这很有趣!我已经假设如果您不在构造函数中初始化实例变量,那么 Java 会在默认构造函数中执行此操作很长一段时间。那么,在这种情况下,变量是如何初始化的呢?
  • 在这里我找到了一篇关于Java初始化的好文章,回答了我的问题:javaworld.com/javaworld/jw-03-1998/…
  • 创建对象实例需要操作符“new”分配内存并调用构造函数(用于初始逻辑)。我们的构造函数只关心后者。我猜第一部分在分配内存时负责数据成员的默认初始化。
【解决方案7】:

拇指规则是子类应该从基类调用任何构造函数。因此,如果您没有默认的 const ,则从子类中调用现有的 const 。否则在基类中实现空 const 以避免编译问题

【讨论】:

    【解决方案8】:

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

    【讨论】:

      【解决方案9】:

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

      【讨论】:

      • "...创建一个没有任何构造函数的对象我们必须声明..." => "...创建一个没有任何构造函数的对象参数,我们必须声明...”
      【解决方案10】:

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

      【讨论】:

        【解决方案11】:

        子类中的任何构造函数都会调用父类的无参数构造函数(或默认构造函数)。如果在父类中定义了参数化构造函数,则必须使用 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 
        

        【讨论】:

          猜你喜欢
          • 2016-03-24
          • 2015-07-09
          • 2018-04-18
          • 2016-12-05
          • 2021-06-02
          • 1970-01-01
          • 2011-05-20
          相关资源
          最近更新 更多