I aware that Java object constructors implicitly initialize their instance's non-static fields. However, I'm unsure of the order that this happens in a class hierarchy. For example:
abstract public class AbstractPieceSequence implements PieceSequence
{
private Tetromino current;
private Tetromino preview;
public AbstractPieceSequence()
{
advance();
}
#Override
public final void advance()
{
if (preview == null) {
current = getNextPiece();
preview = getNextPiece();
} else {
current = preview;
preview = getNextPiece();
}
}
abstract protected Tetromino getNextPiece();
}
public class ShufflePieceSequence extends AbstractPieceSequence
{
private List<Shape> bag = new LinkedList<Shape>();
#Override
protected Tetromino getNextPiece()
{
if (bag.size() == 0) {
Collections.addAll(bag, Shape.I, Shape.J, Shape.L, Shape.O, Shape.S, Shape.T, Shape.Z);
}
return Tetromino.tetrominoes.get(bag.remove(0));
}
}
The parent's constructor calls a method in the child class, which throws an exception as the value of List<Shape> bag is currently null.
I can define a child constructor and call super(), but that must be the first line in the constructor body (which means I still don't have a chance to initialize bag before getNextPiece is called).
I am missing something obvious.
That's right. super(), even if you don't add it explicitly, is placed implictly in every constructor. This means that the constructor of ShufflePieceSequence is called first, but the very first thing it does is calling AbstractPieceSequence.
In AbstractPieceSequence you are calling a method defined in ShufflePieceSequence - which has not been initialized. In fact what you are doing is actually a very subtle bug. You should never call overridable (including abstract methods) from constructor. Period. AFAIR tools like pmd and findbugs are marking this as a potential bug.
See also
What's wrong with overridable method calls in constructors?
Use Care When Calling Non-final Methods from Constructors
Ensure that constructors do not call overridable methods
Object fields are not implicitly initialized... you need to do the init. Maybe you need a lazy init in this case? Generally unpleasant to have the constructor calling methods that do non-trivial work, it's usually a smell that something is more complex than it wants to be.
Depth first, a pre-order walk.
Anders makes a good point: Java only initializes fields that are native types implicitly. Any Object field is merely a reference to Object, and so it in fact initialized, but it's initialized to null.
The order of invoking the constructors of Parent-Sub class in case of inheritance is that, the constructor of Parent class always gets invoke first and then the constructor of Child class.
The Sub class calls the constructor of the base class by default using the Super(), if explicitly not given.
Related
i'm studying java as first language, so i'm a complete newbie.
I'm now studying inheritance between classes, and there's something i can't understand. I give you an example:
This is the main class:
public class Bici {
protected int misura;
protected String modello;
public Bici(int misura, String modello)
{
this.misura=misura;
this.modello=modello;
}
public void stampaCaratteristiche()
{
System.out.println("Size is: "+misura);
System.out.println("Model is: "+modello);
System.out.println();
}
}
This is the subclass:
public class Tandem extends Bici {
private int ruote;
public Tandem (int ruote)
{
super(misura, modello);
this.ruote=ruote;
}
public void stampaCaratteristicheTandem()
{
System.out.println("Le ruote del tandem sono "+ruote);
}
}
but when declaring super variables i get this error:
"Cannot refer to an instance field modello while explicitly invoking a constructor"
Why? Thank you!
you do not have default constructor in Bici class, it means in Tandem class it has to be invoked explicitly. like this :
private int ruote;
public Tandem (int ruote, int misura, String modello)
{
super(misura, modello);
this.ruote=ruote;
}
public void stampaCaratteristicheTandem()
{
System.out.println("Le ruote del tandem sono "+ruote);
}
A superclass constructor must execute before a subclass constructor. So that the state and behavior defined by the superclass may be correctly and completely initialized before a subclass constructor executes.
Java compiler assumes that the first line of every constructor is an implicit call to the default superclass constructor unless you explicitly use super() or this().
Note that Super keyword is used to explicitly invoke a superclass constructor. If you use this form, it must appear as the first statement of the constructor to ensure that the superclass constructor executes before the subclass constructor
The Java inheritance mechanism does not include constructors. In other words, constructors of a superclass are not inherited by subclasses. Subclasses can still call the constructors in the superclass using the super() contruct. In fact, a subclass constructor is required to call one of the constructors in the superclass as the very first action inside the constructor body. You may have seen Java classes where the subclass constructors did not seem to call the constructors in the superclass. Maybe the superclass did not even have a constructor. However, the subclass constructors have still called superclass constructors in those case. You just could not see it. Let me explain why:
If a class does not have any explicit constructor defined, the Java compiler inserts an implicit no-arg constructor. Thus, a class always has a constructor.
This is because you can not call an instance method before the instance is created. By the way, it is possible to call an instance method later on in the constructor.
This solve your problem:
public Tandem (int misura, String modello, int ruote){
super(misura, modello);
this.ruote=ruote;
}
Is it common practice to always use super for calling methods out of the superclass, even when I'm NOT overriding the method?
Assume
public class Parent{
public void method() {
}
}
So
public class Child extends Parent {
public void someMethod() {
super.method();
}
}
or
public class Child extends Parent {
public void someMethod() {
method();
}
}
Thanks for your input.
Calling super tells the JVM to explicitly look to the parent class' version of a method. Continuing with your example, if you just call
method()
The JVM will first search in the calling class for the method (in this case Child) before looking at the parent class. On the other hand, if you call
super.method()
then the JVM will explicitly look at the parent class for an implementation, even if Child has an method called method().
Putting these two ideas together, you should probably always use super when you intend to call the parent class' method. If your class does not override the method, then you could call without super. But even this becomes problematical if someone were to refactor your class later on and override the method.
The leading question is easy to answer:
Is it common practice to always use super for calling methods out of the superclass, even when I'm NOT overriding the method?
No, its not common practice. On the contrary, its dangerously confusing to do so. You call methods normally, because the main point of inheritance is to allow the classes to override methods to change/extend their behavior. You normally don't care about at which level a method is actually implemented.
The obvious exception is when you do override the method yourself and you want/need the parents functionality.
Now to the dangerously confusing part of explicitly calling super:
public class CallSuper {
static class Parent {
public void foo() {
System.out.println("Parent.foo");
}
/**
* Calls foo to do the main work
*/
public void bar() {
System.out.print
foo();
}
}
static class Child extends Parent {
public void foo() {
System.out.println("Child.foo");
}
public void bar() {
super.foo();
}
}
static class GrandChild extends Child {
public void foo() {
System.out.println("GrandChild.foo");
}
}
public static void main(String[] args) {
Parent p = new Parent();
Parent c = new Child();
Parent g = new GrandChild();
System.out.print("Parent.foo() = ");
p.foo();
System.out.print("Child.foo() = ");
c.foo();
System.out.print("GrandChild.foo() = ");
g.foo();
System.out.print("Parent.bar() = ");
p.bar();
System.out.print("Child.bar() = ");
c.bar();
System.out.print("GrandChild.bar() = ");
g.bar();
}
}
If you run this example it will output (added line numbers for clarity):
1 Parent.foo() = Parent.foo
2 Child.foo() = Child.foo
3 GrandChild.foo() = GrandChild.foo
4 Parent.bar() = Parent.foo
5 Child.bar() = Parent.foo
6 GrandChild.bar() = Parent.foo
The first four lines are not surprising, we get what foo implements at each level, respectively Parents's bar calling its foo. It starts to get odd at line 5. Child bypasses its own override of foo by calling super.bar(), so while its foo() is specialized, bar() is not. In Line 6, you see that GrandChild inherits this oddity from Child, so the somewhat innocent looking super.foo() in Child's bar has now broken GrandChild's expectations that its override of foo() is effective for all bar() as well.
Now if you imagine foo() and bar() actually doing something useful and that they have a meaningful relationship with each other, e.g. you are led to believe (either by Parent's documentation or just common sense) that overriding foo() will change the behavior of bar(), too. Child's "super" is breaking that.
As a rule of thumb, if you see a "super.x()" call anywhere outside of an actual override of "x()", its probably an accident lurking to happen.
Is it common practice to always use super for calling methods out of the superclass? Or is it redundant code?
It's not redundant. It have a special purpose of invoking parent class method (though you ovveriden). When you don't want, don't invoke. If you current class is not child of that class, super won't work for you.
Also if you call an overridden supermethod, does it use the supermethod or the lowest method?(in the inheritance tree)
The overridden method. Since you overridden it in your class.
If you're not overriding, let's talk about performance.
If you call an inherited method in your class, let's say, methodInSuperclass(), the JVM will look for that method first in your class, then up the class hierarchy until it finds it.
Using super.methodInSuperclass() tells the JVM to go directly to the superclass to look for that method.
So, using the super keyword improves performance by a few mills. It's ugly code, but it's not redundant as it will bring some performance improvement.
Consider using it if time is critical.
Calling the super method or not depends entirely on what you are trying to do. If you want to do what the parent class did plus some additional action, then calling the super method is good. If you're doing something completely different in the child implementation then do not call the super method. When you do call the super method in a hierarchy of classes, it calls the one closest to your child class in the hierarchy.
In some cases you may have an API where calling the super method is part of the overall contract. The clone method is such a case.
If Child is having the same version method with Parent, JVM will call the Child's version instead of Parent's version if without "super". The "super" keyword is helpful if you want to make sure the Child is always calling the Parent's version method.
I have this inheritance structure:
public abstract class Mom {
int dummy;
Mom() {
dummy = 0;
}
Mom(int d) {
this();
dummy = d;
}
}
public class Kid extends Mom {
String foo;
Kid() {
super();
foo = "";
}
Kid(int d) {
super(d);
}
}
// ...
Kid kiddo = new Kid(10);
// kiddo.foo == null !
My argument-less constructor of Kid is never called! Here's what I expected:
new Kid(10) → Kid#Kid(int)
super(d) → Mom#Mom(int)
this() → Kid#Kid() // doh!!
super() → Mom#Mom()
Is it possible, from Mom, to call Kid's argument-less constructor?
I guess it's not, and I'll add an abstract method[1] init() that Mom will call and that Kids will have to override.
But I just wanted to know the exact reason, and if possible, examples proving why wanting to call subclass' constructor is a bad idea (even if the subclass' constructor does call super()).
// in Mom:
protected abstract void init();
public Mom() {
dummy = 0;
init();
}
// in Kid:
#Override
protected abstract void init() {
foo = "";
}
The way I would arrange these so you don't need to call every constructor.
public abstract class Parent {
final int dummy;
Parent () {
this(0);
}
Parent (int d) {
dummy = d;
}
}
public class Kid extends Parent {
final String foo = "";
Kid() {
}
Kid(int d) {
super(d);
}
}
Using final ensures that every fields is set once.
Its considered bad practice to call any override-able method from a constructor, so making constructors override-able which be a bad idea.
this() calls the constructor of the same class because constructors don't follow inheritance (nor do static methods)
new Kid(10) --> Kid#Kid(int)
super(d) --> Mom#Mom(int)
this() --> Mom#Mom()
Constructors do this otherwise you are in danger for calling the same constructor more than once and there is no way to guarantee that final methods are set only once.
From the JLS §8.8.7.1 (emphasis by me):
Alternate constructor invocations begin with the keyword this (possibly prefaced with explicit type arguments). They are used to
invoke an alternate constructor of the same class.
Superclass constructor invocations begin with either the keyword super (possibly prefaced with explicit type arguments) or a Primary
expression. They are used to invoke a constructor of the direct
superclass.
So, a this-constructor-invocation always refers to the same class, never to a child class.
While it is possible to invoke virtual methods in a constructor, it is unsafe and considered bad practice as it may result in those methods working with partly initialized object instances.
For your problem, there are several possible solutions:
Initialize the member foo at declaration, i.e. foo = "";. This is also known as field initializers
Use an instance initializer: { foo = ""; }. Note that you can have more than one instance initializer if needed in your class.
Bite the bullet and repeat the initialization in all constructors
According to JLS §12.5, initialization in (1) and (2) is always executed before constructors themselves are called, so you have a well-defined object initialization without the need of resorting to problematic patterns.
If a member is initialized multiple times, then the last initialization wins:
4) Execute the instance initializers and instance variable initializers
for this class, assigning the values of instance variable initializers
to the corresponding instance variables, in the left-to-right order in
which they appear textually in the source code for the class.
If the same field is initialized in a constructor as well, then the constructor wins.
You should have these constructors for the Kid class:
Kid(int i) {
super(i);
whatever();
}
Kid () {
this( DEFAULT_VALUE);
}
so that all call to parent constructor are made via fully qualified constructor of child class. And have a default behavior for all constructor of your class that is not bypassed as it is the case with your current code.
I have a pair of classes looking like this;
public abstract class Class1 {
//...
public Class1() {
//...
function2();
//...
}
protected abstract void function2();
}
public class Class2 implements Class1 {
private final OnSomethingListener mOnSomethingListener = new OnSomethingListener() {
#Override
onSomething() {
doThatOtherThing();
}
}
protected void function2() {
//uses mOnSomethingListener
//however mOnSomethingListener is null when this function is called from super()
//...
}
public Class2() {
super();
}
}
I assume the listener is null because I am effectively referencing it from super() and it hasn't instantiated yet. However, I want to make it final because, well, it is. Can I get this field (the listener) to initialize in time without putting it in the superclass (which won't be using the listener, ever)?
Your design is an instance of the "leaked this problem" and is an anti-pattern in Java. You should never call out to a publicly overridable method from a constructor.
Short answer - no. A superclass' constructor, field initialisers and instance initialisers are always called before the subclass'.
The order of calls is formally defined in section 8.8.7.1 of the JLS. Summarising the relevant last parts (where S is the superclass and C is the subclass):
After determining the immediately enclosing instance of i with respect to S (if any), evaluation of the superclass constructor invocation statement proceeds by evaluating the arguments to the constructor, left-to-right, as in an ordinary method invocation; and then invoking the constructor.
Finally, if the superclass constructor invocation statement completes normally, then all instance variable initializers of C and all instance initializers of C are executed. If an instance initializer or instance variable initializer I textually precedes another instance initializer or instance variable initializer J, then I is executed before J.
So when the superclass constructor runs, the subclass and all its fields are completely uninitialised. It's bad practice to call overridden methods from a constructor for this reason. You're essentially letting a reference to the object "escape" from its constructor, which means all the guarantees of construction are off (including things like final fields changing value, etc.).
Calling an abstract method from a constructor is almost always the wrong thing to do. Depending on the implementation of the method in the subclass(es) you might get away with it in some case (i.e. if the method does not depend on any state at all), but it will almost certainly cause a hard-to-debug failure at some point.
For example, would you expect there to be a difference between:
protected String function2() {
return "foo";
}
and
private final String foo = "foo";
protected String function2() {
return foo;
}
Analysing problems like this is hard, because they break the mental model of how classes work. Best to avoid this situation altogether.
super classes are always initialised before subclasses. Only static fields of a sub class can be initialised first.
You can call an overridden method from the super class which then accesses a field which is not initialised. This is considered bad practice.
I know abstract fields do not exist in java. I also read this question but the solutions proposed won't solve my problem. Maybe there is no solution, but it's worth asking :)
Problem
I have an abstract class that does an operation in the constructor depending on the value of one of its fields.
The problem is that the value of this field will change depending on the subclass.
How can I do so that the operation is done on the value of the field redefined by the subclass ?
If I just "override" the field in the subclass the operation is done on the value of the field in the abstract class.
I'm open to any solution that would ensure that the operation will be done during the instantiation of the subclass (ie putting the operation in a method called by each subclass in the constructor is not a valid solution, because someone might extend the abstract class and forget to call the method).
Also, I don't want to give the value of the field as an argument of the constructor.
Is there any solution to do that, or should I just change my design ?
Edit:
My subclasses are actually some tools used by my main program, so the constructor has to be public and take exactly the arguments with which they will be called:
tools[0]=new Hand(this);
tools[1]=new Pencil(this);
tools[2]=new AddObject(this);
(the subclasses are Hand, Pencil and AddObject that all extend the abstract class Tool)
That's why I don't want to change the constructor.
The solution I'm about to use is to slightly change the above code to:
tools[0]=new Hand(this);
tools[0].init();
tools[1]=new Pencil(this);
tools[1].init();
tools[2]=new AddObject(this);
tools[2].init();
and use an abstract getter to acces the field.
How about abstract getter/setter for field?
abstract class AbstractSuper {
public AbstractSuper() {
if (getFldName().equals("abc")) {
//....
}
}
abstract public void setFldName();
abstract public String getFldName();
}
class Sub extends AbstractSuper {
#Override
public void setFldName() {
///....
}
#Override
public String getFldName() {
return "def";
}
}
Also, I don't want to give the value
of the field as an argument of the
constructor.
Why not? It's the perfect solution. Make the constructor protected and offer no default constructor, and subclass implementers are forced to supply a value in their constructors - which can be public and pass a constant value to the superclass, making the parameter invisible to users of the subclasses.
public abstract class Tool{
protected int id;
protected Main main;
protected Tool(int id, Main main)
{
this.id = id;
this.main = main;
}
}
public class Pencil{
public static final int PENCIL_ID = 2;
public Pencil(Main main)
{
super(PENCIL_ID, main);
}
}
How about using the Template pattern?
public abstract class Template {
private String field;
public void Template() {
field = init();
}
abstract String init();
}
In this way, you force all subclasses to implement the init() method, which, since it being called by the constructor, will assign the field for you.
You can't do this in the constructor since the super class is going to be initialized before anything in the subclass. So accessing values that are specific to your subclass will fail in your super constructor.
Consider using a factory method to create your object. For instance:
private MyClass() { super() }
private void init() {
// do something with the field
}
public static MyClass create() {
MyClass result = new MyClass();
result.init();
return result;
}
You have an issue in this particular sample where MyClass can't be subclassed, but you could make the constructor protected. Make sure your base class has a public / protected constructor also for this code. It's just meant to illustrate you probably need two step initialization for what you want to do.
Another potential solution you could use is using a Factory class that creates all variants of this abstract class and you could pass the field into the constructor. Your Factory would be the only one that knows about the field and users of the Factory could be oblivious to it.
EDIT: Even without the factory, you could make your abstract base class require the field in the the constructor so all subclasses have to pass in a value to it when instantiated.
Also, I don't want to give the value of the field as an argument of the constructor.
Is there any solution to do that, or should I just change my design ?
Yes, I think you should change your design so that the subclass passes the value to the constructor. Since the subclass portion of your object isn't initialized until after the superclass constructor has returned, there's really no other clean way of doing it. Sure, this'd work:
class Super {
protected abstract int abstractField();
protected Super() { System.out.println("Abstract field: " + abstractField); }
}
class Sub {
protected int abstractField(){ return 1337; }
}
... since the implementation of abstractField() doesn't operate on object state. However, you can't guarantee that subclasses won't think it's a great idea to be a little more dynamic, and let abstractField() returns a non-constant value:
class Sub2 {
private int value = 5;
protected int abstractField(){ return value; }
public void setValue(int v){ value = v; }
}
class Sub3 {
private final int value;
public Sub3(int v){ value = v; }
protected int abstractField(){ return value; }
}
This does not do what you'd expect it to, since the initializers and constructors of subclasses run after those of the superclass. Both new Sub2() and new Sub3(42) would print Abstract field: 0 since the value fields haven't been initialized when abstractField() is called.
Passing the value to the constructor also has the added benefit that the field you store the value in can be final.
If the value is determined by the type of subclass, why do you need a field at all? You can have a simple abstract method which is implemented to return a different value for each subclass.
I think you need a factory (aka "virtual constructor") that can act on that parameter.
If it's hard to do in a given language, you're probably thinking about it incorrectly.
If I understand you correctly: You want the abstract class's constructor to do something depending on a field in the abstract class but which is set (hopefully) by the subclass?
If I got this wrong you can stop reading ...
But if I got it right then you are trying to do something that is impossible. The fields of a class are instantiated in lexical order (and so if you declare fields "below", or "after", the constructor then those will not be instantiated before the constructor is called). Additionally, the JVM runs through the entire superclass before doing anything with the subclass (which is why the "super()" call in a subclass's constructor needs to be the first instruction in the constructor ... because this is merely "advice" to the JVM on how to run the superclass's constructor).
So a subclass starts to instantiate only after the superclass has been fully instantiated (and the superclass's is constructor has returned).
And this is why you can't have abstract fields: An abstract field would not exist in the abstract class (but only in the subclass) and so is seriously(!) "off limits" to the super (abstract) class ... because the JVM can't bind anything references to the field (cause it doesn't exist).
Hope this helps.