Java 抽象的构造函数 class

Java constructor of an abstract class

据我所知(如果我错了请纠正我)无法实例化抽象的class。你可以给它一个构造函数,但不能在 class 上调用 new。如果你在 subclass 中调用 super,superclass 构造函数将 运行 (并因此创建一个 class 的对象?)那么你怎么能真正调用 super在摘要 class 的子 class 中? 我确定这与我对构造对象的构造函数的误解有关...

If you call super in a subclass, the superclass constructor will run (and thus create an object of that class??) then how come you can accually call super in a subclass of an abstract class?

这部分是错误的。当您在 subclass 构造函数中调用 super 时,您只是告诉 subclass 它首先必须执行来自 super class 的初始化代码(抽象或不),然后它将继续执行代码以初始化正在创建的 class 的当前实例。这并不意味着它会在创建当前实例的过程中创建超级 class 的实例。

在抽象中调用构造函数 class 将仅用于设置特定于该抽象的属性 class - 否则在抽象的每个实现中设置会很乏味 class。此功能删除样板代码。

在下面的示例中,了解如何根据汽车的其他属性计算确定汽车的使用寿命。在 Car 子类型的每个实现中都这样做是多余的。

abstract class Car {
    // Determine how many years a car will last based on other components
    int lifeTimeInYears;

    float price;

    public Car(float price) {
        // Assuming you could calculate the longevity based on price;
        if (price > 50000) {
            lifeTimeInYears = 15;
        }
        else {
            lifeTimeInYears = 10;
        }
    }

    public int getLifeTimeInYears() {
        return lifeTimeInYears;
    }
}

class SportsCar extends Car {

    public SportsCar(float price) {
        super(price);
    }
}

class CommuterCar extends Car {

    public CommuterCar(float price) {
        super(price);
    }
}

public class Test {
    public static void main(String[] args) {
        SportsCar sportsCar = new SportsCar(150000);
        sportsCar.getLifeTimeInYears(); // Value is 15

        CommuterCar commuterCar = new CommuterCar(15000);
        commuterCar.getLifeTimeInYears(); // Value is 10
    }
}

比如说我们定义了抽象class "car"。然后我们写一个subclass,"honda"扩展"car"。为了做一个"honda",你必须先做一个"car"。不管"car"是否是抽象的,为了创建任何subclass对象,你必须先调用super()来"make" superclass对象。

在这里查看我对类似问题的回答:(请注意,这个问题用词不当,实际上是在谈论构造函数)

我将尝试在字节码级别对其进行解释,看看是否有帮助。

AbstractService.java

public abstract class AbstractService {
    protected int id = 10;
    public abstract void verify();
}

Service.java

public class Service extends AbstractService{
    public static void main(String[] args) {
        Service service = new Service();
        service.verify();
    }

    public void verify() {
        System.out.println("printing id = "+id);
    }
}

如果您查看这些 类

生成的字节码
public abstract class AbstractService {
    protected int id;

    public AbstractService() {
        /* L4 */
        0 aload_0;                /* this */
        1 invokespecial 1;        /* java.lang.Object() */
        /* L6 */
        4 aload_0;                /* this */
        5 bipush 10;
        7 putfield 2;             /* .id */
        10 return;
    }

    public abstract void verify();
}




public class Service extends com.sample.service.AbstractService {

    public Service() {
        /* L3 */
        0 aload_0;                /* this */
        1 invokespecial 1;        /* com.sample.service.AbstractService() */
        4 return;
    }

    public static void main(java.lang.String[] args) {
        /* L6 */
        0 new 2;
        3 dup;
        4 invokespecial 3;        /* com.sample.service.Service() */
        7 astore_1;               /* service */
        /* L7 */
        8 aload_1;                /* service */
        9 invokevirtual 4;        /* void verify() */
        /* L8 */
        12 return;
    }

    public void verify() {
        /* Skipping this as it's not needed */
    }
}

Service service = new Service(); 翻译成

        0 new 2;
        3 dup;
        4 invokespecial 3;        /* com.sample.service.Service() */

正如你在上面看到的,首先执行新的字节代码,这将创建一个只有实例变量默认值的新对象(在这种情况下 id 是整数,所以默认为 0)但被初始化,然后 dup 将创建这个新对象引用的副本,然后调用将调用 Service() 的 invokespecial,后者将调用 AbstractService(),后者又调用 Object()

如果您查看这些方法中的字节码,它们不会创建对象(没有新的字节码指令),它们只是初始化对象,例如设置变量 id=10 的值,这是对用户的正确初始化-定义的值。

所以当你说 new SomeClass() 时,它不仅仅是调用你的构造函数,它是关于创建一个具有默认状态的对象,然后调用称为构造函数的特殊方法(编译器生成一个或用户定义的一个)来初始化该对象。换句话说,构造函数将对象从默认状态 (id=0) 带到用户定义状态 (id=10),以便对象可以使用,即调用方法。

这对初学者来说太多了,但如果你注意字节码,它就会有意义:)