Calling Superclass from a Subclass Constructor in Java

Call subclass constructor from parent in Java

Phone iphone = new Phone("iPhone", 368, "4G"); // <- SmartPhone instance

this makes no sense. If you want a SmartPhone instance, you must call

Phone iphone = new SmartPhone("iPhone", 368, "4G");

You cannot call a sub-class constructor from a super-class constructor.

If you want the type of the Phone to be determined by the passed parameters, you can use static factory methods:

public class PhoneFactory {

public static Phone newPhone (String brand, int weight) {
return new Phone(brand, weight);
}

public static Phone newPhone (String brand, int weight, String tech) {
return new SmartPhone(brand, weight, tech);
}
}

Phone nokia = PhoneFactory.newPhone("Nokia", 295); // <- Regular Phone Instance
Phone iphone = PhoneFactory.newPhone("iPhone", 368, "4G"); // <- SmartPhone instance

Calling superclass from a subclass constructor in Java

What you should do:

Add a constructor to your super class:

public Superclass {
public SuperClass(String flavour) {
// super class constructor
this.flavour = flavour;
}
}

In the Crisps class:

public Crisps(String flavour, int quantity) {
super(flavour); // send flavour to the super class constructor
this.quantity = quantity;
}

 

Comments

Some comments to your question:

"In the superclass I have initialised the field with "

private String flavour;

This is not an initialization, it is a declaration. An initialization is when you set a value.

"I am getting an error " flavour has private access in the superclass" but I believe this shouldn't matter as I am calling the accessor method that returns it to the field?"

When you call a accessor (aka getter), it is ok - depends on the getter visibility.
The problem in you code is the:

this.flavour = 

because flavour is not a field declared on Crisps class, but on the supper class, so you can't do a direct access like that. you should use my suggestion or declare a setter on the super class:

public void setFlavour(String flavour) {
this.flavour = flavour;
}

Then you can use it on the child class:

public Crisps(String flavour, int quantity) {
this.quantity = quantity;
super.setFlavour(flavour);
}

why subclass must call superclass constructor before the subclass can initialise its own variable

A subclass is an extension of the superclass and can access any public/protected/package members and methods in the superclass.

The superclass cannot access members/methods of the subclass unless you cast this to the subclass. By straight OO, the superclass knows nothing about the subclass.

Since the subclass can access members/methods in the super class, the superclass must be initialized before the subclass so that any initial values, memory locations, whatever have valid beginning values.

BTW, this is true in all OO languages I've worked with, pretty sure this is a universal truth.

Calling Super class Constructor

A few problems with your code.

First, as the error suggest, you cannot use the member variable before the super call because the object has not been fully initialized yet. Second, your subclass shouldn't have same public variables as the superclass. Third, a common practice in Java is to use getter/settter instead of public variables.

Here is my version of your code:

public class GregorianDate extends Date {
//Define constants
private final static int MONTH = 1;
private final static int DAY = 1;
private final static int YEAR = 1970;

//*************** Constructors ***********************
GregorianDate() {
super(MONTH,DAY,YEAR);
long numToAdd = System.currentTimeMillis();
numToAdd += java.util.TimeZone.getDefault().getRawOffset();
numToAdd /= 86400000;
super.addDays(numToAdd);
}

//Parameterized constructor
GregorianDate(int passedYear, int passedMonth, int passedDay){
super(passedMonth, passedDay, passedYear);
}

//getters and setters here
}

SuperClass file:

public class Date {
private int month;
private int day;
private int year;

Date(int passedMonth, int passedDay, int passedYear){
this.month = passedMonth;
this.day = passedDay;
this.year = passedYear;
}

//Getters and setters here
}

Using subclass method as parameter in super call to superclass constructor

"cannot reference this before superclass constructor has been called"

Invoking any instance method during (as you are doing)

RandomLetterChooser(String str) {
super(getSingleLetters(str)); //here's the problem
}

or before invoking the super class constructor results to a compilation error.

JLS Chapter 8. Classes :

An explicit constructor invocation statement in a constructor body may
not refer to any instance variables or instance methods
or inner
classes declared in this class or any superclass, or use this or super
in any expression; otherwise, a compile-time error occurs.

Or said in an other manner, an object cannot be used (instance fields and methods) while this hierarchy (parent class) has not be fully constructed.

By changing the modifier of the getSingleLetters() method to static you could use this code as a static method is not associated to an instance of the class :

 RandomLetterChooser(String str) {
super(RandomLetterChooser.getSingleLetters(str)); //here's the problem
}

Check conditions in subclass before calling superclass constructor method

You could do something like this:

public class Jlaj extends ArrayList<String> {

public Jlaj(int capacity) {
super(checkCapacity(capacity));
}

private static int checkCapacity(int capacity) {
if (capacity > 1000)
throw new IllegalArgumentException();
return capacity;
}

public static void main(String[] args) {
new Jlaj(1001); // this throws IAE all right
}
}

Note that you can only call static methods in this fashion, and that's good: calling instance methods on a partially initialized object is already a huge trouble, calling them even before superclass constructors would be a nightmare.

Now what if you need to check some other arguments that you don't pass to the superclass? You could do something like this then:

public class Jlaj extends ArrayList<String> {

private final Object foo;

public Jlaj(int capacity, Object foo) {
super(checkArgumentsAndReturnCapacity(capacity, foo));
this.foo = foo;
}

private static int checkArgumentsAndReturnCapacity(int capacity, Object foo) {
if (capacity > 1000)
throw new IllegalArgumentException();
if (foo == null)
throw new NullPointerException();
return capacity;
}

public static void main(String[] args) {
new Jlaj(1000, null); // throws NPE
}
}

It works, but looks a bit ugly. You're passing two unrelated things into a function that returns just an argument for the superclass. At least the descriptive name somewhat compensates for that.

Java subclass constructors not calling parent class constructor

I cannot explain why you experience BillToSite instances with attributes=null. That contradicts the way Java works. But I can explain why you have to write the no-args constructor.

Necessity of explicit no-args constructor

I suppose that in your program BillToSite instances are created using new BillToSite(), either explicitly or by some framework... (otherwise the class wouldn't have any instances).

In the original BillToSite.java you had no explicit constructor, so the Java compiler created one for you, effectively identical to the one you asked about.

Introducing the 6-args constructor deactivated the compiler's auto-creation of the no-args constructor, and as your code relies on this constructor, it's clear to me that it couldn't work any longer. Normally, you should have got compile errors for the new BillToSite() calls. If you didn't get them, I'd guess that the instance creation happens in some hidden place using reflection.

So, when you wrote the explicit no-args constructor, you re-introduced the missing element that was no longer auto-generated.

Calling the super constructor

You never need to explicitly begin a constructor with super() (we may regard it bad style if you omit it, thus not making clear which superclass constructor is to be used). If you don't explicitly call a super(...) or this(...) constructor, the compiler effectively inserts super() at the very beginning. In this regard, some of the other answers are misleading.

So adding that line to your BillToSite(...) constructors can't change anything.

I'd recommend that you run your program under debugger control with a breakpoint on the BillToSite() constructor and watch the attributes field. I'm sure it will be initialized to an empty HashSet. If you later experience a null value, the problem must be in another part of your code.



Related Topics



Leave a reply



Submit