Accessing subclass members through super class reference variables - java

I am reading a Java text book and came across a doubt.
A reference variable of a superclass can be assigned a reference to an object of any subclass derived from that superclass. However, when a reference to a subclass object is assigned to a superclass reference variable, you will have access only to those parts of the object defined by the superclass.
Example:
class X {
int a;
X(int i) {
a = i;
}
}
class Y extends X {
int b;
Y(int i, int j) {
super(j);
b = i;
}
}
class SupSubRef {
public static void main(String args[]) {
X x = new X(10);
X x2;
Y y = new Y(5, 6);
x2 = x; // OK, both of same type
System.out.println("x2.a: " + x2.a);
x2 = y; // still Ok because Y is derived from X
System.out.println("x2.a: " + x2.a);
// X references know only about X members
x2.a = 19; // OK
// x2.b = 27; // Error, X doesn't have a b member
}
}
So, in the above example, x2 (a variable of the superclass type) can refer to an object of the derived class, bit it cannot access subclass specific members. However, in the discussion on method overriding, it is shown that a superclass reference variable's call to an overridden method can be resolved to the subclass method. But the subclass method is not defined in the superclass, so isn't this a contradiction, how is the superclass reference variable able to access the subclass specific method? Example:
class Sup {
void who() {
System.out.println("who() in Sup");
}
}
class Sub1 extends Sup {
void who() {
System.out.println("who() in Sub1");
}
}
class Sub2 extends Sup {
void who() {
System.out.println("who() in Sub2");
}
}
class DynDispDemo {
public static void main(String args[]) {
Sup superOb = new Sup();
Sub1 subOb1 = new Sub1();
Sub2 subOb2 = new Sub2();
Sup supRef;
supRef = superOb;
supRef.who();
supRef = subOb1;
supRef.who();
supRef = subOb2;
supRef.who();
}
}
The output from the program is shown here:
who() in Sup
who() in Sub1
who() in Sub2
So how is supRef able to access the who method in the subclass object?

When the textbook says that you can't access subclass-specific members with x2, it meant that you can't access them at compile time.
To the compiler. x2 is of type X (though it's really of type Y at runtime), so when the compiler sees you trying to access stuff defined in Y, it spots and says "that is not defined in X. You can't do that!"
However, we all know that at runtime, x2 stores a reference to a Y object. At runtime, you can indeed access members defined in Y with x2. You can prove this by using reflection.
At runtime, x2 is of type Y, so obviously Y's implementation will be called.

Related

Explain how variable hiding is working in this Java code

Consider below code
class A
{
int x = 5;
void foo()
{
System.out.println(this.x);
}
}
class B extends A
{
int x = 6;
// some extra stuff
}
class C
{
public static void main(String args[])
{
B b = new B();
System.out.println(b.x);
System.out.println(((A)b).x);
b.foo();
}
}
Output of the program is
6
5
5
I understand the first two but can't get my head around the last one. How does b.foo() print 5. B class will inherit the foo method. But shouldn't it print what b.x would print? What exactly is happening here?
Yes, the B class inherits the foo method. But the variable x in B hides the x in A; it doesn't replace it.
This is an issue of scope. The foo method in A sees only the variables that are in scope. The only variable in scope is the instance variable x in A.
The foo method is inherited, but not overridden, in B. If you were to explicitly override foo with the same exact code:
class B extends A
{
int x = 6;
#Override
void foo()
{
System.out.println(this.x);
}
}
Then the variable that would be in scope when referred to by this.x would be B's x, and 6 would be printed. While the text of the method is the same, the reference is different because of scope.
Incidentally, if you really wanted to refer to A's x in the B class, you can use super.x.
Well, this is because of static binding.
1) Static binding in Java occurs during Compile time while Dynamic
binding occurs during Runtime.
2) private methods, final methods and static methods and variables
uses static binding and bonded by compiler while virtual methods are
bonded during runtime based upon runtime object.
3) Static binding uses Type(Class in Java) information for binding
while Dynamic binding uses Object to resolve binding.
4) Overloaded methods are bonded using static binding while overridden
methods are bonded using dynamic binding at runtime.
Fields are not overridable in Java and subclasses with same field names as the parent class shadow "only" the fields of the parent class.
So this.x refers to the x defined in the current class : A.
Whereas the result : 5.
To be more precise : the foo() method is inherited by the B subclass but it doesn't mean that the behavior of the inherited method will change about instance fields referenced since as said fields are not overridable : the this.x expression that refers the A.x field in the foo() method goes on referencing A.x.
It is exactly the same thing as for the two previous statements :
B b = new B();
System.out.println(b.x); // refers B.x -> 6
System.out.println(((A)b).x); // refers A.x -> 5
b.foo(); // refers under the hood A.x -> 5
The very good answer of rgettman shows how you can overcome the field hiding in the subclass.
A alternative to overcome the hiding relies on making the instance field private (which is recommended) and providing a method that returns the value.
In this way you benefit from the overriding mechanism and the field hiding is not an issue any longer for clients of the classes :
class A
{
private int x = 5;
int getX(){
return x;
}
void foo()
{
System.out.println(this.getX());
}
}
class B extends A
{
private int x = 6;
int getX(){
return x;
}
}
In JAVA, methods can be overridden while variables can't. So, as your method foo is not overridden in B, it takes the member variable from A.
When you call
b.foo();
It checks to see if B has overridden the method foo(), which it has not. It then looks one level up, to the superclass A and invokes that method.
You have then invoked A's version of foo() which then prints out
this.x
Now, A can not see B's version of x.
In order to solve this, you have to override the method in B
class B extends A
{
int x = 6;
#Override
void foo()
{
System.out.println(this.x);
}
}
Now, calling
b.foo();
will call B's version of foo() and you will get the expected result.

What is the difference between the two statements?

I create the object using two statements , is there any difference between the two ?
public interface vehicle
{
void accelerate () ;
}
class bmw implements vehicle
{
void accelerate ()
{
System.out.println (" top speed of 300kmph " ) ;
}
}
public class driver
{
public static void main (String qw [] )
{
vehicle v = new bmw () ; // statement 1
v.accelerate () ;
bmw b = new bmw() ; // statement 2
b.accelerate() ;
}
}
Both the statements are giving same output but I think there is some difference between the two .
Variable 'y' it's private so you can't access it directly from you subclass.
But you can organize the access to this variable creating public methods.
So when are you calling:
subclass.show ( 23 , 45 );
you are not accessing directly to 'y' attribute of 'A' class but only to a public method defined in it where you are using 'y'. You can do it because it's a method in 'A' class.
Trying to explain better:
Private modifier let your attribute in this case be not accesible from a subclass. So you can"t do this:
B b = new B();
b.y = 10;
Because you don't have direct access to this attribute.
So now you can define how subclass can access this private attribute with a public method. The best example will be a getter or setter: (this methods have to be defined in your superclass)
Public int getY(){
Return this.y;
}
Public void setY(int y){
This.y = y;
}
Now you can access to private attribute 'y' but you need to call this public method so now you can do:
B b = new B();
b.setY(10);
And you will change the value of 'y'.
Now, according to yuor code, you didn't made any setter or getter but you defined a method call 'show(int,int)' where you are changing the value of 'y'.
And this is working likely as setter methods.
So you can access directly this method like:
B b = new B();
b.show(5,10);
Because it's a public method. And inside of this method you are doing operationts on a private attribute.
So, finally, the private attribute 'y' belongs to 'A' superclass and can't be access directly by any subclass but you can manage operations defining public method in superclasw where you specific how other classes can access superclass private attribute.
I have this doubt because since y is a private variable then how can y belong to object subclass ?
'y' doesn't belong to subclass. As i said before you can access 'private' attributes only using public methods defined in superclass. So if i want to change value or show 'y' i can do it only if there is public methods in superclass that change or show 'y' value.
void show (int o ,int e )
{
x=o ; // I mean to say ,
int y ; // Is this implicitly declared above ?
y=e ;
System.out.println(" x = " + x);
System.out.println(" y = " + y);
}
Here you don't need to declare 'int y;' because this method is defined in superclass and so you have direct access to 'y'.
If you need more please comment.
yes, y will b printed because y is local and it has been initialized before printing . so there is no error.
In your second program, Y is private member of class A and it is not directly accesible in its child class. you have made object of sub class but you have not override show method of parent class.So the show method of parent class means A class will be executed, and there you will find Y.

Overloading method on extended class

Simple question, strange result. I have two classes A and B:
public class A
{
protected int num;
public A(int n)
{
num = n;
}
public boolean f(A a)
{
return num == a.num * 2;
}
}
public class B extends A
{
public B(int n)
{
super(n);
}
public boolean f(B b)
{
return num == b.num;
}
}
Why does y1.f(y2) call the f() method in A instead of in B?
A y1 = new B(10);
B y2 = new B(10);
System.out.println(y1.f(y2));
Is it not supposed to call f() in B as B is more specific than A?
Why does y1.f(y2) calls the f() method in A instead of in B?
Because the compile-time type of y1 is A.
Overloading is performed at compile-time... the execution-time type of the object you call the method on is only relevant for overriding.
So the compiler is choosing the method f(A) as that's the only f method it's aware it can call on y1 (and it's checked that it's applicable given the argument list). That method isn't overridden in B, therefore at execution time, the implmenetation in A is called.
As a starker example, consider this code:
Object x = "foo";
int length = x.length();
This won't even compile, because Object doesn't contain a length() method. String does, but the compiler doesn't consider that, because the compile-time type of x is Object, not String - even though we can tell that at execution time, the value of x will be a reference to a String object.

Query on field shadowing in java

This concept contradicts the concept of a class and it's instance.
Below is the program that looks fine to me and gives NullPointerException as expected:
class SuperClass{
int x = 2;
}
class SubClass extends SuperClass{
int x = 4;
}
public class Dummy2 {
public static void main(String[] args){
SubClass obj1 = new SubClass();
SuperClass obj2 = null;
System.out.println(obj1.x);
System.out.println(obj2.x);
}
}
But when I say SuperClass obj2 = obj1; strangely I see the value of SuperClass instance member value 2,
despite there is no instance of class SuperClass created in the above program.
Is this the valid concept in Java?
First, since obj2 is null in your example, it will of course throw a NPE when you attempt to access x in it.
Second, when you set obj2 = obj1, you are casting obj1, of type SubClass, to type SuperClass. When you then access x in obj2, you are accessing the x that SuperClass knows about, which has a value of 2. This is how it is supposed to work.
The reason is, the x in SubClass isn't overwriting the x in SuperClass. It is simply hiding it. So when obj1 is cast to type SuperClass, the x in SuperClass is now the visible x.
If you wish to get the x value that you seem to be expecting, simply use a getter instead of accessing x directly, and then you can override it in SubClass.
SuperClass:
public class SuperClass {
public int x = 2;
public int getX() {
return x;
}
}
SubClass:
public class SubClass extends SuperClass {
public int x = 4;
public int getX() {
return x;
}
}
test code:
SubClass obj1 = new SubClass();
SuperClass obj2 = obj1;
System.out.println(obj2.x); // outputs 2
System.out.println(obj2.getX()); // outputs 4
It's valid in java, and many other languages strongly typed. When you upcast the variable to a superclass you can use properties of that class only. This make a variable strongly typed. Means that you have a variable of the type that you can use regardless of instance type. The type of variable is important that you have access to.

How Base class initialize when initialize Sub class

The code is like this :
class Base {
int x = 10;
public Base() {
this.printMessage();
x = 20;
}
public void printMessage() {
System.out.println("Base.x = " + x);
}
}
class Sub extends Base {
int x = 30;
public Sub() {
this.printMessage();
x = 40;
}
public void printMessage() {
System.out.println("Sub.x = " + x);
}
}
public class DispatchTest {
public static void main(String[] args) {
Base b = new Sub();
System.out.println(b.x);
}
}
The result is :
Sub.x = 0
Sub.x = 30
20
Can anybody please tell me how this code run?
Why doesn't the costructor of class Base run?
Because you created a new Sub object instance. The class Sub has the printMessage() method overriden, which means that the Base.printMethod() is not being executed.
The constructor of the Base class runs, but the this.printMessage() executes the printMessage method from the Sub class.
Immediatelly after the Sub's constructor has been invoked, the Base constructor is being called. It prints Sub.x = 0 because no x (in Sub) has been set so far. After that the value x gets assigned.
After the Base constructor is done, the rest of the Sub constructor is being executed. It prints calls the Sub's printMessage method again, but this time the value x has a value, and it prints Sub.x = 30.
The 20 comes from the System.out.println(b.x);.
You might wonder, why the value xis not assigned during the first printMessage call? Because you have x in your Sub class as well, so the x from the Base class is not visible!
Your SuperClass constructor is always called but "Polymorphic behaviour cannot be seen when accessing overridden member variables".
Base b = new Sub();
System.out.println(b.x);
Now if you access x(which is present in both subclass and superclass) it is actually the type of reference variable which determines the value.
Note: This behaviour is different with overridden methods,in this case it is actually the type of object which determines the method to be called not the type of reference variable.
The constructor
public Sub() {
this.printMessage();
x = 40;
}
is equivalent to
public Sub() {
super();
this.printMessage();
x = 40;
}
So when you create
Base b = new Sub();
Base's constructor gets executed followed by Sub's constructor. See JLS 8.8.7, which states
The first statement of a constructor body may be an explicit
invocation of another constructor of the same class or of the direct
superclass
Base's constructor is calling printMessage() which is overriden by Sub. When it gets called from Base's constructor printMessage() prints x of Sub which is not yet initialized. This is an anti pattern, so Sub.x = 0 gets printed (x is not yet initialized, and hence default value of int which is 0 )
Now once the Base's constructor finishes, Sub's constructor gets called and now the x is initialized to 30 why?
because
class Sub extends Base {
int x = 30;
public Sub() {
this.printMessage();
x = 40;
}
....
essentially means
class Sub extends Base {
int x;
public Sub() {
{
x=30;
}
this.printMessage();
x = 40;
}
....
hence this time printMessage() prints Sub.x = 30
finally 20 is printed because fields are NOT overriden.
When ever we are creating child class object then the following sequence of events will be executed automatically.
Step 1.Identification of instance members from parent to child and initialize them to default value.
after first step
Base instance variable is int x=0;
Sub instance variable is int x=0;
Step 2. Execution of instance variable assignments and instance blocks only in parent class
after second step
Base class instance variable is int x= 10;
Sub class instance variable is int x = 0;
Step 3.Execution of parent class constructor.
after third step
here you have a "printMessage()" invocation.It is overridden in child class Sub
So Sub class method is executes and prints Sub class's variable x value,which is now assigned as 0 only.
So the out put now "Sub.x = 0".
and Base class int x = 20;
Sub class int x = 0;
Step 4.Execution of instance variables and instance blocks in child class.
After 4th step
Base class int x=20;
Sub class int x=30;
Step 5.Execution of child constructor.
After 5th step.
In Sub class constructor you have "printMessage()" method invocation.So it will executes and prints output.
So the out put now "Sub.x = 30".
After the method invocation you have an assignment.
So now Base class int x=20;
Sub class int x=40;
For now your Sub class constructor created successfully.
Now you a print statement of variable x on type reference "Base".So now "Base" class variable x will be prints as output.
So the out put is "20".

Categories