This question already has answers here:
Why does Java bind variables at compile time?
(4 answers)
Closed 7 years ago.
class A {int x = 5;}
class B extends A {int x = 10;}
class D {
public static void main(String[] args){
A b0 = new B();
System.out.print(b0.x);
}
}
I am wondering why this code prints 5 instead of 10.
If I instead write the following, converting the variables x to methods, it works more as I'd expect, and prints out 10, since at compile time it merely checked if b0's static type, A, has a method x, and then at runtime, uses b0's dynamic type, B, to run x.
class A {int x() {return 5;}}
class B extends A {int x() {return 10;}}
class D {
public static void main(String[] args){
A b0 = new B();
System.out.print(b0.x());
}
}
My theory is that instance variables are looked up statically unlike methods, but I am not sure about why that would be.
Thanks!
In B the field x from A is shadowed(hidden) not overriden. To answer "why that would be" references to the docs here and here. The compiler will pick one of the 2 instances of x according to the type of the containing object. And b0 is of type A
A b0 = new B();
When you define (getter) methods on the other hand these can override methods with the same signature in the parent class. Another nasty surprise is that a field in the parent class is shadowed even if it's a different type.
Shadowing of members is considered a bad practice as it tends to confuse developers.
Because you are accessing the variable x from the class A, since b0 is defined as A. It is called hiding a variable, and not as you might suspect overriding a variable, which is not possible in java. You would get your expected result if you would access x from b0 by using a typeCast.
A b0 = new B();
System.out.print(((B)b0).x);
By using a typeCast you would be accessing the variable x from the class B now.
for further information you could read through JLS 8.3
Static fields are not inherited, they do not override each other, they shadow each other. When you directly access Static field of the same name in your case, the field of superclass hides the other field and you have two int Xes but the one of the superclass is not hidden and gets picked. Even better yet, when you call another instance of the same method and access the same static field, that is when things get very weird. The static fields get added together and you may end up with X being 5+5 = 10.
On the other hand, if you inherit non static field from superclass, there is no problem of it having different value in sub-class, because the sub-class can override the non-static super member.
Static variables and inheritance is bad, it breaks the polymorphism where you would least expect it. (Actually, if you understand concepts of your language, you expect it, but other people may not)
Related
I'm preparing for the SCJP (recently rebranded as OCPJP by Oracle) and one particular question that I got wrong on a mock exam has confused me, the answer description doesn't explain things clear enough.
This is the question :
class A
{
int x = 5;
}
class B extends A
{
int x = 6;
}
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest
{
public B getObject()
{
return new B();
}
}
The answer is 5, but I chose 6.
I understand that overriding applies to methods at runtime, and not variables, but the way my mind interpreted that println was :
call getObject on c1
c1 is actually a SubCovariantTest object, and has a valid override
for getObject(), so use the overridden method
The override returns B, so grab x from B which is 6
Is it a case of the JVM ignoring the getObject() part, and always taking x from c1 as variables are associated at compile time?
Although the override is done properly for SubCovariantTest the answer is 5 because of how the variable c1 is declared. It is declared as a CovariantTest and not as a SubCovariantTest.
When c1.getObject().x is run, it does not know that it is a SubCovariantTest (no casting was used). This is why 5 is returned from CovariantTest and not 6 from SubCovariantTest.
If you change
System.out.println(c1.getObject().x);
to
System.out.println(((SubCovariantTest) c1).getObject().x);
you will get 6 as you expected.
Edit: As pointed out in the comments
"fields are not polymorphic in Java. Only methods are. The x in the subclass hides the x in the base class. It doesn't override it." (Thanks to JB Nizet)
Okay I know this is a bit late to reply to this question but I and my friend had the same problem and the answers already here didn't quite clear it for us. So I'll just state what problem I had and how it makes sense now :)
Now I do understand that fields don't get overrided but instead they get hidden as miller.bartek pointed out and I also understand that overriding is for methods and not fields as Scott points out.
The problem I had however was this. According to me,
c1.getObject().x
This must transform into:
new B().x // and not newA().x since getObject() gets overrided
And that evaluates to 6.
And I couldn't get why the variable of class A (super-class) is being called by an object of class B (sub-class) without having explicitly asked for such a behaviour.
And guessing from the wording of the question, I feel the OP had the same question/doubt in mind.
My Answer:
You get a hint from Elbek's answer. Put the following lines in the main method and try to compile the code:
A a = c1.getObject(); //line 1
B b = c1.getObject(); //line 2
You'll notice that line 1 is completely legal while line 2 gives compilation error.
So when the function getObject() is being called, the CovariantTest (super) function IS getting overrided by SubCovariantTest (sub) function since that is valid overriding in the code and c1.getObject() WILL return new B().
However, since the super-function returns a reference of class-type A, even after getting overrided, it must return a reference of class-type A unless ofcourse we type-cast it. And here, class B is a class A (due to inheritance).
So practically, what we're getting from c1.getObject() is not
new B()
but this:
(A) new B()
That is why the output comes out to be 5 even though an object of class B is returned and class B has value of x as 6.
The technical term for what is happening here is "hiding". Variables names in Java are resolved by the reference type, not the object they are referencing.
A object has a A.x variable.
B object has both A.x and B.x variables.
However instance methods with the same signature are "overridden" not "hidden", and you cannot access the version of a method that is overridden from the outside.
Note that hiding also applies to static methods with the same signature.
Your mock question in a simplified form (without overriding):
class A {
int x = 5;
}
class B extends A {
int x = 6;
}
public class CovariantTest {
public static void main(String[] args) {
A a = new B();
B b = new B();
System.out.println(a.x); // prints 5
System.out.println(b.x); // prints 6
}
}
You are calling method from c1: System.out.println(c1.getObject().x);
c1 reference type is:
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
so for this: c1.getObject() return type is A. from A you getting directly attribute not method, as you mention java does not override attributes, so it is grabbing x from A
When methods are overridden, subclass methods are called, and when variables are overridden the superclass variables are used
When the child and parent class both have a variable with same name child class's variable hides parent class's variable and this is called variable hiding.
While variable hiding looks like overriding a variable similar to method overriding but it is not, Overriding is applicable only to methods while hiding is applicable variables.
In the case of method overriding, overridden methods completely replaces the inherited methods so when we try to access the method from parent's reference by holding child's object, the method from child class gets called.
But in variable hiding child class hides the inherited variables instead of replacing, so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class.
When an instance variable in a subclass has the same name as an instance variable in a superclass, then the instance variable is chosen from the reference type.
You can read more on my article What is Variable Shadowing and Hiding in Java.
class A {
public int a = 100;
}
class B extends A {
public int a = 80;
}
class C extends B {
public int a = 10;
public void show() {
int a = 0;
System.out.println(a);
System.out.println(super.a);
System.out.println(((A) this).a);
}
}
What does ((A) this).a in the line System.out.println(((A) this).a); do?
Is it upcasting/downcasting thisor is something else happening here?
I also tried System.out.println(this); and System.out.println((A)this); and they both have the same output. What exactly is happening here?
In the java programming language, we have classes. When we write java code, we create instances of those classes, for example:
Object o = new Object();
Object is a class. Writing new Object() creates an instance of that class. The above code declares a variable o and assigns it [a reference to] an instance of class Object.
In the terminology of the java programming language, we say that variable o has type Object.
In the code in your question, a variable that is assigned an instance of class C, really has three types.
It has type C.
It has type B since B is the superclass of C.
It has type A because it indirectly extends class A also.
In the context of the code in your question, this is a special variable whose type is C. Writing (A) this is telling java to relate to the variable this as if its type is A.
Class A cannot access its subclasses. Hence it is only aware of its class member a. Hence when you write this line of code...
((A) this).a
You are accessing the member of class A only.
System.out.println(a);a is the one from the show method of your C class → a = 0
System.out.println(super.a);a is the one from the super-class of C, which is B → a = 80
System.out.println(((A) this).a);First, you cast your C instance (this) into A, then you call a which is a member of the A class → a = 100
There is also something to consider : method will always take the more specialized one (except if super is used), where field will be taken directly from the type referenced (even if there is an extending class).
For example, if I add getA() in each classes :
class A {
public int a = 100;
public int getA(){
return a;
}
}
class B extends A {
public int a = 80;
public int getA(){
return a;
}
}
class C extends B {
public int a = 10;
public int getA(){
return a;
}
public void show() {
int a = 0;
System.out.println(a);
System.out.println(super.a);
System.out.println(((A) this).a);
System.out.println(getA());
System.out.println(super.getA());
System.out.println(((A) this).getA());
}
}
class Scratch {
public static void main(String[] args) {
new C().show();
}
}
I get the following output :
0
80
100
10
80
10
Which means that in the case of the method, except in the case of super.getA() which explicitly goes to the superclass, casting your C into a A doesn't change much for methods, as it impacts the field.
If you write something like obj.a, obj.getA() or someMethod(obj), Java somehow has to find the actual field or method to be used, based on the type or class of obj. There are two distinct dispatch mechanisms involved (plus the special construct super).
Dynamic dispatch (polymorphism, overriding): This is used when calling an instance method on the object, as in obj.getA(). Then the runtime class of the obj is examined, and if this class contains a getA() method, this is used. Otherwise, the direct parent class is examined for a getA() method, and so on up to the Object class.
Static dispatch: In cases like obj.a or someMethod(obj), the runtime class of obj doesn't matter. Involved is only the compiler, and from his knowledge of obj's type, he decides which field or method to use.
super dispatch: If you write super.getA() or super.a, your getA() method or a field is ignored, and instead the next-higher class in the hierarchy is used that contains such a method or field.
In your case you have 3 fields plus one local variable, all with the same name a. (By the way, it's a very bad idea to have such name conflicts in professional code.) We are inside a method show() declared in the C class. Let's have a look at some different expressions and what they mean here:
a references the local variable a. There's no dispatch needed, it's just that local definitions take precedence over fields.
this.a is a static-dispatch expression, so it's important what the compiler thinks about the type of this. And that's always the class where this code has been written. In your case, it's class C, so the field a from class C is used, the one being 10.
super.a is a super-dispatch expression, meaning that the a field from this class C is ignored and the next higher one taken (the one from B, in our case).
((A) this).a is static dispatch, but the (A) casting has a significant effect. The expression before the dot originally comes from this, being of type C, but the (A) cast tells the compiler to believe it were of type A. This is okay, as every C also is an A, by inheritance. But now, static dispatch sees something of type A in front of the dot, and dispatches to the a field from the A class, and no longer from C.
getA(), this.getA() and ((A) this).getA() are all dynamic-dispatch examples, all giving the same result. The method called will be the one based on the runtime class of this object. This will typically be one defined in the C class. But if show() was called on an object of a subclass of C, e.g. D, and D had its own getA() method, that one would be used.
super.getA() is a case of super-dispatch, it will call the getA() method next higher up in the class hierarchy from the current class, e.g. B.
System.out.println(this);
And
System.out.println((A)this)
These two prints the object reference to class C with toString() method.
System.out.println(((A)this).a);
This is upcasting, child object to parent object.
i want to make sure that my understanding is correct in static-polymorphism
please look at the code below
class a {
int x=0;
}
class b extends a {
int x=4;
}
public class main4 {
public static void main(String[] args) {
a f = new b();
System.out.println(f.x);
b ff = new b();
System.out.println(ff.x);
}
}
the output is
0
4
does that happened because the compiler looks at the declared type of the reference and upon that determines which x to print at compile time ??
(f is declared as type a, the compiler looks at f.x and decides it means a.x)??
& if so,is this called a static-polymorphism or hiding or what ??
thanks in advance
Polymorphism is like looking on the object via the key hole. You don't see the whole object but only that it's part which corresponds to the type of variable you have assigned a reference to the object to.
The object can be seen as different "shapes/forms" - it depends what the key hole you are looking through. But it is still the same object in computer's memory. The form you can see depends on the type of variable you have assigned the object to.
Polymorphism is a multi-form of seeing same object.
If you have object created by new b() - you'll see it as a b class representant when you assign this object to the variable of type b. And you'll see it as a a class representant when you assign it to the variable of type a.
But it is still the same object. And... you can cast it between variables:
f = (a)ff;
and you'll see that suddenly the same object is seen as an representative of a class (including visibility of x field belonging to the a class).
Hopefully this question hasn't already been asked. I've had a look around but haven't found a similar post.
Experimenting in Java I've noticed that there is no restriction on having duplicate method signatures in a nested class, which seems counter-intuitive.
For example, if I create class A containing a method with the signature int x() and later add a nested class B containing an identical method, the compiler seems to have no problem with it. My initial assumption was that it would complain that x is already defined. Perhaps I'm missing something obvious that explains why this is allowed?
class A {
int x() {
return 1;
}
class B {
int x() {
return 2;
}
}
}
Subsequently, is there any way to access class A's method x from within the scope of class B, or is it permanently hidden by the method x of the local scope?
Edit: I appreciate that the core of the question is the same as this post, however, I was more interested in understanding why this behaviour is allowed as it wasn't immediately clear to me.
Where a class is defined doesn't matter so much. Keep in mind, in the end you have
class A { int x()
and
class A.B { int x()
Two (almost) independent classes. The only relationship that we have here is that any instance of B needs an "enclosing" instance of A to which it belongs (because it is a non-static inner class).
And of course, you can access the "enclosing" A "stuff" from within B, for example using A.this.x().
This should be available somewhere in the JLS - but ultimately it boils down to scope. Each of them has a different scope - thus the compiler does not complain.
Why would the compiler complain? They are two different classes, they just happen to be nested.
Subsequently, is there any way to access class A's method x from within the scope of class B, or is it permanently hidden by the method x of the local scope?
A.this.x()
At first method signature is not the combination of return type and method name it is method name and parameters.
if you call x() it will run x() inside the B
A.this.x(); it will run x() in A
Its scope, it's similar to have an instance variable called foo and then a local one in the method called foo as well.
Its worth reading about scope in java
Inner class in java can access all the members (i.e variables and methods) including private one, but outer class can not access member of inner class directly.
To access x() method of class B inside class A you can either create B's instance and call it or call like this A.this.x();
To access x() method outside class A you can do something like this:
B b = a.new B();
b.x();
If you are using non-static nested class (inner class) then it wouldn't be able to access to x method of B class from other classes. But if you are using static nested class you will be able to access that method from other classes. Example:
public class A {
int x() {
new A.B().x();
return 1;
}
static class B {
int x() {
new A().x();
return 2;
}
}
}
public static void main(String[] args) {
A a = new A();
a.x();
B b = new A.B();
b.x();
}
I hope this example answering your question... ☺
B is nested inside A. According to scope rules we can do the following:
class A {
int x() {
return 1;
}
class B {
int x() {
return 2;
}
int xOfA(){
return A.this.x();
}
}
public static void main(String[] args) {
final A objA = new A();
final B objB = objA.new B();
System.out.println(objA.x());
System.out.println(objB.x());
System.out.println(objB.xOfA());
}
}
that is because B is visible from an instance of A.
Moreover B can reference methods in the containing class through their full paths.
For example, if I create class A containing a method with the signature int x() and later add a nested class B containing an identical method, the compiler seems to have no problem with it. My initial assumption was that it would complain that x is already defined. Perhaps I'm missing something obvious that explains why this is allowed?
When you define something in a nest scope which is otherwise in an outer scope, this is hiding.
What is important is that -: The version of a method that is executed will NOT be determined by the object that is used to invoke it. In fact it will be determined by the type of reference variable used to invoke the method
Subsequently, is there any way to access class A's method x from within the scope of class B, or is it permanently hidden by the method x of the local scope?
So as it is clear from above we can access it using class name, eg A.x
Hope this helps!!
I'm preparing for the SCJP (recently rebranded as OCPJP by Oracle) and one particular question that I got wrong on a mock exam has confused me, the answer description doesn't explain things clear enough.
This is the question :
class A
{
int x = 5;
}
class B extends A
{
int x = 6;
}
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest
{
public B getObject()
{
return new B();
}
}
The answer is 5, but I chose 6.
I understand that overriding applies to methods at runtime, and not variables, but the way my mind interpreted that println was :
call getObject on c1
c1 is actually a SubCovariantTest object, and has a valid override
for getObject(), so use the overridden method
The override returns B, so grab x from B which is 6
Is it a case of the JVM ignoring the getObject() part, and always taking x from c1 as variables are associated at compile time?
Although the override is done properly for SubCovariantTest the answer is 5 because of how the variable c1 is declared. It is declared as a CovariantTest and not as a SubCovariantTest.
When c1.getObject().x is run, it does not know that it is a SubCovariantTest (no casting was used). This is why 5 is returned from CovariantTest and not 6 from SubCovariantTest.
If you change
System.out.println(c1.getObject().x);
to
System.out.println(((SubCovariantTest) c1).getObject().x);
you will get 6 as you expected.
Edit: As pointed out in the comments
"fields are not polymorphic in Java. Only methods are. The x in the subclass hides the x in the base class. It doesn't override it." (Thanks to JB Nizet)
Okay I know this is a bit late to reply to this question but I and my friend had the same problem and the answers already here didn't quite clear it for us. So I'll just state what problem I had and how it makes sense now :)
Now I do understand that fields don't get overrided but instead they get hidden as miller.bartek pointed out and I also understand that overriding is for methods and not fields as Scott points out.
The problem I had however was this. According to me,
c1.getObject().x
This must transform into:
new B().x // and not newA().x since getObject() gets overrided
And that evaluates to 6.
And I couldn't get why the variable of class A (super-class) is being called by an object of class B (sub-class) without having explicitly asked for such a behaviour.
And guessing from the wording of the question, I feel the OP had the same question/doubt in mind.
My Answer:
You get a hint from Elbek's answer. Put the following lines in the main method and try to compile the code:
A a = c1.getObject(); //line 1
B b = c1.getObject(); //line 2
You'll notice that line 1 is completely legal while line 2 gives compilation error.
So when the function getObject() is being called, the CovariantTest (super) function IS getting overrided by SubCovariantTest (sub) function since that is valid overriding in the code and c1.getObject() WILL return new B().
However, since the super-function returns a reference of class-type A, even after getting overrided, it must return a reference of class-type A unless ofcourse we type-cast it. And here, class B is a class A (due to inheritance).
So practically, what we're getting from c1.getObject() is not
new B()
but this:
(A) new B()
That is why the output comes out to be 5 even though an object of class B is returned and class B has value of x as 6.
The technical term for what is happening here is "hiding". Variables names in Java are resolved by the reference type, not the object they are referencing.
A object has a A.x variable.
B object has both A.x and B.x variables.
However instance methods with the same signature are "overridden" not "hidden", and you cannot access the version of a method that is overridden from the outside.
Note that hiding also applies to static methods with the same signature.
Your mock question in a simplified form (without overriding):
class A {
int x = 5;
}
class B extends A {
int x = 6;
}
public class CovariantTest {
public static void main(String[] args) {
A a = new B();
B b = new B();
System.out.println(a.x); // prints 5
System.out.println(b.x); // prints 6
}
}
You are calling method from c1: System.out.println(c1.getObject().x);
c1 reference type is:
public class CovariantTest
{
public A getObject()
{
return new A();
}
public static void main(String[]args)
{
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
so for this: c1.getObject() return type is A. from A you getting directly attribute not method, as you mention java does not override attributes, so it is grabbing x from A
When methods are overridden, subclass methods are called, and when variables are overridden the superclass variables are used
When the child and parent class both have a variable with same name child class's variable hides parent class's variable and this is called variable hiding.
While variable hiding looks like overriding a variable similar to method overriding but it is not, Overriding is applicable only to methods while hiding is applicable variables.
In the case of method overriding, overridden methods completely replaces the inherited methods so when we try to access the method from parent's reference by holding child's object, the method from child class gets called.
But in variable hiding child class hides the inherited variables instead of replacing, so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class.
When an instance variable in a subclass has the same name as an instance variable in a superclass, then the instance variable is chosen from the reference type.
You can read more on my article What is Variable Shadowing and Hiding in Java.