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.
Related
I am thinking about this java oop problem . I don't exactly know exactly what is really happening there . Can someone make me understand ?
abstract class A {
public int proc (A p){
return 98;
}
}
class B extends A {
public int proc(A p) {
return 17;
}
}
class C extends A {
public int proc (C p) {
return 65;
}
}
public class HelloWorld{
public static void main(String []args){
C x = new C(); // here x is C type and is an instance of C ?
A y=new B(); // here y is A type and is an instance of B?
C z=new C(); // here z is C type and is an instance of C ?
System.out.println(y.proc(x)+z.proc(x)); /* y is A type so it is looking for proc function in A ,but doesn't return 98
, z is C type and it is looking for proc function in C and return 65 .*/
}
}
Can someone tell me how should I tackle theese instances ?
Y is an A but contains a reference to a B so when we call y.proc it is the proc in B that is called, and returns 17, not 98.
You need to look at the instance that is created and not the type of variable.
In Java, you can create base class objects which hold the child classes objects except for abstract classes.
A is an abstract class, you cannot instantiate it, but you can assign an object of the child class to it which holds the child class object's features.
You can think, we are assigning the reference of B to y which has a type of A.
System.out.println(y.proc(x));
The code above will print 17, which is the return value of the proc in class B returns.
Whenever you call the methods of y, the compiler will give you class B's methods automatically.
So, you are creating an instance of class B in the memory and assigning it to y which points to the same memory location.
For that reason, you can use the methods of class B.
Same goes for z as well.
class A {
public int a = 100;
}
class B extends A {
public int a = 80;
}
class C extends B {
public int a = 10;
public void show() {
int a = 0;
System.out.println(a);
System.out.println(super.a);
System.out.println(((A) this).a);
}
}
What does ((A) this).a in the line System.out.println(((A) this).a); do?
Is it upcasting/downcasting thisor is something else happening here?
I also tried System.out.println(this); and System.out.println((A)this); and they both have the same output. What exactly is happening here?
In the java programming language, we have classes. When we write java code, we create instances of those classes, for example:
Object o = new Object();
Object is a class. Writing new Object() creates an instance of that class. The above code declares a variable o and assigns it [a reference to] an instance of class Object.
In the terminology of the java programming language, we say that variable o has type Object.
In the code in your question, a variable that is assigned an instance of class C, really has three types.
It has type C.
It has type B since B is the superclass of C.
It has type A because it indirectly extends class A also.
In the context of the code in your question, this is a special variable whose type is C. Writing (A) this is telling java to relate to the variable this as if its type is A.
Class A cannot access its subclasses. Hence it is only aware of its class member a. Hence when you write this line of code...
((A) this).a
You are accessing the member of class A only.
System.out.println(a);a is the one from the show method of your C class → a = 0
System.out.println(super.a);a is the one from the super-class of C, which is B → a = 80
System.out.println(((A) this).a);First, you cast your C instance (this) into A, then you call a which is a member of the A class → a = 100
There is also something to consider : method will always take the more specialized one (except if super is used), where field will be taken directly from the type referenced (even if there is an extending class).
For example, if I add getA() in each classes :
class A {
public int a = 100;
public int getA(){
return a;
}
}
class B extends A {
public int a = 80;
public int getA(){
return a;
}
}
class C extends B {
public int a = 10;
public int getA(){
return a;
}
public void show() {
int a = 0;
System.out.println(a);
System.out.println(super.a);
System.out.println(((A) this).a);
System.out.println(getA());
System.out.println(super.getA());
System.out.println(((A) this).getA());
}
}
class Scratch {
public static void main(String[] args) {
new C().show();
}
}
I get the following output :
0
80
100
10
80
10
Which means that in the case of the method, except in the case of super.getA() which explicitly goes to the superclass, casting your C into a A doesn't change much for methods, as it impacts the field.
If you write something like obj.a, obj.getA() or someMethod(obj), Java somehow has to find the actual field or method to be used, based on the type or class of obj. There are two distinct dispatch mechanisms involved (plus the special construct super).
Dynamic dispatch (polymorphism, overriding): This is used when calling an instance method on the object, as in obj.getA(). Then the runtime class of the obj is examined, and if this class contains a getA() method, this is used. Otherwise, the direct parent class is examined for a getA() method, and so on up to the Object class.
Static dispatch: In cases like obj.a or someMethod(obj), the runtime class of obj doesn't matter. Involved is only the compiler, and from his knowledge of obj's type, he decides which field or method to use.
super dispatch: If you write super.getA() or super.a, your getA() method or a field is ignored, and instead the next-higher class in the hierarchy is used that contains such a method or field.
In your case you have 3 fields plus one local variable, all with the same name a. (By the way, it's a very bad idea to have such name conflicts in professional code.) We are inside a method show() declared in the C class. Let's have a look at some different expressions and what they mean here:
a references the local variable a. There's no dispatch needed, it's just that local definitions take precedence over fields.
this.a is a static-dispatch expression, so it's important what the compiler thinks about the type of this. And that's always the class where this code has been written. In your case, it's class C, so the field a from class C is used, the one being 10.
super.a is a super-dispatch expression, meaning that the a field from this class C is ignored and the next higher one taken (the one from B, in our case).
((A) this).a is static dispatch, but the (A) casting has a significant effect. The expression before the dot originally comes from this, being of type C, but the (A) cast tells the compiler to believe it were of type A. This is okay, as every C also is an A, by inheritance. But now, static dispatch sees something of type A in front of the dot, and dispatches to the a field from the A class, and no longer from C.
getA(), this.getA() and ((A) this).getA() are all dynamic-dispatch examples, all giving the same result. The method called will be the one based on the runtime class of this object. This will typically be one defined in the C class. But if show() was called on an object of a subclass of C, e.g. D, and D had its own getA() method, that one would be used.
super.getA() is a case of super-dispatch, it will call the getA() method next higher up in the class hierarchy from the current class, e.g. B.
System.out.println(this);
And
System.out.println((A)this)
These two prints the object reference to class C with toString() method.
System.out.println(((A)this).a);
This is upcasting, child object to parent object.
I am facing some problems about inheritance in Java.
I can't understand why the following two programs have those outputs!
Could anyone help me? :)
1)
public class A {
int foo() {
return 1;
}
}
public class B extends A {
int foo() {
return 2;
}
}
public class C extends B {
int bar(A a) {
return a.foo();
}
}
C x = new C();
System.out.println(x.bar(x));
// OUTPUT:2
2)
public class A {
int e=1;
}
public class B extends A {
int e=2;
}
public class C extends B {
int bar(A a){
return a.e;
}
}
C x= new C();
System.out.println(x.bar(x));
// OUTPUT:1
In both cases, you're passing in an object of type C into the print function. The bar function asks for an object of type A, but it's still acceptable for you to pass in an object of type C since it is a subclass of A. So first of all, it's important to keep in mind that a.foo() and a.e are being called on a C object.
So what is happening in both cases is that it's searching for the lowest attribute or method in the list. Here is a very simplified version of what Java is doing in part 1:
Hey, you've passed in an object of type C to the bar method! Now let's call its foo method.
Whoops! C doesn't have a foo method! Let's take the next step up to the B class to see if it has a foo method.
Yay! B has a foo method, so let's call it. No need to work our way up to the A class because we've already found what we need in B.
It's all about understanding that the parameter was downcast from A to C. The exact same sort of logic is used in part 2. It notices that an object of type C was passed in, so it gets the e attribute from object B since its the lowest class in the hierarchy that contains that attribute.
Hopefully that answers your question!
This question already has answers here:
Is it possible to call subclasses' methods on a superclass object?
(9 answers)
Closed 6 years ago.
I am new to Java and I have trouble understanding one thing:
When I am declaring an Object by assigning to a sub object (a class extending object), it doesn't have access to sub object attributes.
Why is that ?
Let's say I have this:
public class A {
public int a;
}
public class B extends A {
public int b;
}
When I create an B object like this:
A object = new B();
I don't have access to object.b
I am forced to declare that way
B object = new B();
Isn't my object supposed to be a B with the first way to ?
The object is of type B only at runtime, at compile time , the compiler does not that its actual type is B since the variable object is declared of type A, an explicit downcast is required
A object = new B();
B b = (B)object;
int x = b.b;
If you called myfunc():
A object = myfunc();
And I define myfunc() as:
A myfunc() {
if (new Random().nextBoolean()) {
return new A();
} else {
return new B();
}
}
Can you still expect to always access object.b? No. myfunc() is only promising that it will return something of class A (or derived from class A)
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.