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.
Related
I'm struggling to understand the C() object created in this code.
I understand that when it is created on line 3, it is an object with the reference in the A class. I also understand that you can reference the same object on line 4 from a reference in the B class. However, I don't understand the casting of reference o1 on line 4. Does this change the object or just how it is referenced?
Would really appreciate an explanation :) thanks
public class TestClass{
public static void main(String args[ ] ){
A o1 = new C( );
B o2 = (B) o1;
System.out.println(o1.m1( ) );
System.out.println(o2.i );
}
}
class A { int i = 10; int m1( ) { return i; } }
class B extends A { int i = 20; int m1() { return i; } }
class C extends B { int i = 30; int m1() { return i; } }
In
A o1 = new C( );
you assign an object of type C to a variable of type A.
o1 can reference any object of class A or any sub-class of A (such as B and C). However, once you assign an object of class C to a variable of type A, you can only use that variable to execute methods declared in class A (or any super class of A).
If you want to execute methods of class B, you must tell the compiler that this variable actually references an object of class B (which is true, since that variable holds a reference to an object of class C, which is also of class B, since C extends B).
That's what the cast is for:
B o2 = (B) o1;
Now, using the variable o2, you can call methods declared in class B.
However, since all 3 classes declare a method of the same signature (int m1( )), the cast doesn't allow you to call a method you couldn't call via the o1 variable. It does, however, give you access to the instance variable i of class B (by writing o2.i).
Does this change the object or just how it is referenced?
It doesn't change the object. It just gives the compiler more detailed information about the actual type of the object referenced by that variable.
If I have three classes as follows:
package com.Bob.Marley;
public class SuperClass{
protected int x = 0;
}
package com.Bob.Marley;
public class SubClass extends SuperClass{
protected int x = 1;
}
package com.Bob.Marley;
public class TestClass{
public static void main (String[] args){
SubClass s = new SubClass();
//print 1
System.out.println(s.x);
//how do I print the superclass variable?
//I know inside SubClass I can access it with plain old super.x
//but what about outside the subclass with a new object.
}
}
So the question is how would I print out 0 from the superclass of the new object s created in a separate class. System.out.println(s.super.x); does not work. I don't think it changes anything but I am using java 8.
The expression s.super.x is invalid here. Whenever you prefix a super.x with something, it should be a type name, not a variable name, e.g. SuperClass.super.x. However, this would be valid only inside the subclass for accessing the superclass of the enclosing class, which does not exist here.
Cast x to be a SuperClass so you can access the x declared in Superclass.
System.out.println( ((SuperClass) s).x);
or
SuperClass sc = (SuperClass) s;
System.out.println(sc.x);
This works because variable access is statically binded. The type of the variable or expression determines the scope searched for variable access.
TL;DR: if you introduce a new field in a subclass, don't re-use a field name from the parent class. You gain nothing, only confusion and problems.
If I understand correctly, you want SubClass instances to have two fields, one inherited from the SuperClass (for the discussion, let's rename that to superX to make things clearer), and one from the subclass itself (let's rename that to subX).
For a given SubClass instance, you want to be able to access both fields, superX and subX (of course, using different expressions). What makes things difficult in your code sample, is the fact that you chose to give both of them the same name x.
So, if you really want your instances to carry both fields, I'd recommend to rename them, so you don't have to use ugly tricks like casting to the SuperClass.
public class SuperClass{
protected int superX = 0;
}
public class SubClass extends SuperClass{
protected int subX = 1;
}
But, if x stands for the same property with the same meaning for both the super and the sub class, just with different initial values, then it doesn't make sense to have two different fields, and you should change the code to become:
public class SuperClass{
protected int x = 0;
}
public class SubClass extends SuperClass{
// constructor initializes the x field with 1.
public SubClass(){
x = 1;
}
}
Of course, then it's impossible to get two different values from a single instance of SubClass.
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.
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.
I have an array of objects called _Array. I have defined _Array[0] as object that is a subclass of the superclass. I have fields in this sub class that dont exist in the superclass yet i want to access these fields from the array that i created in the superclass. Is this possible? There is sample code below. I have indicated the line i'm having an issue with by the comment.
public class SuperClass {
String color = "Red";
int favenumber = 15;
public static void main(String[] args) {
SuperClass[] _Array = new SuperClass[10];
_Array[0] = new SubClass(10, 150);
_Array[0].age = 10; /////THIS LINE HERE IS MY QUESTION
System.out.println(_Array[0].getClass());
}
}
public class SubClass extends SuperClass{
public int age = 0;
public int weight = 0;
SubClass(int age, int weight)
{
this.age = age;
this.weight = weight;
}
}
This is not possible, but you could instead do this, if you are COMPLETELY SURE that the object is always a SubClass:
((SubClass) _Array[0]).age = 10;
This is casting the object first as SubClass and then accessing the field in one line. You could also check first if it is a SubClass:
if(_Array[0] instanceof SubClass){
((SubClass) _Array[0]).age = 10;
}
You'd have to cast the object to the derived class, in your case:
((SubClass) _Array[0]).age = 10;
However, it's quite ugly:
The code will throw an InvalidCastException if the object in that array isn't of type SubClass, and the compiler cannot help you catch this.
The code is hard to understand.
Instead, you could first create a SubClass without immediately assigning it to the array, set the age as needed, and then add it to _Array:
SubClass s = new SubClass(10, 150);
_Array[0] = s;
Yes you can but compiler should complain that the object doesn't have field named age because your array is declared as containing superclasses but at runtime array[0] will be instance of subclass which effectively has age, you just have to add something in order that code compiles you should cast array[0] to subclass. I advise you to read about object oriented programming and inheritance