I tried to upcast an objet. But at runtime object class is remained as a derived class.
Derived drv = new Derived();
Base base = (Base) drv;
System.out.println("Class : " + base.getClass());
//prints -> Class : class packagename.Derived
So Why class property didn't change?
So Why class property didn't change?
Because the object hasn't changed, just the type of the reference you have to it. Casting has no effect at all on the object itself.
In Java, unlike some other languages (thankfully), the type of the reference largely doesn't affect which version of a method you get. For instance, consider these two classes (courtesy of 2rs2ts — thank you!):
class Base {
public Base() {}
public void foo() {
System.out.println("I'm the base!");
}
}
class Child extends Base {
public Child() {}
public void foo() {
System.out.println("I'm the child!");
}
}
This code:
Child x = new Child();
Base y = (Base) x;
y.foo();
...outputs
I'm the child!
because even though the type of y is Base, the object that we're calling foo on is a Child, and so Child#foo gets called. Here (again courtesy of 2rs2ts) is an example on ideone to play with.
The fact that we get Child#foo despite going through a Base reference is crucial to polymorphism.
Now, it just so happens that the method you were calling (getClass) can only be Object#getClass, because it's a final method (subclasses cannot override it). But the concept is crucial and I figured it was probably the core of what you were asking about.
The chief thing that the type of the reference does is determine what aspects of an object you're allowed to access. For instance, suppose we add bar to Child:
class Child extends Base {
public Child() {}
public void foo() {
System.out.println("I'm the child!");
}
public void bar() {
System.out.println("I'm Child#bar");
}
}
This code won't compile:
Child x = new Child();
Base y = (Base) x;
y.bar(); // <=== Compilation error
...because Base has no bar method, and so we can't access the object's bar method through a reference with type Base.
You can not change the type of an instance in Java. All you're doing with your cast is reference it from a variable of a different type.
An upcast does not change the object's type. As a matter of fact, NOTHING changes a Java object's type.
That's the very core of OO programming: An object has a defined behavior that can't be influenced from the outside.
Related
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.
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.
In the following example, I reckon it's something about run time polymorphism, but I can't figure out why y.m1(x) prints out A. My understanding is that y.m1() calls the m1()method in class B, because y contains an object of B. Since x is passed to it as a parameter, and it belongs to the class A which is wider than B, won't it lead to a run-time error? Plus how come z.m1(y) prints out A too?
Many thanks in advance!
class A {
public void m1(A a) {
System.out.println("A");
}
}
class B extends A {
public void m1(B b) {
System.out.println("B");
}
}
class D2 {
public static void main(String[] args) {
A x = new A();
A y = new B();
B z = new B();
}
}
B's m1 does not override A's m1 method, as it does not take the same parameter. So B class consist of two overloaded m1 methods, one taking an A object, the other taking a B object.
Only static polymorphism can be used here, that's why you can see this behavior.
The dynamic type of an object (the type used in the new) is it's actual runtime type: it defines the actual methods that are present for an object.
The static type of an object reference (a variable) is a compile-time type: it defines, or rather declares, which methods can be called on the object the variable references.
Because the parameter type of both the dynamic type and the static type are different, we dynamic type doesn't override the method, but overloads it.
If the parameter types would have been the same, the output would be B...
class A {
int super_var = 1;
}
class B extends A {
int sub_var = 2;
}
public class Demo{
public static void main(String []args){
A a = new B();
System.out.print(a.sub_var); //compile error
}
}
why this will end with a compile error ? reference (a) referencing to an Object of B it has sub_var so why is it restricted ? why reference (a) can access only the fields in A ?
Let's say you have these classes:
public class Animal() {
// ...
}
public class Fish extends Animal() {
public void swim() {...}
}
If you declared an Animal:
Animal x = new Fish();
and you called the swim() method
x.swim();
Would you expect it to work? I don't think so, because not every animal can swim. That's why you have to explicitly specify that the animal x is a Fish:
((Fish) x).swim();
In your case, if you wanted to call that method, you should specify (technically, it's called cast) the type:
System.out.print(((B)a).sub_var);
Note:
This works similar for methods and variables. I used a method in the example since it's more illustrative.
Edit:
Let's see this example:
Animal x;
if (some_condition)
x = new Fish();
else
x = new Cat();
x.swim();
This restriction exists, because Java won't know if, at execution time, the object assigned to x will have the method swim(). So to avoid this, you have to cast to the respective type to call a method that doesn't exist in superclass.
At first it does sound like it should work. (And in some languages it probably does.) But think about this example:
public class Demo {
public static void main(String []args){
A a = new B();
print( a );
}
public static void print( A arg ) {
System.out.print(arg.sub_var); //compile error
}
}
This functionally does the same thing but the print is in another method. If your version worked, this one could be expected to work too.
But what if someone then does this?
Demo.print( new A() );
This should fail because A doesn't have a sub_var. It would have to throw some kind of runtime error instead.
So the design decision in Java was not to allow this and if you declare a local variable/field/method parameter as type A, then you can only access things that every object that is either A or a subclass is guaranteed to have.
If you want to access more, you need to cast it to the subclass, which will throw an exception if you try it on an object that doesn't fit.
A a = new A();
System.out.print(((B)a).sub_var); //ClassCastException is thrown here
You can not access B members with the reference of Parent object A.
Instead change your println statement like below to access,
System.out.print(((B)a).sub_var);
Is there a variable called sub_var in the parent class ? No. That is why you get the error -
sub_var cannot be resolved or is not a field
See this
System.out.print(a.super_var); //okay
System.out.print(a.sub_var); //compile error
you create an object of type B and assign it to a variable of type A. The type A does not declare sub_var. This field is declared only in type B. the compiler only sees what is declared in type A, although the variable is instantiated to an object of type B.
If you want to access sub_var you would have to cast a to B.
System.out.println( ((B)a).sub_var);
The sub_var is in class B, so you can only access through a reference of class B. To the compiler A a = new B(); means a is an instance of class A.
I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.