4

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

1
  • 1
    The abstract constructor can be used for initializing variables or performing initializing steps in the abstract class. Commented Jan 21, 2015 at 21:25

4 Answers 4

7

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.

Sign up to request clarification or add additional context in comments.

4 Comments

So invoking a constructor doesn't mean making an object? little confused at the moment...
Invoking a constructor will inherently call all super constructors in the parent tree of that object type. The only object that is created is the actual type you called "new" on.
@Maxim invoking a constructor does mean making an object, but executing super(...) doesn't invoke the constructor of the super class to create an object of the super class while creating an instance of the current class, it just executes any behavior defined in the constructor of the super class (abstract or not).
So normally if you invoke a constructur when saying new... it does call the constructor, but when calling super, it just executes the code in the superclass constructor but doesn't make a new object of that class, seems a little weird to me because as far as I cann tell the constructor of that class is literally beeing called and thus a new object should automatically be created... I'll have to review this tomorrow and hope it will make more sense. I'd like to thank you guys very much for your time, I really appreciate the effort all of you make to help beginners start their coding journey.
2

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

1 Comment

I understand this part, I just always thought that calling a constructor meant making an object, which you can't cuz the class is abstract...
1

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)

3 Comments

you say that you first have to make a car? but that's my question, how come you CAN make a car if the class is abstract?
You're thinking about this the wrong way. Lets use a different analogy. In order to have a child, the child must have parents. The child here is an actual object (not abstract), and the parents we don't care about (they are abstract). The parents provide a ton of stuff for the child, toys, food, etc (providing methods and variables), but we don't care or know who they are. We just know that they exist, and they're there. Since every child has parents, by default have we not "created" parents for a child when we make the child? Even if we didn't say "make a parent"?
Even using the same car analogy, we can say this; you can make any vehicle, or have a lot of vehicles, but none of them are "just vehicles". You can point at any car on the street, and it's not just "a car". It could be a "mazda ____", or "honda ____", or "pontiac ___". It is impossible to just "have a vehicle". If you wanted to make a vehicle, you can't, because you have to know what you are making (car, plane, boat, etc), but if you are making a honda, you know that it is a car. When someone asks you what you are making, you can say "i'm making a car", even though you're making a honda
1

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 i.e 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 :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.