摘要classjava继承

Abstract class java inheritance

我有两个抽象 classes 一个继承自另一个。在 Child 摘要 class 中,除了 class 的声明外,我没有任何代码。在 parent 抽象 class 中,我有一个私有的 int 质量和一个接收 int 的构造函数。 由于某种原因,没有任何代码,编译器给我编译时错误。 因为它试图调用 parent class 构造函数,但是 java 只给了他的 child 默认构造函数。

我的问题是: 为什么没有任何代码编译器会给我这个错误。

从你写的情况看是这样的:

// in a file A.java
public abstract class A {
    private int quality;
    public A(int quality) {
        this.quality = quality;
    }
}

// in another file B.java
public abstract class B extends A {
    
}

编译器将编译这些 classes,因为当它生成 .class 文件时,它生成的 classes 必须是可用的。你说 'without any code' 但上面是代码。它只是不是您在任何地方使用的代码。

然而,javac 生成的 .class 文件可以从另一个来源链接到。编译器不知道,所以它确保代码编译或生成错误。

在您的情况下,如果您定义构造函数,则必须显式调用 parent 构造函数,否则将采用默认构造函数。

所以你的 class B 没有定义构造函数。默认构造函数是在不可见的情况下生成的。这个默认构造函数只能尝试调用它的超级构造函数。具体来说,它调用 parent 默认构造函数。除了构造函数不存在。

生成的构造函数无法调用带有 1 个参数的构造函数,因为它不知道为该参数输入什么。所以基本上如果你有一个构造函数参数,你的 child classes 需要提供那个参数或者你在 parent 级别提供一个默认构造函数。

所以这两个都有效:

 public abstract class A {
    private int quality;
    public A(int quality) {
        this.quality = quality;
    }
}

public abstract class B extends A {
    public B() {
        super(0);
    }
}

public abstract class A {
    private int quality;
    public A() {
        this(0);
    }
    public A(int quality) {
        this.quality = quality;
    }
}

public abstract class B extends A {
    
}

在第一种情况下,child class 显式调用 parent 构造函数。在第二个中,parent 负责知道如何处理该值。

可能在你的情况下(如果你希望另一个 class 扩展 B 并提供实现)你会想要这样做:

public abstract class A {
    private int quality;
    public A(int quality) {
        this.quality = quality;
    }
}

public abstract class B extends A {
    public B(int quality) {
        super(quality);
    }
}

然后,当您使用 non-abstract(具体)class 扩展此 class 时,它可以提供链上游的价值。

最后再说一次,因为我觉得这就是你问题背后的想法:

项目的其余部分未使用代码并不意味着编译器未尝试创建可用的 class。因为您可以从项目中获取任何 class 文件并将其复制到其他地方并使用它。因此,编译器提供的内容必须是正确的,否则会抛出错误。

将构造函数添加到子 class 并在构造函数内部使用 super()

示例:

abstract class Parent{
    private int x;
    Parent(int x){
        this.x = x;
    }
    
}

abstract class Child extends Parent{
    Child(int y){
        super(y);
    }
    
}

现在没有编译错误:)

你有这两个 class 定义(或类似的东西)。

abstract class Parent {
    private int quality;
    Parent(int quality) {
        this.quality = quality;
    }
}

abstract class Child extends Parent {
    
}

我们先来看看Parent的构造函数。只有一个,它需要调用者提供一个 quality 值。您明确不提供允许您未指定 quality 的构造函数。

现在你有一个扩展 ParentChild class。不要指定任何构造函数,因此 Java 的默认值适用,静默创建一个哑 no-args 构造函数。

Child class 扩展了它的 Parent class,这意味着每个 Child 实例都具有 Parent 的所有属性,包括 quality。但是在构造 Child 时,您没有提供一种方法来指定 quality.

使用什么值

在 Java 继承系统中,构造函数必须始终通过使用 super(...) 语法调用父构造函数来初始化实例的父 class 方面。如果您不自己编写该调用,它会自动插入到您的构造函数中。

这是一种很好的做法,而且通常需要编写显式构造函数,而不是依赖一些愚蠢的自动机制。在继承的情况下,构造函数应该以 super(...) 调用开始,指定如何初始化要创建的实例的父方面,在您的情况下为父构造函数提供 quality 值。

因此,根据您的要求,解决方案可能是

abstract class Child extends Parent {
    Child() {
        super(42); // All Child instances get a constant quality=42
    }
}

abstract class Child extends Parent {
    // When cinstructing a Child instance, 
    // an explicit quality value must be supplied.
    Child(int quality) {
        super(quality);
    }
}

应用所有built-in Java 自动编码规则后,您的原始版本相当于

// Auto: If you don't specify a parent class, it's java.lang.Object
abstract class Parent extends Object {
    private int quality;
    Parent(int quality) {
        super(); // Auto: calls the `Object()` constructor to initialize
                 // aspects that every Java instance needs
        this.quality = quality;
    }
}

abstract class Child extends Parent {
    // Auto: no constructor supplied in source, so a dumb one gets generated 
    Child() {
        super(); // Auto: calls the parent's no-args constructor
                 // But there is no such constructor, hence compile error.
    }
}