简体   繁体   中英

Java constructor of an abstract class

As far as I know (please correct me if I'm wrong) a class that is abstract cannot be instantiated. You can give it a constructor, but just can't call new on that 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 actually call super in a subclass of an abstract class? I'm sure it has something to do with my misunderstanding about a constructor making an object...

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?

This part is wrong. When you call super in the subclass constructor, you're just telling to the subclass that it first has to execute the initialization code from the super class (abstract or not), then it will continue executing the code to initialize the current instance of the class being created. This doesn't mean that it will create an instance of the super class in the middle of the creation of the current instance.

Calling a constructor in an abstract class would only be used to setup attributes that are specific to that abstract class - which would otherwise be tedious to setup in each implementation of the abstract class. This ability removes boiler plate code.

In the example below, see how determining the lifetime of the car could be calculated based on other attributes of the car. This would be excessive to do it in each implementation of the Car subtype.

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
    }
}

Lets say for example we define the abstract class "car". Then we write a subclass, "honda" extending "car". In order to make a "honda", you must first make a "car". Regardless of whether or not "car" was abstract, in order to make any subclass object, you have to call super() to "make" the superclass object first.

See my answer to a similar question here: What is (is there?) a purpose behind declaring a method twice when parent class appears to not change any properties? (Note that this question is a misnomer, and is actually talking about constructors)

I'll try to explain it at byte code level and see if that helps.

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);
    }
}

If you look at the generated byte code for these classes

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(); is translated to

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

As you can see above, first new byte code is executed which will create a new Object with only default values for instance variables (in this case id is integer so default 0) but are initialized, then dup which will create a copy of this new object reference and then invokespecial which will call Service() that will call in turn call AbstractService() which in turn calls Object()

If you look at the byte codes in those methods, they don't create objects (no new byte code instruction) they merely initialize the objects like setting the value of variable id=10 which is the proper initialization to user-defined values.

So when you say new SomeClass(), it's not just about calling your Constructor, its about creating an object with default states and then calling special method called constructor (either the compiler generated one or the user-defined one) to initialize that object. In another words, constructors bring objects from default state(id=0) to user-defined state(id=10) so that the object is ready to use ie calling methods on it.

This is too much at the beginner level but if you pay attention to the byte code it will make sense :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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