Slight confusion regarding overriding where variables are concerned - java

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.

Related

Holding Child Object to a Reference of Parent [duplicate]

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.

Java Type System: Why do these assignments, method calls and type casts fail?

Let's say I have the following interface and classes defined:
public interface I { void a(); }
public class A implements I {
public void a() { System.out.println("A"); }
}
public class B implements I {
public void a() { System.out.println("B"); }
public void b() { System.out.println("C"); }
}
And then I run the following code:
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
I i;
i = a;
i.a(); // prints "A"
i = b;
i.a(); // prints "B"
i.b(); // 1st problem: i can't seem to find method b. Why?
b = i; // 2nd problem: b can't be assigned to i although i references an object of class B?
b = (B)i; // why does this work fine...
a = (A)i; // 3rd problem: ...but this here doesn't?
}
}
So here are my questions:
First Problem
Why can't i.b() be called?
i points to the same object as b, an object of class B which does have a method b.
So why does i.a() call the right method (the one that prints out "B") but i.b() doesn't resolve at all?
Does the fact that i was declared as being of type I (an interface) have anything to do with that? Does this mean that in an assignment X x = new Y() where Y extends X, one can only ever call methods on x that are already declared in X, and not just specific to Y?
Second Problem
Why can't b be assigned to i although i references an object of class B? b and i already reference the same object, don't they? So why does it cause an error if I try to assign b to i - the end result of which should be identical to the state of the program before that assignment, unless I'm missing something significant.
Third Problem
Why can I cast i to type B now although I couldn't assign b to i earlier, and why doesn't casting i to A work?
I'm assuming my confusion is somehow rooted in an unclear distinction between the reference variables and the objects they're referencing, as well as the differences between the types of these variables and objects. I just can't quite explain these occurrences - and in particular the first problem confuses me a lot.
For the first problem:
You can use the interface reference to call only the methods it declares
For the second problem:
You can use interface reference to invoke methods in the classes that implement the interface. However, there is no use to assign interface reference to a class reference since interface reference doesn't have any methods that can be invoked.
for the third problem:
You have assigned previously
i=b
and hence
b=(B)i
works fine.
However,
a=(A)i
wouldn't work because i stores b and not a
First of all, learn Java (and/or OO (object oriented)) programming...
Variable i is a reference to an object instance that implements interface I. Method b() was not declared in interface I, thus it is not visible through i.b().
To be able to call it, i needs to be casted, EG: ((B) i).b()
Variable b is a reference to an object that is an instance of class B, and cannot be assigned to any reference that itself is not declared as an instance of B.
Again, a cast needed, EG: b = (B) i
Class B is not a child of class A. They both implement interface I, but A is not parent of B.
It's not a problem at all but It's behavior of inheritance and polymorphism.
Please note that when you
I i = new A();
Left hand side (I) will tells compiler which all methods it can call using that reference.
Right hand side (A) will tells the runtime which method should execute using that method call
So in your case
1 Problem
you can not call b() since b() is not there in inteface I
2 Problem
you are casting interface to object b and then calling b() so its working fine.

Java subclass passing itself through a superclass constructor [duplicate]

I am studying overriding member functions in Java and thought about experimenting with overriding member variables.
So, I defined classes
public class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
public class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class mainClass
{
public static void main(String [] args)
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
System.out.println(aRef.intVal);
aRef.identifyClass();
}
}
The output is:
1
I am class A
1
I am class B
I am not able to understand why when aRef is set to b intVal is still of class A?
When you make a variable of the same name in a subclass, that's called hiding. The resulting subclass will now have both properties. You can access the one from the superclass with super.var or ((SuperClass)this).var. The variables don't even have to be of the same type; they are just two variables sharing a name, much like two overloaded methods.
Variables are not polymorphic in Java; they do not override one another.
There is no polymorphism for fields in Java.
Variables decision happens at a compile time so always Base Class variables (not child’s inherited variables) will be accessed.
So whenever upcasting happens always remember
1) Base Class variables will be accessed.
2) Sub Class methods(overridden methods if overriding happened else inherited methods as it is from parent) will be called.
Variables are resolved compile-time, methods run-time. The aRef is of type A, therefore aRef.Intvalue is compile-time resolved to 1.
OverRiding Concept in Java
Functions will override depends on object type and variables will accessed on reference type.
Override Function: In this case suppose a parent and child class both have same name of function with own definition. But which function will execute it depends on object type not on reference type on run time.
For e.g.:
Parent parent=new Child();
parent.behaviour();
Here parent is a reference of Parent class but holds an object of Child Class so that's why Child class function will be called in that case.
Child child=new Child();
child.behaviour();
Here child holds an object of Child Class, so the Child class function will be called.
Parent parent=new Parent();
parent.behaviour();
Here parent holds the object of Parent Class, so the Parent class function will be called.
Override Variable: Java supports overloaded variables. But actually these are two different variables with same name, one in the parent class and one in the child class. And both variables can be either of the same datatype or different.
When you trying to access the variable, it depends on the reference type object, not the object type.
For e.g.:
Parent parent=new Child();
System.out.println(parent.state);
The reference type is Parent so the Parent class variable is accessed, not the Child class variable.
Child child=new Child();
System.out.println(child.state);
Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.
Parent parent=new Parent();
System.out.println(parent.state);
Here the reference type is Parent, so Parent class variable is accessed.
From JLS Java SE 7 Edition §15.11.1:
This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used.
Answers from Oliver Charlesworth and Marko Topolnik are correct, I would like to elaborate a little bit more on the why part of the question:
In Java class members are accessed according the type of the reference and not the type of the actual object. For the same reason, if you had a someOtherMethodInB() in class B, you wouldn't be able to access it from aRef after aRef = b is run. Identifiers (ie class, variable, etc names) are resolved at compile time and thus the compiler relies on the reference type to do this.
Now in your example, when running System.out.println(aRef.intVal); it prints the value of intVal defined in A because this is the type of the reference you use to access it. The compiler sees that aRef is of type A and that's the intVal it will access. Don't forget that you have both fields in the instances of B. JLS also has an example similar to yours, "15.11.1-1. Static Binding for Field Access" if you want to take a look.
But why do methods behave differently? The answer is that for methods, Java uses late binding. That means that at compile time, it finds the most suitable method to search for during the runtime. The search involves the case of the method being overridden in some class.
I hope this can help:
public class B extends A {
// public int intVal = 2;
public B() {
super();
super.intVal = 2;
}
public void identifyClass() {
System.out.println("I am class B");
}
}
So overriding variable of base class is not possible, but base class variable value can be set (changed) from constructor of inherited class.
This is called variable hiding. When you assign aRef = b; , aRef has two intVal, 1 is named just intVal another is hidden under A.intVal (see debugger screenshot), Because your variable is of type class A , even when you print just intVal java intelligently picks up A.intVal.
Answer 1: One way of accessing child class's intVal is System.out.println((B)aRef.intVal);
Answer 2: Another way of doing it is Java Reflection because when you use reflection java cant intelligently pickup hidden A.intVal based on Class type, it has to pick up the variable name given as string -
import java.lang.reflect.Field;
class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class Main
{
public static void main(String [] args) throws Exception
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
Field xField = aRef.getClass().getField("intVal");
System.out.println(xField.get(aRef));
aRef.identifyClass();
}
}
Output -
1
I am class A
2
I am class B
Well, I hope u got the answer. If not, you can try seeing in the debug mode. the subclass B has access to both the intVal. They are not polymorphic hence they are not overriden.
If you use B's reference you will get B's intVal. If you use A's reference , you will get A's intVal. It's that simple.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
Hence the variable in the sub class only can be seen as one sharing the same name.
Also when the constructor of A is called during the instance creation of B the variable (intVal) is initialized and hence the output.
It is because when you assign b to aRef, it is resolved, leading aRef to just be of class A. This means that aRef does not have access to any of class B's fields or methods. If you call for intVal instead by using b.intVal, you will get 2.
Java has a feather of encapsulation means it tightly binds the property and the behavior of an object. so only via a class reference we can call it's behavior to change it's property.
and in inheritance only method overrides so that it can affects only it's property.
As Many users have already pointed out, this is not polymorphism. Polymorphism only applies to methods(functions).
Now as to why the value of the intVal of class A is printed, this happens because as you can see the reference aRef is of type A.
I can see why you are confused by it. By the same procedure you have accessed the overridden methods for ex. the method identifyClass() but the not the variables which directly proves the first line that I have written .
Now in order to access the variable you can do ((Superclass)c).var
Note here that the Superclass can be many levels up for example
A<-B<-C. That is C extends B and B extends A. If you wanted the value of var of A then you could have done ((A)c).var .
EDIT: as one of the users have pointed out this 'trick' does not apply to static methods, because they are static.

Java: duplicate method signature in nested 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!!

Why isn't this method chosen based on the runtime-type of its object?

Consider this:
class A {
int x =5;
}
class B extends A{
int x =6;
}
public class CovariantTest {
public A getObject() {
return new A();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest {
public B getObject(){
return new B();
}
}
As far as I know, the JVM chooses a method based on the true type of its object. Here the true type is SubCovariantTest, which has defined an overriding method getObject.
The program prints 5, instead of 6. Why?
The method is indeed chosen by the runtime type of the object. What is not chosen by the runtime type is the integer field x. Two copies of x exist for the B object, one for A.x and one for B.x. You are statically choosing the field from A class, as the compile-time type of the object returned by getObject is A. This fact can be verified by adding a method to A and B:
class A {
public String print() {
return "A";
}
}
class B extends A {
public String print() {
return "B";
}
}
and changing the test expression to:
System.out.println(c1.getObject().print());
Unless I'm mistaken, methods are virtual in java by default, so you're overriding the method properly. Fields however (like 'x') are not virtual and can't be overriden. When you declare "int x" in B, you are actually creating a totally new variable.
Polymorphism doesn't go into effect for fields, so when you try and retrieve x on an object casted to type A, you will get 5, if the object is casted to type B, you will get 6.
When fields in super and subclasses have the same names it is referred to as "hiding". Besides the problems mentioned in the question and answer there are other aspects which may give rise to subtle problems:
From http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html
Within a class, a field that has the
same name as a field in the superclass
hides the superclass's field, even if
their types are different. Within the
subclass, the field in the superclass
cannot be referenced by its simple
name. Instead, the field must be
accessed through super, which is
covered in the next section. Generally
speaking, we don't recommend hiding
fields as it makes code difficult to
read.
Some compilers will warn against hiding variables

Categories