I ran into this example about inheritances on the web, and I am not easy regarding its results. I'm missing something critical.
public class A {
int i = 5;
public A() {
foo();
}
private void foo() {
System.out.println(i);
}}
public class B extends A {
int i = 6;}
public class C extends B {
int i = 7;
public void foo() {
System.out.println("C's foo");
System.out.println(super.i);
}}
I'm trying to figure out what's happening by the following command: C c = new C();
System.out.println(C.i);
I know that when we create a new instance of C we approach A's and B's constructures, So We reach to A() - (question 1) Does i (of A) being initialize on the way?
Now we need to call to foo()- (question 2)- Does C's foo() consider as an override of A's foo()? and what if B had a foo() of itself? then it was consider as a override and C's foo() was operated?
As far as I know, there is no override when it relates to local variables. How come that System.out.println(c.i) is 7 and not 5? shouldn't it b the i of the highest-father?
EDIT: My question is not about which foo and i will be used when I use c, is about what happens during these two specific commands, cause obviously A's foo was used and not C's.
Thank you very much.
The three i variables here are completely independent. Which one is used by any statement is determined at compile-time - there's no polymorphism involved. So A.foo() will always print out the value of the variable declared in A.
Note that these aren't local variables by the way - they're instance variables.
When you print out c.i that uses the variable declared in C because the compile-time type of c is C. You can see this if you write:
C c = new C();
A a = c;
B b = c;
System.out.println(a.i); // 5 - variable declared in A
System.out.println(b.i); // 6 - variable declared in B
System.out.println(c.i); // 7 - variable declared in C
Note that in a well-written program this sort of thing almost never causes a problem, as variables should be private.
No, you always use the the class member closest to the class you've instantiated. So, C c = new C(); will use i=7 and C's foo only. Class B's i is overridden by class C's i, just as A's i has been overridden by B's i.
There's no chaining going on, just overriding.
A, B, and C each have an instance variable called "i". If you have a C object and execute foo() you will print C's value for "i".
If you had put foo() in B rather than C, oddly you'd still get C's value for "i" if you have a C object, since the "outermost" version of "i" will be used.
About method overriding and visibility:
A.foo() is private. It means it's not visible to its subclasses. If you want B or C to override A.foo(), A.foo() needs to be protected or public. So in your code, B.foo() doesn't exist, because B doesn't know about A.foo().
Related
I have problems understanding the behaviour of this piece of code.
a is defined as an A, c is defined as a C.
Then, at the end of the public class, a = c.
When a calls the display() method it reaches the C version of it.
But when a calls the f() it only reaches the A version, despite the fact that the first arguments (byte and long) are more compliant with long than float.
It's an exercice from a book, but explanation is scarce, or inexistent.
class A{
public void display(){
System.out.println("I am an A ");
}
public void f(double x){
System.out.println("A.f(double = " + x + ") ");
}
}
class C extends A{
public void display(){
System.out.println("I am a C ");}
public void f(long q){
System.out.println("C.f(long = " + q + ") ");}
}
public class PolySurStack{
public static void main(String Args[]){
byte bb =1; long q = 4; float x = 5.f;
System.out.println(" ** A **");
A a = new A(); a.display();
a.f(bb); a.f(x);
System.out.println();
System.out.println(" ** C **");
C c = new C(); c.display();
c.f(bb); c.f(q); c.f(x);
System.out.println();
a = c; a.display();
a.f(bb); a.f(q); a.f(x);
}
}
When you call a.f(bb) or a.f(q) or a.f(x), the only method signatures the compiler can choose from are those defined in class A (or any super class of A), since a is a reference variable of type A.
Therefore, only public void f(double x) is considered. In order for public void f(long q) to be a candidate for overload resolution, you'd have to cast a to type C before calling f(), since only class C defines a method with that signature.
The important thing to understand is that method overloading resolution takes place in compile time. Only the compile time type of the reference variable for which you call the method determines which method signatures are candidates for method overloading resolution, as well as which candidate will be chosen.
I just found this on another forum :
Overloading :(same function name but different signature)
Two or more methods having the same name with different arugment in same class is known as Overloading.
Overloading is used when you want to extend the functionality.
Overloading is known as compile time polymorphism
Overriding :(same function name but same signature)
Two or more methods having the same method name and same arugment in parent class and child class in known as overriding.
Overriding is used when you want to reuse the existing functionlity.
Overriding is known as run time polymorphism
So the answer to my question seems to be that overriding resolution (like for display() )occurs at run time (here after a = c) while overloading resolution (like for f() ) occurs at compilation time, when a is Still an A.
I think.
I also found this page : https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/
to be clear and highly relevant to this topic.
The method selected by the compiler depends on the declared type, not on the runtime type.
The first series that declares as variable A can only invoke A methods (whatever the runtime type instantiated as A derives only of Object) :
A a = new A();
a.f(bb); a.f(x);
For the second series, the compiler binds the methods with the most specific parameter matching to the invocation since C is a A and so the compiler can bind any public methods of these here :
C c = new C();
c.f(bb); c.f(q); c.f(x);
But in the last chunk of code that probably questions yourself, a refers to C as runtime object but to A as declared type :
A a = new A();
// ...
a = c;
a.f(bb); a.f(q); a.f(x);
So only methods defined in A may be invoked.
I'll try to clarify the answer of #eran a bit so you can understand it.
A subclass has all the methods of its superclass, and then perhaps some more in addition to them. You have a variable of type A, in which you store an object of type C. C has all the methods that are defined in class A, and also an additional method that is f(long q). A is unaware of this new method, so since you store the object in a variable of A, you can't call f(long q).
You can however call display() because it is defined in A, but it will still be the C object that executes it.
Hello everyone,
I am very surprise to see the following program's output:
class A{
int f() {return 0;}
int g() {return 3;}
}
class B extends A{
int f() {return 1;}
int g() {return f();}
}
class C extends B {
int f() {return 2;}
}
public class Test {
public static void main(String args[]){
A ref1 = new C();
B ref2 = (B)ref1;
System.out.println(ref2.g());
}
}
Please help me to explain the code.
You are creating an instance of C and assigning it to the ref1 with type A. Further you are declaring a variable ref2 of type B which get assigned the value of ref1. The value of ref1 is still an instance of C even if you are viewing it by the type of class A.
Calling ref2.g() executes the method g() on the instance of the variable ref2. This is still the one and only created instance of C. Looking on it by the type of class B doesn't change the implementation of the instance the variable ref2 is referring to.
Let us extend class C by a method int h() { return 5; }. Using ref2 you cannot call method h() because the type of the variable is B. But h() is still present on the instance ref2 is referring to. If you extend the main method by
C ref3 = (C) ref2;
System.out.println(ref3.h());
this will output 5. But assigning the value of ref2 to ref3 and calling on it h() implies that the value of ref2 and ref3 (and ref1) is the same.
System.out.println(ref2 == ref3);
This outputs true. So both variables refer to the same object, the instance of C.
I will try to explain by steps:
Reference ref1 points to the instance of the class C.
Reference ref2 points to the same instance of the class C. No matter that it was done with explicit typecast, the instance in the heap still has the type C. Again:
ref2 has the type B;
object instance that ref2 is pointed to has the type C.
When we call to ref2.g(), JVM actually try to find method g() in class C (because object instance in heap has the type C, as was stated above). Because there is no method g() in class C, JVM moves to the parent class B, finds method g() in it, and calls it.
Call to method g() in class B leads to method f(). JVM again try to find that method initially in class C, finds it and return value 2.
This code represents overriding. And in overriding at runtime the jvm decides that which method to call (also called late binding).
Now come to code, the class C has the overridden method f() and in the code you have type-casted the reference of class A (ref1) to class B and called to g() method, so at runtime the jvm will call g() method of class B and ref2 is a reference of class B, which is pointing to class C object, so at runtime the f() method of class C has binded and it will call f() method of class C.
This question already has answers here:
Does polymorphism apply on class attributes in Java?
(8 answers)
Closed 4 years ago.
I have the following program :
class A{
int b = 50;
}
class B extends A{
int b = 20;
}
public class Maini{
public static void main(String[] args){
A a = new B();
System.out.println(a.b);
}
}
and the result is 50 and I would like to know why?
before I run the code I am pretty sure that the result should be 20.
This has nothing to do with how constructors work.
Note that the member variable b in class B does not override the member variable b in class A. Only non-static, non-private methods can be overridden. Member variables cannot be overridden.
If you have an instance of class B, then it actually has two member variables called b: one in the superclass (A) part of the object, and one in the subclass part (B).
The reason that you see the value 50, which is the value of b in the A part of the object, is because the variable a in the main method is of type A. If you change this to B, you'll get 20:
B a = new B(); // instead of A a = ...;
In the statement
A a = new B();
You are calling Bs constructor in an object of type A
In your program, you have given no constructor to B, so it looks to A.
In A, the value of int b is 50 and an object is of type A, hence the value is chosen as 50
If you had a constructor in B e.g.
B() { b = 20;}
the value would be 20.
You think that you are creating a B but you have not written any constrcutors for the class B so it looks to the super() constructor which is it's parents (A). So you now have an object of A. If you are curious about why A's object isi being created while there is no constructor to it too. A calls to it's super constructor too which is Java's Object Class's constructor.
I hope that I could make this point clear.
use a intellitrace enabled IDE for better experience of coding.
1st of all you'l hav a default constructor if you are not imposing on it.
Secondly you are defining an object of type 'A' not 'B'. if you want the output as 20 then you hav to include this B() {int b = 20;}.
Here in this code Sniplet there is no constructor in Any class.
So JVM will create no argument default constructor in all classes.
While you are Running this then .
In the below code you
a is referring class A and having object of class B
A a = new B();
So here the Object a will have class A 's variable value.
and Class B object value as its calling Class B 's default constructor(new B();)
If Class A and B have same Method like below Example:
class A{
int b = 50;
void method(){
System.out.println("Method of A class");
}
}
class B extends A{
int b = 20;
void method(){
System.out.println("Method of B class");
}
}
public class Maini{
public static void main(String[] args){
A a = new B();
System.out.println(a.b);
a.method();
}
}
Then a.method() will print
50
Method of B class
as a is have Class B 's object.
When you write A a = new B() the object a is type A. This is why you're getting b = 50. If you want to get b = 20, you need to declare a as a B class
Hope it's clear enough.
Best
This question already has answers here:
A Base Class pointer can point to a derived class object. Why is the vice-versa not true?
(13 answers)
Closed 7 years ago.
This is rather basic question. But I can't understand well the concept of inheritance.
Suppose I have two classes, A and B with both have a test() method that returned 1 and 2 respectively, and B inherited A class. In main method I declare the instance as such;
A a1 = new B();
and call the method a1.test(), it will return 2. This is the concept of polymorphism. But when I have a method test2() in just subclass, I can't call the method using the same instance declaration as above. Why is that happen?
I can't call the method using the same instance declaration as above. Why is that happen?
Because the type of the variable is A, and class A does not have a method test2(). The Java compiler only looks at the type of the variable to check if you can call a method, it does not look at the actual object (which is in this case a B).
This is all easier to understand if you use more concrete and meaningful names for your classes, instead of abstract names such as A and B. Let's call them Animal and Bear instead:
class Animal {
}
class Bear extends Animal {
public void growl() { ... }
}
class Cat extends Animal {
public void meow() { ... }
}
Animal a1 = new Bear();
Animal a2 = new Cat();
// Doesn't work, because not every Animal is a Bear, and not all
// animals can growl.
a1.growl();
// You wouldn't expect this to work, because a2 is a Cat.
a2.growl();
Because variable type is A, and class A does not have a method test2():
Rather you can use:
A a1 = new B(); // upcasting
B b1 = (B)a1; // Downcasting a1 to type B
b1.test2(); // now you can call test2 function
Because, the left side of your condition determines which method's you can call, and right side determines which methods will be called. So in this case class A does't have test2() method.
Imagine A = "TV" and B = "HD_TV".
You can say
TV tv = new HD_TV() // HD TV
and
TV tv = new TV() // ordinary TV
because an HD_TV is a TV.
You can say:
tv.show(movie)
It will show what is on TV, but you will get a better picture with the HDTV.
You cannot say:
tv.showHD(hdMovie) // Compiler error !!!
because in declaring tv as TV, you are saying it might not be an HD TV. Even though you can see that in this case it is, the compiler still respects your declaration that it is just a TV and you can only use methods supported for a TV.
That is because you are declaring the instance a1 as an A. Because B inherits A, you can call all the functions declared in A and they might have a different meaning if they are overloaded in B, but you do not have any access to B-only things.
You can see the first A as some kind of a header file, if you are familiar with that. It declares what A contains, without looking at how the functions are implemented or what the default vars are of everything in A. As a direct consequence, you can only access everything that is declared to literally be in A.
The left-hand side - A in this case - is the declared type, and it doesn't know about anything specific to child classes. The right-hand side - ´B´ in this case - is the actual type, and this provides the behaviour.
So, this will work because the declared type B knows about methods available in the class B.
B b1 = new B();
b1.test2();
If it was possible to have a1.test2(), that would mean every class would have to know about every child it has - including those in other libraries, when projects are assembled!
When B inherits A class and the reference of A is created with object of B like A a1 = new B();.
On Compile time java compiler looks for method availability in class A.
So it allows calling method test() but not the test2().
As test() method is available in class A but test2() is not available in class A.
You can type cast the object created like ((B)a1).test2().
This will work.
Here a1 object is of type A. a1 is pointing to an object of type B.
a1 is a reference of type A to an object of type B.
since a1 is of type A it know only test() which is declared in its class definition already. In case you want to access test2 declared in class B you need to type cast the a1 object back to B
like
B b1 = (B)a1
b1.test2() will be accessible.
This happens because you declare A variable and use B class which is an A. The compiler know it's an A but doesn't know it's a B later in the code. It's easier to use real life objects as example.
For example you have:
class Pet() {
method feed();
}
And a
class Dog() extends Pet {
method feed();
method bark()
}
If you have a code in another class:
So if you have code :
Pet dogPet=new Dog();
You know it's a dog here because you create the instance and you can use:
((Dog)dogPet).bark(); or just declare the variable as a dog instead of pet.
But if you have a method in another class:
void someMethod(Pet aPet){
// Here you don't know if the Pet is a dog or not. So you know only that it
//can be fed but you don't know if it barks. Even if a Dog is supplied to the method
}
In a1 = new B(), the actual type of the object created is B but you reference it as its supertype so you can call a method that accepts A (polymorphism).
So if a method is overridden in subclass, a1.test() is executing subclass's test().
In order to execute test2() you have to do that: ((B) a1).test2();
There is a concept called Up casting and Down casting.Up-casting is casting to a supertype, while downcasting is casting to a subtype. Supercasting is always allowed, but subcasting involves a type check and can throw a ClassCastException.,See the Example Code:
class A{
public int test(){
return 1;
}
}
class B extends A{
public int test(){
return 2;
}
public int test2(){
return 3;
}
}
and
A a1 = new B();
a1.test2();//not possible
Here you can't invoke methods of class B.
class A{
int a=10;
public void show(){
System.out.println("Show A: "+a);
}
}
class B extends A{
public int b=20;
public void show(){
System.out.println("Show B: "+b);
}
}
public class DynamicMethodDispatch {
public static void main(String[] args) {
A aObj = new A();
aObj.show(); //output - 10
B bObj = new B();
bObj.show(); //output - 20
aObj = bObj; //assigning the B obj to A..
aObj.show(); //output - 20
aObj = new B();
aObj.show(); //output - 20
System.out.println(bObj.b); //output - 20
//System.out.println(aObj.b); //It is giving error
}
}
In the above program i'm getting Error wen i try invoking aObj.b.
1.why i'm not able to acess that variable through the aObj though it is refering to class B??
2. why i'm able to acess the method show()?
You have to distinguish between the static type of aObj and the runtime type of aObj.
Code such as
A aObj = new B();
results in an aObj variable with static type A and runtime type B.
The compiler will only bother too look at the static type when deciding what to allow or not.
To your questions:
1.why i'm not able to acess that variable through the aObj though it is refering to class B??
Because there is (in general) no way for the compiler to know that aObj will refer to a B object at runtime, only that it will refer to some form of A object. Since .b is not available on all A objects, so the compiler will think "better safe than sorry" and disallow it.
2.why i'm able to acess the method show()?
Because this method is available in all A objects (if it's not declared in the subclass, it is still inherited from A).
aObj is a local variable of type A. A has no member called b, that's only in your subclass B. If you want to use b, you need to declare a variable of type B, but of course you can only assign it instances of B (or subclasses if there are any).
A declares a method show(), but you override the implementation in your subclass B.
This behavior is known as virtual method invocation, and it is an important aspect of polymorphism in Java. You should have a look at this tutorial.
class A{ // class A has variable a and method show();
int a=10;
public void show(){
System.out.println("Show A: "+a);
}
}
class B extends A{ //class B inherits variables and methods of A.
// so class B has variable a, b and show(). Also, show is overridden by class B.
public int b=20;
public void show(){
System.out.println("Show B: "+b);
}
}
since A doesn't have variable b inside it, even when u are passing B to A, you still have A object which does not have variable b inside it. So, trying to access b will give you compile time error.
in case of show(), A and B both have this method, so what you are doing here is actually overriding it at runtime. This is nothing but Polymorphism. So since A already has method show(), and it is overridden later by B,
A a = new B();
a.show();
this will run the show() method of B at runtime.
Methods and fields have different polymorphic behaviour.
The method that will be called is the method of the run time type of the instance
aObj=new B(); //new B()
The field that will be called is the field of the type of reference that you declared
A aObj = new A(); // A aObj
The following would work even is there was no show() method in A.
aObj = new B();
aObj.show(); //calls B's show()