Suppose I have the following classes
class A{
public method(A a) {
System.out.println(3);
}
}
class B extends A{
public void method (A a) {
System.out.println(2);
}
public void method (B b) {
System.out.println(1);
}
}
A obj = new B();
obj.method( (B) obj);
((B) obj).method( (B) obj);
The first method call prints out 2 while the second method call prints out 1. Why don't both method calls print out 1?
void method (B b) of B is totally unknown for its parent A.
It's logical, because in obj.method((B) obj);, the type of obj is A which in polymorphism rule it can just call void method(A a) version of class B.
class B extends A {
// This is an overridden method visible to A
public void method(A a) {
System.out.println(2);
}
// This is an overloaded method unknown from A
public void method(B b) {
System.out.println(1);
}
}
You can read this SO answer which explained Override vs. Overload.
Because java selects the method to call in compile time. And the compiler only take into account the "left side" of an assignment.
So when you type A obj = new B() the compiler only "sees" the methods in class A.
The first method call is done using object reference of type A, so the corresponding method, which could be overridden, is called.
In the second case first the cast is done to type B, so corresponding method defined in class B ,i.e,
method (B b)
is called.
Related
We expect "ACBD" for output with that code but we get "ACBB". Why?
class A{
public void f(Object o){
System.out.println("A");
}
}
class B{
public void f(String s){
System.out.println("B");
}
}
class C extends A{
public void f(String s){
System.out.println("C");
}
}
class D extends B{
public void f(Object o){
System.out.println("D");
}
}
public class JavaApplication40 {
public static void main(String[] args) {
A a=new C(); a.f("mee");
C c=new C(); c.f("mee");
B b=new D(); b.f("mee");
D d=new D(); d.f("mee");
}
}
I think a must call f of class A, c must call f of class C, b must call f from class B, d must call f from class D. But it looks like that it's change wit argument of function. Why?
In Java the method's identity is tied not only to its name but also to its set of parameters. That is,
public void f(Object o)
and
public void f(String s)
are separate methods in D. Java determines which one to execute at runtime, based on the type of parameter you give it. You're not actually overriding any methods in this example, just adding new ones with similar names but different parameter sets.
Note that, in all your test cases, Java chooses the object that's closest to String. If a version of the method takes a String and another version takes an Object, then the more specific String will win out.
If you instead call d.f(a), or with any other object that isn't a string, then you should see it print "D". Similarly, if you call b.f(a) with any argument that isn't a string, it should print "A".
Since class D extends class A, and you are passing String as the parameter, it will take the method with the parameter that matches your input in d.f("mee") - namely public void f(String s).
On the other hand, if in class 'D' function wasn't public void f(Object o), but public void f(String s), you would have gotten "D" as output in the log.
There is a difference between overloading and overriding. In your code you use overloading methods (creating methods with the same name but different parameter types). Overloading is resolved by compiler at compile time (unlike overriding, which is resolved at runtime).
For a, compiler sees that its type is A, so it chooses A method.
For c, compiler sees that its types is C, so it chooses the method with the most specific signature, which is C method (String is more specific than Object).
For b, compiler sees that its type is B, so it chooses B method.
For d, compiler sees that its type is D, so it chooses the method with the most specific signature, which is B method (String is more specific than Object).
Your parameter, "mee" is closest to String than to Object and therefore,
public void f(String s){
System.out.println("B");
}
is chosen over
public void f(Object o){
System.out.println("D");
}
If you are expecting ACBB, you need to define D as
class D extends B{
public void f(String s){
System.out.println("D");
}
I have a class named A, and a class named B that extends A.
Playing with some methods to understand polymorphic behaviour, I ran into a weird situation.
public class Main {
public static void main(String[] args){
B b = new B();
A a = b;
b.f1(a);
}
}
public class A {
.
.
.
public void f1(A a){
if(a instanceof B)
f1((B)a);
else
System.out.println("Nothing");
}
.
.
.
}
public class B extends A {
.
.
.
public void f1(B b){
System.out.println("B::f1(B)");
}
.
.
.
}
I expected f1 in class A to be called first(because a is of type A) which actually happened. Then I expected the line f1((B)a); to be called, since a is an instance of B. Until now everything went as expected. However, I thought that the next method that will be called is f1(B) in class B. Instead, f1(A) in class A was called over and over causing a stack overflow exception. Why wasn't the f1(B) in class B called? An instance of B was the caller and the parameter was cast to type B.
f1(A a) is an instance method of class A. It has no knowledge of methods of sub-classes of A. Therefore, it cannot call void f1(B b) of class B. Therefore, f1((B)a) executes void f1(A a) again.
If you want to call f1(B b), you'll have to call f1 on an instance variable of class B:
public void f1(A a){
if(a instanceof B) {
B b = (B)a;
b.f1(b);
} else {
System.out.println("Nothing");
}
}
Your class A has no any idea that class B exists somewhere and has B.f1(B b) function. Actually f1(A a) and f1(B b) are two different functions. what you want probably to achieve, should be done in bit different way:
public class A {
//...
public void f1(A a) {
System.out.println("Nothing");
}
//...
}
public class B {
//...
public void f1(B a) {
// this is different function, because of another parameters
}
public void f1(A a) {
if(a instanceof B)
f1((B)a);
else
super.f1(a);
}
//...
}
The code must cast the caller of the method as follow:
public class A {
public void f1(A a){
if(a instanceof B)
((B) this).f1(a);
else
System.out.println("Nothing");
}
}
In your code instead you are casting only the parameter. Doing that result in a call on the same method of the same class recursively.
If you cast the caller instead you inform the JVM that you like to call the method on the subclass, so you can exit from the method immediately.
Important Note that invoking a cast on the caller depending on the parameter can generate a class cast exception, for example in the following context:
B b = new B();
A a = new A();
a.f1(b);
You can't be sure that the method f1 receiving a B parameter is called on B object.
why it is printing Integer?
At the time of compilation, the method call bound to class A's method.
I hope in B I am not overriding. creating a other method means method overloading with different classes.
but what is happening at run time?
class A{
void method(Integer i)
{
System.out.println("Integer");
}
}
class B extends A
{
void method(int i)
{
System.out.println("Int");
}
}
public class Puzzle{
public static void main(String ar[]){
A a = new B();
a.method(20);
}
}
B has two different methods called method: one declared by A, which is method(Integer), and one declared by B, which is method(int).
Since your variable a is of type A, a call to a.method() must refer to a method provided by class A, which is method(Integer).
Your methods don't share the same signature.
void method(int i) is not equal to void method(Integer i) - the first one uses primitive type. Second one uses Object Integer.
If you change method in A to method(int i) you can then override the method of A, so in your subclass:
#Override
void method(int i)
{
System.out.println("Int");
}
B doesn't override the method called "method" because it is not the same type of parameter of your method in A (Integer).
int is a primitive type while Integer is a class.
B method should be :
#Override
void method(Integer i)
{
System.out.println("Int");
}
The annotation #Override is here to tell the class should override a method. It is a good practice but not necessary (I would work without it). If you put it with your current code you would have an error because method doesn't override any method.
I hope it will help you.
This is exactly what #Override annotation is for - add #Override when you think you're overriding and the compiler will tell you if you're wrong in thinking so.
If you add #Override to the B's method(int i), the compiler will give you an error telling you that you're not in fact overriding it, because the signatures differ - namely the method has different parameter type that's not a superclass of parent's parameter type.
The signatures of the method of A and that of B are not the same. The method in A takes an object integer (Integer) as parameter while that of B takes a primitive integer (int) as parameter. So you are not really overriding the method of A in B. To do so, change the signature of the method B to be like that of A.
class A{
void method(Integer i){
System.out.println("Integer");
}
}
class B extends A{
#Override
void method(Integer i){
System.out.println("Int");
}
}
public class Puzzle{
public static void main(String[] args){
A a = new B();
a.method(20);
}
}
Your reference is of type A - it does not recognize methods declared in type B in compile time, even though the may exist in runtime. The int literal 20 is then autoboxed to a java.lang.Integer, and method(Integer) is called.
If you were to declare the reference as B, the method(int) would be a better fit to your argument, and would be have been called.
Having trouble understanding why the output is "3" and "4" for the two function calls. For,
g2.foo( t1 );
At compile time, g2 is type A, it looks for foo(type C), which it doesn't find in its main class, so it looks at its children class B, then C. So foo(...) should be bind to
public void foo(C p) {
System.out.println("5");
}
is subclass C right?
Then during run time g2 will be type C and calls foo(C p) which will result in an output of "5". I am not sure where my logic/understanding of polymorphism is wrong.
class A {
public void foo(A p) {
System.out.println("1");
}
}
class B extends A {
public void foo(B p) {
System.out.println("2");
}
}
class C extends B {
public void foo(A p) {
System.out.println("3");
}
public void foo(B p) {
System.out.println("4");
}
public void foo(C p) {
System.out.println("5");
}
}
public class HelloWorld {
public static void main(String[] args) {
A g2 = new C();
B r2 = new C();
C t1 = new C();
g2.foo(t1); // 3
r2.foo(new C()); // 4
}
}
The main thing to remember is that the overloaded method is chosen at compile time based on the compile time type of the instance for which the method is called. The run time type only determines if the chosen method is overridden by an implementation of the run time type.
g2.foo( t1 )
g2 has a compile type A, which means only public void foo(A p) can be chosen at compile time. At run time g2 in an instance of C, which means public void foo(A p) of C is called, which prints 3.
r2.foo( new C() )
r2 has a compile type B, so either public void foo(A p) or public void foo(B p) can be chosen at compile time. public void foo(B p) is the best overloaded match (since B is more specific than A). In run time, r2 is an instance of C, so public void foo(B p) of C is called, and prints 4.
Whenever a function is overridden, the virtual table (v-table) of the derived class has that function mapped with its implementation. So the function call would call the implementation as given by the v-table of that particular class.
In your case, A g2 = new C(); creates the instance of C and hence the v-table would have the foo function mapped with its (C's) implementation.
Now, when the function call happens i.e. on g2.foo(t1), the implementation of the class C will be called as it had it mapped and hence 3 is printed.
At compile time, g2 is type A, it looks for foo(type C), which it doesn't find in its main class, so it looks at its children class B, then C. So foo(...) should be bind to ...
This understanding of yours is wrong.
During compile time, since there's not foo(C) in type A, it marks that the method foo(A) will be called (Since A is a supertype of C and it's the most specific method which matches).
During runtime, C's implementation of the specific method (foo(A)) is called and prints 3. Similar for the next call too.
When u call g2.foo(t1)
g2 gets the Compile type Object of A which means that that method of A ie
public void foo(A p)
but at the runtime g2 is an Object of C Class so public void foo(A p) is called
Why overloading is not happening here even though passing integer argument to method "p" . ?
public class Test {
public static void main(String[] args) {
B a = new A();
a.p(10);
a.p(10.0);
}
}
class B {
public void p(double i) {
System.out.println(i * 2);
}
}
class A extends B {
// This method the method in B
public void p( int i) {
System.out.println(i);
}
//added below code
public void p( double i) {
System.out.println(i*5);
}
}
Output:50.0
50.0
Because the variable a is declared as B, only the p method declared in B is visible and thus chosen. There's no overriding involved.
When in doubt, annotate your method with #Override in your favorite IDE. The IDE won't let it compile if it's not actually overriding anything.
After your edit, you now have an overriden method in the form of A#p(double). When you invoke
a.p(10);
a.p(10.0);
The method p visible on the B class will be invoked. Through polymorphism and because the variable a is of run time type A, the overriden method declared in A will be invoked.
Note that the int argument in
a.p(10);
becomes a double through widening primitive conversion.
Because you're invoking things through a reference-to-a-B. That only has one method.
It's always calling the method in B, because:
the variable is of type B, so the compiler only knows about the double method
the method in A does not override B's method because the parameter type int is different from B's double - it's invisible to the calling code