I couldn't understand the behavior of the below code.
My expectation was that it should print 100 in both println() methods. Why the result is different?
If I uncomment getX() method in inner class, then the output of println() methods are the same which is 100.
I couldn't figure out the reasoning of different behavior. Please help me to understand.
public class Foo {
public static void main(String[] args) {
MyOuter outerObj = new MyOuter();
MyOuter.MyInner innerObj = outerObj.new MyInner();
innerObj.setX();
System.out.println("x: " + innerObj.getX()); //x: 3
System.out.println("x: " + outerObj.getX()); //x: 100
}
}
class MyOuter {
private int x = 3;
public int getX() { return x; }
class MyInner extends MyOuter {
public void setX(){ x = 100; }
// public int getX() { return x; }
}
}
From MyInner's perspective, there are two private int x fields in play here:
One field super.x that is inherited from MyOuter, but inaccessible because it is declared as private, and MyInner as an inheriting object cannot access this field.
One field MyOuter.this.x from the sorrounding MyOuter-instance (since MyInner is a (non-static) inner class, it is always bound to an instance of the surrounding MyOuter), that is accessible.
The method setX() in MyInner cannot access the inherited field super.x, thus it accesses the field MyOuter.this.x and sets its values to 100. A consecutive call on the surrounding MyOuter's getX() will return 100.
The call innerObj.getX() (which is inherited from MyOuter and can access super.x) returns the value of the inherited field super.x (still having its initial value of 3).
If we remove the extends MyOuter from and include the getX()-method in MyInner, the code behaves as expected.
The fact that MyInner cannot access the inherited field private x is confusing at first, but the behaviour is actually in line with the behaviour of the keyword protected in the context of static mehthods in inheriting classes as discussed in this post by Hariharan
Related
This question already has answers here:
Overriding member variables in Java ( Variable Hiding)
(13 answers)
Closed 9 years ago.
Here are three classes that I wrote:
public class Shape {
public int x = 0;
public void getArea() {
System.out.println("I don't know my area!");
}
public String toString() {
return "I am a shape!";
}
public int getX() {
return x;
}
}
public class Rectangle extends Shape {
public int x = 1;
public int getX() {
return x;
}
public void getArea() {
System.out.println("L*W");
}
public String toString() {
return "I am a rectangle!";
}
}
public class Tester {
public static void main(String[] args) {
Shape s = new Shape();
Rectangle r = new Rectangle();
System.out.println(r);
System.out.println(r.x + "\n");
s = r;
System.out.println(s);
s.getArea();
System.out.println(s.x);
System.out.println(s.getX());
}
}
The output from the main method of the Tester class is:
I am a rectangle!
1
I am a rectangle!
L*W
0
1
Why does s.x return 0 and not 1? As isn't the current instance of the variable a Rectangle and that class also has that same instance variable declared, or does the variable in the Rectangle class not override the previous public x variable in the Shape class as it does to the getX() method in the rectangle class thus returning 1?
Also as a general rule the superclass has access to the implementation of the its subclasses methods only if they are declared in that class as well? Is this because the compiler will see that the same amount of methods with the same signature are in the "Shape" class (with overridden Rectangle implementations) and accept those as valid Shape methods?
Thanks in advance,
There is no polymorphism for fields in Java. There is however, inheritance. What you've effectively done is create two fields in your Rectangle class, with the same name. The names of the field are, effectively:
public class Rectangle {
public int Shape.x;
public int Rectangle.x;
}
The above doesn't represent valid Java, its just an illustration of how the fields are scoped in your class
Within the entire scope of the Rectangle class, the superclass field of the same name is hidden. So anytime you reference the simple name x, or the scoped name this.x, within the class, you are referring to the field that is defined in Rectangle. You can actually access the superclass field as well, with the scoped name super.x.
Now, from outside of the class, the rules for which field is being accessed is slightly different. The scope will be determined by the compile time type of the class that the field is being referenced from. So in your code:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(s.x);
The output is 0 because the compile time type of s is Shape (not Rectangle). You can observe a change in this behavior when you do this:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(((Rectangle)s).x);
Presto! Your output is now 1, because the compiler sees that you've scoped the field access to Rectangle.
To condense the rules of visibility:
You can read more about instance variable hiding in the JLS, Section 8.3.3.2
Subclasses only inherit variables and methods in the superclass, not the other way around. So in order to get x to equal 1 you have to call rectangle not shape.Unless you do what the other guy demonstrated with casting which you should avoid as much as possible in real programming. Plus you should never use public instance variables ever! If you want variables to be public at least make them static or constant.
I have following classes:
public abstract class AClass {
public AClass() {
aMethod();
}
abstract protected void aMethod();
}
public class SubClass extends AClass {
private int x = 5;
private static final int y = 6;
#Override
protected void aMethod() {
System.out.println("x: " + x + " | y: " + y);
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Running Main prints the following: x: 0 | y: 6
Why does 0 get printed for x?
The reason of the misbehaviour is a wrong initialization sequence:
new SubClass() executes AClass constructor
AClass constructor calls aMethod()
aMethod() shows x (which is 0 so far) and y which is 6 because of being static)
SubClass initialize its non-static fields, so x becomes 5.
To avoid surprizes, never call virtual methods (esp. overriden) in constructors
The static field is initialized as soon as the class is initialized (after loading). Now when you call
new SubClass() the following things happen.
Constructor of SubClass is called as the first statement of SubClass (implicitly)
Constructor of SuperClass is called. --> you are checking value of x here
Once SuperClass constructor's execution completes, then instance level fields of SubClass are initialized. So x will be initialized here.
Initialization order. aMethod() is called before the line private int x = 5
Playing round with code examples like this is a great way to learn the order in which things are executed. Try adding a static and non-static initialization block too.
The result is because the super class constructor is called before the members are initialized.
In your case the following sequence is executed:
Call to constructor SubClass
immediate call to constructor AClass
call of method aMethod()
initializing of members of SubClass
This is also the reason why you should not call any overrideable methods from a constructor as the called method may access the state of an object that is not fully initialized.
private static final int y = 6;
Value of y is 6 when the constructor calls aMethod(), because it is static and is initialized while class loading.
private int x = 5;
While this initialization is appended at the end of your constructor body. It means while aMethod is being executed, the variable x has still default value i.e 0.
Default constructor of SubClass would look like
SubClass() {
super();
//All instance initialization are performed here.
}
Because when you created an instance of the Subclass it invokes the constructor of its super class AClass, and at this point, x was not yet set that's why it gets the default value of 0.
In this code I allocate one only object, but in some way I store 2 copies of x (one for the base class and one for the subclass). How is it possible if the object is only one? Where is the space found to store two x vars? Does it mean in reality two objects are createed?
class App {
class Base {
public int x;
public Base() {
x = 2;
}
int method() {
return x;
}
}
class Subclass extends Base {
public int x;
public Subclass() {
x = 3;
}
int method() {
return x;
}
}
public static void main(String[] args) {
new App().run();
}
public void run() {
Base b = new Subclass();
System.out.println(b.x);
System.out.println(b.method());
}
}
One x belongs to the superclass and the other to the subclass. The fact that they have the same name is of no importance and you can access both by qualifying your access expression with the class:
((Base)b).x
((Subclass)b).x
(note that the cast in the first line is not necessary; I've put it in for symmetry)
In java you can not overload variables.,Though they are with the same name,their classes are different.
According to this tutorial(in section "What You Can Do in a Subclass"), when you declare a field in the subclass with the same name as the one in the superclass, in this case x, the one in the superclass will be hidden, which means that there're actually two xs in the subclass, one for itself, the other for its superclass, only baring the same name x. You can reference to the one in the derived class using derivedObject.x and the one in the subclass using ((Base)derivedObject).x(or super.x if within the derived class)
This question already has answers here:
Overriding member variables in Java ( Variable Hiding)
(13 answers)
Closed 9 years ago.
Here are three classes that I wrote:
public class Shape {
public int x = 0;
public void getArea() {
System.out.println("I don't know my area!");
}
public String toString() {
return "I am a shape!";
}
public int getX() {
return x;
}
}
public class Rectangle extends Shape {
public int x = 1;
public int getX() {
return x;
}
public void getArea() {
System.out.println("L*W");
}
public String toString() {
return "I am a rectangle!";
}
}
public class Tester {
public static void main(String[] args) {
Shape s = new Shape();
Rectangle r = new Rectangle();
System.out.println(r);
System.out.println(r.x + "\n");
s = r;
System.out.println(s);
s.getArea();
System.out.println(s.x);
System.out.println(s.getX());
}
}
The output from the main method of the Tester class is:
I am a rectangle!
1
I am a rectangle!
L*W
0
1
Why does s.x return 0 and not 1? As isn't the current instance of the variable a Rectangle and that class also has that same instance variable declared, or does the variable in the Rectangle class not override the previous public x variable in the Shape class as it does to the getX() method in the rectangle class thus returning 1?
Also as a general rule the superclass has access to the implementation of the its subclasses methods only if they are declared in that class as well? Is this because the compiler will see that the same amount of methods with the same signature are in the "Shape" class (with overridden Rectangle implementations) and accept those as valid Shape methods?
Thanks in advance,
There is no polymorphism for fields in Java. There is however, inheritance. What you've effectively done is create two fields in your Rectangle class, with the same name. The names of the field are, effectively:
public class Rectangle {
public int Shape.x;
public int Rectangle.x;
}
The above doesn't represent valid Java, its just an illustration of how the fields are scoped in your class
Within the entire scope of the Rectangle class, the superclass field of the same name is hidden. So anytime you reference the simple name x, or the scoped name this.x, within the class, you are referring to the field that is defined in Rectangle. You can actually access the superclass field as well, with the scoped name super.x.
Now, from outside of the class, the rules for which field is being accessed is slightly different. The scope will be determined by the compile time type of the class that the field is being referenced from. So in your code:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(s.x);
The output is 0 because the compile time type of s is Shape (not Rectangle). You can observe a change in this behavior when you do this:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(((Rectangle)s).x);
Presto! Your output is now 1, because the compiler sees that you've scoped the field access to Rectangle.
To condense the rules of visibility:
You can read more about instance variable hiding in the JLS, Section 8.3.3.2
Subclasses only inherit variables and methods in the superclass, not the other way around. So in order to get x to equal 1 you have to call rectangle not shape.Unless you do what the other guy demonstrated with casting which you should avoid as much as possible in real programming. Plus you should never use public instance variables ever! If you want variables to be public at least make them static or constant.
public class Base {
public Base() {
x = 0;
bar();
}
public Base(int x) {
this.x = x;
foo();
}
public void foo() {
System.out.println("Base.foo : " + x);
}
private void bar() {
System.out.println("Base.bar:" + x.toString());
}
protected Integer x;
}
public class Derived extends Base {
public Derived() {
bar();
}
public Derived(int x, int y) {
super(x);
this.y = y;
}
public void foo() {
System.out.println("Derived.foo : " + x + ", " + y);
}
public void bar() {
System.out.println("Derived.bar:" + x.toString() + ", " + y.toString());
}
private Integer y;
public static void main(String[] args) {
Base b = new Derived(10, 20);
}
}
Why does it print "Derived.foo:" 10, nulll and not 20 instead of the null?
y is a private variable of Derived, and it was initialized with 20. it's in its scope.. so why is it null?
Because the super constructor is first called (super(x)). This super constructor calls the method foo. Then the Derived constructor initializes y to 20 (this.y = y). So when foo is called, y is not initialized yet.
It's a bad practice to call overridable methods in constructors, because, as you just noticed, it can call overridden methods on partially constructed objects.
The println comes from method foo which is called from Base's constructor, which is called from Derived's constructor (via super) before you initialize y. So the null value is expected.
It does that because the superclass (Base) constructor calls Derived.foo() before the y member variable has been set.
So here is the basic order of operations:
main(...)
Derived(10,20) (start constructor)
Base(10) (start constructor)
this.x = x
foo() (calls Derived.foo() which prints the message you see)
Then after that
this.y = y
If you follow the calls from the constructor it makes it clearer:
Calls the Derived(int x, int y) constructor
Calls the super constructor Base(int x)
Sets the x variable
Calls the overridden foo() method
Performs the println()
Then sets the y variable
As you can see, the y variable is getting set after you try to print out the value. That is why you are seeing the uninitialized value of null.
Calling overridable methods from a constructor is a common mistake, as it can allow uninitialized variables to escape before the object is fully constructed.
When you get into the constructor of the super class y is not yet instantiated yet. So the call to foo() will have a null y.
It is printed by Derived.foo() triggered by Super-Constructor call before it is initialized with 20 afterwards. So while printing it is still null.
All the answers are indeed correct but next time you can maybe put a breakpoint in the function where you are printing something.
Then you can simply examine the call stack and folow the code by reading the parts that are being called.
This way you could have traced that y would not be initialized.
Good luck!
Roel
because y has not been initialised when foo() is called in the Base class constructor.
the chain goes
main -> Derived(x,y) -> Base(x) -> initialise x, foo(). However, because you're starting the call inside Derived, which overrides foo(), derived's foo() is actually executed by the interpreter.