Polymorphism with instance variables [duplicate] - java

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.

Related

Inner class object

I couldn't understand the behavior of the below code.
My expectation was that it should print 100 in both println() methods. Why the result is different?
If I uncomment getX() method in inner class, then the output of println() methods are the same which is 100.
I couldn't figure out the reasoning of different behavior. Please help me to understand.
public class Foo {
public static void main(String[] args) {
MyOuter outerObj = new MyOuter();
MyOuter.MyInner innerObj = outerObj.new MyInner();
innerObj.setX();
System.out.println("x: " + innerObj.getX()); //x: 3
System.out.println("x: " + outerObj.getX()); //x: 100
}
}
class MyOuter {
private int x = 3;
public int getX() { return x; }
class MyInner extends MyOuter {
public void setX(){ x = 100; }
// public int getX() { return x; }
}
}
From MyInner's perspective, there are two private int x fields in play here:
One field super.x that is inherited from MyOuter, but inaccessible because it is declared as private, and MyInner as an inheriting object cannot access this field.
One field MyOuter.this.x from the sorrounding MyOuter-instance (since MyInner is a (non-static) inner class, it is always bound to an instance of the surrounding MyOuter), that is accessible.
The method setX() in MyInner cannot access the inherited field super.x, thus it accesses the field MyOuter.this.x and sets its values to 100. A consecutive call on the surrounding MyOuter's getX() will return 100.
The call innerObj.getX() (which is inherited from MyOuter and can access super.x) returns the value of the inherited field super.x (still having its initial value of 3).
If we remove the extends MyOuter from and include the getX()-method in MyInner, the code behaves as expected.
The fact that MyInner cannot access the inherited field private x is confusing at first, but the behaviour is actually in line with the behaviour of the keyword protected in the context of static mehthods in inheriting classes as discussed in this post by Hariharan

How does Superclass cast on objects work? [duplicate]

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
}
}

Java Inheritance Test [duplicate]

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.

How to implement multiple subclasses with the same methods that use encapsulation?

I want to create a simple game in Java.
I'm struggling to understand how to use inheritance to accomplish how to implement subclasses that use encapsulation without needing to write out the same methods in the subclasses.
Ideally I'd like to make one base class "character" with a bunch of methods that use encapsulation, so that I can just declare different values for the private members of the subclasses. So something like,
public class Character {
private int hitPoints;
public int getHitPoints(){return hitPoints;}
}
And then just declare different values for the variables.
public class subCharacter extends Character {
private int hitPoints=100;
//getHitPoints() already inherited and should return 100
}
But to properly get the hit points of the subclass. I have to declare the same method in the subclass to actually get the method to work.
So isn't encapsulation incompatible with inheritance? Is there something basic here I'm misunderstanding or completely overlooking?
You should make the variable hitPoints protected in you Character class, and set it to 100 in the constructor of the subCharacter class. There is no need for the declaration of the getHitPoints method in the subclass. The code would look like this:
public class Character {
protected int hitPoints;
public int getHitPoints(){return hitPoints;}
}
public class subCharacter extends Character {
public subCharacter () {
hitPoints = 100;
}
}
Example of a subCharacter object:
subCharacter sub = new subCharacter();
System.out.println(sub.getHitPoints()); // prints 100
The reason this doesn't work like you think it should is because the subclass's hitpoints field is different from the superclass's hitpoints field. So while the superclass method is defined, it's trying to refer to a variable that you never actually initialized because it's not the same variable named hitpoints.
As others have already said, you should use the protected access modifier instead of the private access modifier on fields you want to have inherited to a subclass.
Then again, you probably don't actually need the SubCharacter class to begin with, if this is what you're actually writing for. You just need to have a constructor that takes a variable argument for hitpoints, or any other field in Character that needs to take different values.
//I'm not going to reproduce everything.
Character(int hp, String nm, boolean someBooleanThatIJustMadeUpToGetTheConceptAcross){
hitpoints = hp;
name = nm;
randomBoolean = someBooleanThatIJustMadeUpToGetTheConceptAcross;
}
This is not to say, however, that you don't need a superclass/subclass if, say, you're using this Character class for both enemies and player characters, for instance.
For an example of when you'd use inheritance...
public class Circle{
protected int radius;
Circle(){//It's always a good idea to have default constructors, by the way.
radius = 1;
}
Circle(int rad){
radius = rad;
}
}
public class Wheel extends Circle{
protected int numspokes;
Wheel(){
super(); //Calls the constructor for Circle, instead of reimplementing the wheel. badpuns++;.
numspokes = 0;
}
Wheel(int rad, int spokes){
super(rad); //This passes the radius up to the Circle this Wheel also is, so that any calls to this Wheel AS IF IT WAS a Circle, like an array or ArrayList of Circles, will function, which is the point of inheritance.
numspokes = spokes;
}
}

Object that stores two vars with the same name

In this code I allocate one only object, but in some way I store 2 copies of x (one for the base class and one for the subclass). How is it possible if the object is only one? Where is the space found to store two x vars? Does it mean in reality two objects are createed?
class App {
class Base {
public int x;
public Base() {
x = 2;
}
int method() {
return x;
}
}
class Subclass extends Base {
public int x;
public Subclass() {
x = 3;
}
int method() {
return x;
}
}
public static void main(String[] args) {
new App().run();
}
public void run() {
Base b = new Subclass();
System.out.println(b.x);
System.out.println(b.method());
}
}
One x belongs to the superclass and the other to the subclass. The fact that they have the same name is of no importance and you can access both by qualifying your access expression with the class:
((Base)b).x
((Subclass)b).x
(note that the cast in the first line is not necessary; I've put it in for symmetry)
In java you can not overload variables.,Though they are with the same name,their classes are different.
According to this tutorial(in section "What You Can Do in a Subclass"), when you declare a field in the subclass with the same name as the one in the superclass, in this case x, the one in the superclass will be hidden, which means that there're actually two xs in the subclass, one for itself, the other for its superclass, only baring the same name x. You can reference to the one in the derived class using derivedObject.x and the one in the subclass using ((Base)derivedObject).x(or super.x if within the derived class)

Categories

Resources