Reputation: 415
I'am learning Java and I got an unexpected output. That's the code:
public class Point {
protected final int x,y;
private final String name;
public Point(int x,int y){
this.x = x;
this.y = y;
name = makeName();
}
protected String makeName() {
return "["+x+" ,"+y+"]";
}
public final String toString(){
return name;
}
}
public class ColorPoint extends Point{
private final String color;
public ColorPoint(int x,int y, String color){
super(x,y);
this.color = color;
}
protected String makeName(){
return super.makeName() + ":" + color;
}
public static void main (String[] args){
System.out.println(
new ColorPoint(4,2,"viola"));
}
}
The output is: [4,2]:null
.
Why? Shouldn't it be just [4,2]
because the variable String name is initialized first in makeName()
method of the Point
class and then should become unmutable? Am I wrong?
Upvotes: 1
Views: 115
Reputation: 124225
final
fields are initialized with default values (which for references is null
). You can easily check it with this code:
class FinalTest{
public final String value = test();
private String test() {
System.out.println("current state of value is '"+value+"'");
return "foo";
}
public static void main(String[] args) {
FinalTest ft = new FinalTest();
System.out.println(ft.value);
}
}
which produces output:
current state of value is 'null'
foo
So as you see final variable has its default value which can be later modified in constructor once.
But lets get back to your example. When you call
System.out.println(new ColorPoint(4, 2, "viola"));
you are creating invoking constructor of ColorPoint
class, and then on this instance toString
will be called. But lets take a closer look at ColorPoint
constructor:
public ColorPoint(int x, int y, String color) {
super(x, y);
this.color = color;
}
As you see before this.color
will be set you are invoking super(x,y)
which code looks like this:
public Point(int x, int y) {
this.x = x;
this.y = y;
name = makeName();
}
But here in makeName();
thanks to polymorphism (late binding) you are using code of makeName
from ColorPoint
class which looks like
protected String makeName() {
return super.makeName() + ":" + color;
}
So at start you will get result of super.makeName()
which is "[" + x + " ," + y + "]"
but then you are trying to access color
which as you remember is not initialized with because
super(x, y); //<-- we are still here
this.color = color;//this wasn't invoked (yet)
so color
still has its default value (null
).
This means that name
will be set to [4 ,2]:null
.
Since ColorPoint
inherits toString
from Point
which looks like
public final String toString() {
return name;
}
you see as output value stored in name
which is [4 ,2]:null
.
Upvotes: 0
Reputation: 2065
new ColorPoint(4,2,"viola"));
calls the constructor on line 22 , which inturn calls the constructor on line 5 the constructor on line 5 calls the overridden function make name on line 27 which sets name as [4,2]:null because colour hasnt been initialized yet.
Upvotes: 0
Reputation: 26926
makeName()
is called in the constructor of the superclass.
When it is called color is not yet set so the default value of color is null.
To solve the problem you have to explicitly call makeName()
at the end of constructor. Here is the correct code:
public ColorPoint(int x,int y, String color){
super(x,y);
this.color = color;
makeName();
}
Upvotes: 0
Reputation: 1136
Flow is like this,
Point constructor > makeName of ColorPoint > makeName of Point
since, makeName of ColorPoint is called first, till that time color property value was not assigned, so its giving null
Upvotes: 0
Reputation: 3830
super(x,y) is calling method makeName() of ColorPoint class and color is not assigned till then.
Upvotes: 0
Reputation: 363815
the makeName()
method is called before you set this.color = color
;
The makeName()
method is called by your super.construtctor when the color variable is still null
.
Upvotes: 2