This question already has answers here:
Java inheritance fields [duplicate]
(5 answers)
How to cast subclass object to superclass object
(4 answers)
Closed 3 years ago.
Let's say I have a super-class Ugrad like this:
public class Ugrad{
int DM = 140;
int perYear() { return DM/4; }
}
And I have a sub-class of that class named Grad , like this:
public class Grad extends Ugrad{
int DM = 28;
int perYear() { return DM/2; };
Now , I have a tester class , in which I do some prints to learn how objects work, like this:
//In the line-comments I denote what the result of the print will be.
public class Tester{
public void main(String[] args){
Grad g = new Grad();
System.out.println(g.DM); // 28
System.out.println(g.perYear()); // 14
Ugrad u = (Ugrad) g;
System.out.println(u.DM); //140
System.out.println(u.perYear()); //14
}
}
My question is how does super-class cast works on objects?
Why does u.perYear prints 14 equals to g.DM/2 when u.DM equals to 140?
You are casting a subclass to a superclass.
This is upcasting (or implicit casting) as per: Inheritance -> Casting Obects
This means that this casting can be done implicitly.
You do not have to put casting operator after the assignment.
Every Grad object is implicitly an object of class Upgrad because
of your declaration: Grad extends Upgrad.
I.e. this will work:
Upgrad u = g;
You have overriden the perYear() method.
After casting to a superclass and calling this method it will stay as implemented in Grad class because of polymorphism principles and override rules for Java:
This questions has in fact been answered here and here on Stackoverflow.
To quote Learning Java by Daniel Leuck & Patrick Niemeyer:
When there are multiple implementations of a method in the inheritance hierarchy of an object, the one in the “most derived” class (the furthest down the hierarchy) always overrides the others, even if we refer to the object through a reference of one of the superclass types.
This is defferent from hiding a field.
Hiding or shadowing a field is best described here:
Subclassing and inheritance -> Shadowed Variables
A different set of types is used there in the link but the meaning is the same:
Another important point about shadowed variables has to do with how they work when we refer to an object by way of a less derived type (a parent type). For example, we can refer to a DecimalCalculator object as an IntegerCalculator by using it via a variable of type IntegerCalculator. If we do so and then access the variable sum, we get the integer variable, not the decimal one:
DecimalCalculator dc = new DecimalCalculator();
IntegerCalculator ic = dc;
int s = ic.sum; // accesses IntegerCalculator sum
As said in Inheritance -> What You Can Do in a Subclass :
You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it (not recommended).
Testing code:
class Ugrad {
int DM = 140;
int perYear() { return DM/4; }
}
class Grad extends Ugrad {
int DM = 28; // we have *hidden* Upgrad.DM field by
int perYear() { return DM/2; }
}
public class UpgradGrad {
public static void main(String[] args){
Grad g = new Grad();
System.out.println(g.DM); // Grad.DM field is accessed directly, thus output = 28
System.out.println(g.perYear()); // 14
Ugrad u = g; // this will work because of implicit casting to a superclass
System.out.println(u.DM); // g is casted to u. Grad.DM was hiding Upgrad.DM. Thus Upgrad.DM emerges.
System.out.println(u.perYear()); // because g is just referred to as Upgrad, its original Grad.perYear() method will be called
}
}
Related
This question already has answers here:
Hiding Fields in Java Inheritance
(2 answers)
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
I have a parent class A which has a primitive type property x
public class A {
String type = "A";
int x = 5 ;
void increment()
{
x++ ;
System.out.println(x);
}
}
I have a child class B which extends from class A, This child class also has propery x of String type
public class B extends A {
String type = "B" ;
String x = "Hello";
}
Now, both parent and child class has instance variable x with different type( int and String).
Parent class A has a method to increase value of X and now the method is available in the child class B ( Class B extends Class A, so all the methods in class A are accessible in class B)
Now I have a main method in a Runner class,
public class Runnable {
public static void main(String[] args)
{
//Creating object
B instanceOfB = new B() ;
//Invoke increment method
instanceOfB.increment();
}
}
While running the main method, I got an OUTPUT : 6
I am invoking increment method using reference variable instanceOfB
instanceOfB.increment();
instanceOfB is an instance of Class B.
By invoking this function, we are trying to increase the value stored in variable x, but x has reference to a String Object.
It should either throws compile time reception or run time exception because we are trying to increase a String object, It is not possible but I got output 6.
The behavior of instance variables and instance methods in a class hierarchy is different. If you wanted to access the value in the subclass from the superclass, you would need to wrap the subclass value with an instance method that is declared in the superclass but overridden in the subclass.
This question already has answers here:
Overriding member variables in Java ( Variable Hiding)
(13 answers)
Closed 9 years ago.
Here are three classes that I wrote:
public class Shape {
public int x = 0;
public void getArea() {
System.out.println("I don't know my area!");
}
public String toString() {
return "I am a shape!";
}
public int getX() {
return x;
}
}
public class Rectangle extends Shape {
public int x = 1;
public int getX() {
return x;
}
public void getArea() {
System.out.println("L*W");
}
public String toString() {
return "I am a rectangle!";
}
}
public class Tester {
public static void main(String[] args) {
Shape s = new Shape();
Rectangle r = new Rectangle();
System.out.println(r);
System.out.println(r.x + "\n");
s = r;
System.out.println(s);
s.getArea();
System.out.println(s.x);
System.out.println(s.getX());
}
}
The output from the main method of the Tester class is:
I am a rectangle!
1
I am a rectangle!
L*W
0
1
Why does s.x return 0 and not 1? As isn't the current instance of the variable a Rectangle and that class also has that same instance variable declared, or does the variable in the Rectangle class not override the previous public x variable in the Shape class as it does to the getX() method in the rectangle class thus returning 1?
Also as a general rule the superclass has access to the implementation of the its subclasses methods only if they are declared in that class as well? Is this because the compiler will see that the same amount of methods with the same signature are in the "Shape" class (with overridden Rectangle implementations) and accept those as valid Shape methods?
Thanks in advance,
There is no polymorphism for fields in Java. There is however, inheritance. What you've effectively done is create two fields in your Rectangle class, with the same name. The names of the field are, effectively:
public class Rectangle {
public int Shape.x;
public int Rectangle.x;
}
The above doesn't represent valid Java, its just an illustration of how the fields are scoped in your class
Within the entire scope of the Rectangle class, the superclass field of the same name is hidden. So anytime you reference the simple name x, or the scoped name this.x, within the class, you are referring to the field that is defined in Rectangle. You can actually access the superclass field as well, with the scoped name super.x.
Now, from outside of the class, the rules for which field is being accessed is slightly different. The scope will be determined by the compile time type of the class that the field is being referenced from. So in your code:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(s.x);
The output is 0 because the compile time type of s is Shape (not Rectangle). You can observe a change in this behavior when you do this:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(((Rectangle)s).x);
Presto! Your output is now 1, because the compiler sees that you've scoped the field access to Rectangle.
To condense the rules of visibility:
You can read more about instance variable hiding in the JLS, Section 8.3.3.2
Subclasses only inherit variables and methods in the superclass, not the other way around. So in order to get x to equal 1 you have to call rectangle not shape.Unless you do what the other guy demonstrated with casting which you should avoid as much as possible in real programming. Plus you should never use public instance variables ever! If you want variables to be public at least make them static or constant.
This question already has answers here:
Java Inheritance - instance variables overriding
(3 answers)
Closed 8 years ago.
Code in Java
public class A {
int x;
public A() {
x = 0;
}
public void print() {
System.out.println("This is A");
}
}
public class B extends A {
int x;
public B() {
x = 1;
}
public void print() {
System.out.println("This is B");
}
}
B b = new B();
A a = b;
System.out.print(a.x);---------------->0
a.print();---------------->This is B
I am very confused. I create object b for B class, although I assign b to a, I think b should still point the class B. Why the "a.x" will return 0 instead of 1? Why a.x point to the x in A, but a.print() point to the print() method in B?
fields are not polymorphic but the methods are,
which means method will be invoked on the object which is referred by reference at runtime
field variables are tied to reference, so if you remove field x from class A and try the same code it will fail to compile
You are seeing some irregularities on how polymorphism is applied in Java. Polymorphism is seen where invoking a.print() invokes B's print(), while this is not the case for fields. The field is tied to the reference, so in this case b.x and a.x are distinct (although you could leave out x in B's definition and have a single field declared in the superclass. In that case, a form of hiding is seen.
This question already has answers here:
Overriding member variables in Java ( Variable Hiding)
(13 answers)
Closed 9 years ago.
Here are three classes that I wrote:
public class Shape {
public int x = 0;
public void getArea() {
System.out.println("I don't know my area!");
}
public String toString() {
return "I am a shape!";
}
public int getX() {
return x;
}
}
public class Rectangle extends Shape {
public int x = 1;
public int getX() {
return x;
}
public void getArea() {
System.out.println("L*W");
}
public String toString() {
return "I am a rectangle!";
}
}
public class Tester {
public static void main(String[] args) {
Shape s = new Shape();
Rectangle r = new Rectangle();
System.out.println(r);
System.out.println(r.x + "\n");
s = r;
System.out.println(s);
s.getArea();
System.out.println(s.x);
System.out.println(s.getX());
}
}
The output from the main method of the Tester class is:
I am a rectangle!
1
I am a rectangle!
L*W
0
1
Why does s.x return 0 and not 1? As isn't the current instance of the variable a Rectangle and that class also has that same instance variable declared, or does the variable in the Rectangle class not override the previous public x variable in the Shape class as it does to the getX() method in the rectangle class thus returning 1?
Also as a general rule the superclass has access to the implementation of the its subclasses methods only if they are declared in that class as well? Is this because the compiler will see that the same amount of methods with the same signature are in the "Shape" class (with overridden Rectangle implementations) and accept those as valid Shape methods?
Thanks in advance,
There is no polymorphism for fields in Java. There is however, inheritance. What you've effectively done is create two fields in your Rectangle class, with the same name. The names of the field are, effectively:
public class Rectangle {
public int Shape.x;
public int Rectangle.x;
}
The above doesn't represent valid Java, its just an illustration of how the fields are scoped in your class
Within the entire scope of the Rectangle class, the superclass field of the same name is hidden. So anytime you reference the simple name x, or the scoped name this.x, within the class, you are referring to the field that is defined in Rectangle. You can actually access the superclass field as well, with the scoped name super.x.
Now, from outside of the class, the rules for which field is being accessed is slightly different. The scope will be determined by the compile time type of the class that the field is being referenced from. So in your code:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(s.x);
The output is 0 because the compile time type of s is Shape (not Rectangle). You can observe a change in this behavior when you do this:
Shape s = new Shape();
Rectangle r = new Rectangle();
s = r;
System.out.println(((Rectangle)s).x);
Presto! Your output is now 1, because the compiler sees that you've scoped the field access to Rectangle.
To condense the rules of visibility:
You can read more about instance variable hiding in the JLS, Section 8.3.3.2
Subclasses only inherit variables and methods in the superclass, not the other way around. So in order to get x to equal 1 you have to call rectangle not shape.Unless you do what the other guy demonstrated with casting which you should avoid as much as possible in real programming. Plus you should never use public instance variables ever! If you want variables to be public at least make them static or constant.
I have 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.