Lets say I have two classes A and B . B inherits from A and B has the following methods:
public boolean equals(Object other) {
System.out.print("Object");
return true;
}
public boolean equals(A other){
System.out.print("A object");
return true;
}
public boolean equals(B other) {
System.out.print("B object");
return true;
}
A a1 = new A();
A ab = new B();
B b1 = new B();
what is unclear to me is why
ab.equals(a1)
ab.equals(b1)
Returns Object
ab is an instance of B with pointer of A. a1 is clearly both instance and pointer of A. So Why does it use the Object other instead of A other method?? same goes for b1 which is an instance of B with pointe B yet the compiler chose to apply the equals method like I inserted regular object?? AM i that stupid or is this language incoherent?
BTW A doesn't have any equals methods at all.
Explanation
BTW A doesn't have any equals methods at all.
But you do
ab.equals(a1)
ab.equals(b1)
And ab is:
A ab = new B();
So while it is actually a B, the variable is of type A.
Javas rules for choosing methods in such situations will start looking for an equals method in the A class. And it actually has one, the default implementation inherited from Object. It has the signature
public boolean equals(Object other)
So it decides for this signature. Now it asks the actual instance behind ab, which is of type B, for a method with that signature. It chooses the overriden implementation in B:
public boolean equals(Object other) {
System.out.print("Object");
}
And consequentially prints Object in both cases.
Details
The details for this are defined in JLS§15.12. Method Invocation Expressions. It talks about finding the most specific match. The rules can get quite complex if you dive deep into it.
Some excerpts:
The first step in processing a method invocation at compile time is to figure out the name of the method to be invoked and which class or interface to search for definitions of methods of that name.
The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expressions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.
There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.
The class or interface determined by compile-time step 1 (§15.12.1) is searched for all member methods that are potentially applicable to this method invocation; members inherited from superclasses and superinterfaces are included in this search.
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
The setup
Given a class A and a class B extends A, overriding and overloading equals(...) with different parameter types as follows:
class A {}
class B extends A {
public boolean equals(Object other) {
System.out.println("Object");
return true;
}
public boolean equals(A other) {
System.out.println("A object");
return true;
}
public boolean equals(B other) {
System.out.println("B object");
return true;
}
}
The question
Given the following code
A a1 = new A();
A ab = new B();
B b1 = new B();
ab.equals(a1);
ab.equals(b1);
Why is "Object" printed out for both calls?
The explanation
The signature of method called is determined through the static type of the receiver and the static type of the parameters (as described in JLS, §15.12.3). Furthermore, through dynamic dispatch, a child-class override of a method may be executed.
If we analyze the type of ab (the receiver of the call), we find it to be A. There is only one method called equals(...) wihtin A, which is equals(Object) (inherites from Object). the parameters (a1 and b1 respectively) are assignable to Object, so this method is called.
Through dynamic dispatch, equals(Object) in B is actually executed and "Object" is printed out for both calls.
A full example is available on Ideone
Related
To clarify- To my understanding, the methods below are all override of Object.equals. Are they overloading instead and I am not understanding this correctly?
I'm running this code:
public class AA
{
private int _val=0;
public AA()
{
_val=5;
}
}
public class BB extends AA
{
public BB()
{
....
}
public boolean equals(BB ob)
{
return false;
}
public boolean equals(Object ob)
{
return true;
}
public boolean equals(AA ob)
{
return true;
}
public static void main(String args[])
{
AA a2=new BB();
BB b1=new BB();
if((a2.equals(b1)))
System.out.println("hi");
}
}
Class AA does not have an equalsmethod
I'm trying to figure out with the second method is triggered and not the first one. My understanding is:
Since class AA does not have an equals method, I suppose that at
compile-time the compiler wants to run the equals from Object
class.
At run time the compiler finds out that a2 is actually a BB object
and therefore has equals methods that override the method from
Object.
However, what is not clear to me is why the second method (Object ob) is chosen instead of the first (BB ob), if the sent object is defined and actually is a BB object.
Would appreciate your feedback!
When you call a.equals(b), the compiler looks at the equals methods in AA. If it found an appropriate one there, it would use it. In this case, AA has no methods called 'equals'. So it steps up the inheritance chain, and looks again. This time, it is looking at Object, and it finds Object.equals(Object). At runtime, it finds the most overridden version and calls it.
So if it's still just looking for a method called 'equals', why doesn't it find the more specific version equals(BB) at runtime?
BB.equals(BB) is not considered an override of Object.equals(Object). It has a more specific parameter, and can't handle a plain Object. Imagine the types are part of the name:
equals_Object
equals_BB
The compiler picked the equals_Object method, so at runtime the JVM will not find the equals_BB method, because it isn't looking for it.
Overloads are not chosen at runtime, they're chosen at compile time, when the compiler only knows that the object is an AA. Only overrides are chosen at runtime, based on the actual runtime type of the object, but the overload selected at compile time is still used.
I've tried to execute the following code:
abstract class A {
int met(A a) { return 0;}
int met(B b) { return 1;}
int met(C c) { return 2;}
}
class B extends A {
int met(A a) { return 3;}
int met(B b) { return 4;}
int met(C c) { return 5;}
}
class C extends B {
int fun() {
return ((A) this).met((A) this);
}
}
class Test {
public static void main(String[] args) {
C x = new C();
System.out.println(x.fun());
}
}
And the output is "3".
Can someone explain in more detail the theoretical concept behind this result.
I know that class A is abstract and that's why it cannot be instantiated but I'd like to understand the whole mechanism of this result.
The overloaded method is selected at compile time. Since your code calls met((A) this), the method signature with the argument of type A is chosen.
Now, at run time, the JVM has to decide which met(A a) method to execute. This is determined by the runtime type of the object for which the method is called. Since your object is of type C which extends B, met(A a) of B (which overrides met(A a) of A) is executed.
Method signatures are determined at compile time.
.met(A)
must be called as the signature doesn't change based on the actual type of the object, only the type is appears to be.
However, polymorphism does apply to determine which implementation of this signature is called.
The object this is a C which extends B and so the implementation in B is the one called.
This is why B.met(A) is called.
B is the only class implementing A so A implementations will never be executed as B as overrided them.
When you cast your C object as A, it's still a C object so calling met on this object will execute the method of B. This call is resolved at runtime using the real type of the object.
Concerning the parameter, you casted it as a A so the java compiler made it point to the right method : B.met(A)
return ((A) this).met((A) this);
When you write this it's always points to current instance which is C which extends B, and you didn't over-ridden the method hence it's pointing to the method of super class (B).
And coming to the part (A) this, it still points to this only, not the A. The underlying implementation of methods still remains same. You are just changing type.
((A) this).met((A) this) interpreted as
- instanceOfC.met(typeOfA)
so two questions arise, why is
class selected as B not A - subclass over super class
within class B met is selected as met(A) not met(C) or met(B) - type over instance
A. Overriding - subclass over super class
if same method signature in the object's sub-class and super-class,
then it was selected it from sub-class.
so ((A) this).met resolver to instanceOfC.met
B. Overloading - type over instance
if duplicate method name found in the class
then selected was one with same parameter as the argument passed,
hence met ((A) instanceOfC) interpreted as met(typeOfArgument)
so
this.met((A) null) will also invoke B.met(A)
this.met(this) will invoke B.met(C)
if we remove B.met(C), this.met(this) will invoke A.met(C), i.e. overriding doesnt happen.
and then removing A.met(C), it will invoke B.met(B), - overloading by closest typecast-able parameter.
If I have two classes, A and B,
public class A {
public int test() {
return 1;
}
}
public class B extends A{
public int test() {
return 2;
}
}
If I do: A a1 = new B(), then a1.test() returns 2 instead of 1 as desired.
Is this just a quirk of Java, or is there some reason for this behavior?
This is called polymorphism. At runtime the correct method will be called according to the "real" type of a1, which is B in this case.
As wikipedia puts it nicely:
The primary usage of polymorphism in industry (object-oriented
programming theory) is the ability of objects belonging to different
types to respond to method, field, or property calls of the same name,
each one according to an appropriate type-specific behavior. The
programmer (and the program) does not have to know the exact type of
the object in advance, and so the exact behavior is determined at
run-time (this is called late binding or dynamic binding).
No, that is correct (it is due to polymorphism). All method calls operate on object, not reference type.
Here your object is of type B, so test method of class B will be called.
This is polymorphism and more specifically in Java overriding. If you want to invoke Class A's test method from Class B then you need to use super to invoke the super classes method. e.g:
public class B extends A{
public int test() {
return super.test();
}
This is intended behavior. The method test() in class B is overriding the method test() of class A.
For
A a1 = new B();
a1 is pointing towards the object of B which is the real type at run-time. Hence value is printed from Object B.
A obj = new A();
obj.test()
will return 1
A obj = new B();
obj.test()
will return 2
B obj = new B();
obj.test()
will return 2
As stated in other answers this is how polymorphism works.
This post may make things a bit clearer
Java uses dynamic binding (or late binding), so the method of B is called, not A. This is the opposite of static binding. There is a nice example here.
You declare your object as A but your instance is B. So the method which will be called is from class B. B extends A(we can say that A is parent for B) if you will comment method test in B and then recall this method, in this case the method invoked will be test from A class and will return 1.
I've been studying because I have an exam and I don't have many problems with most of Java but I stumbled upon a rule I can't explain. Here's a code fragment:
public class A {
public int method(Object o) {
return 1;
}
public int method(A a) {
return 2;
}
}
public class AX extends A {
public int method(A a) {
return 3;
}
public int method(AX ax) {
return 4;
}
}
public static void main(String[] args) {
Object o = new A();
A a1 = new A();
A a2 = new AX();
AX ax = new AX();
System.out.println(a1.method(o));
System.out.println(a2.method(a1));
System.out.println(a2.method(o));
System.out.println(a2.method(ax));
}
This returns:
1
3
1
3
While I would expect it to return:
1
3
1
4
Why is it that the type of a2 determines which method is called in AX?
I've been reading on overloading rules and inheritance but this seems obscure enough that I haven't been able to find the exact rule. Any help would be greatly appreciated.
The behavior of these method calls is dictated and described by the Java Language Specification (reference section 8.4.9).
When a method is invoked (§15.12), the number of actual arguments (and
any explicit type arguments) and the compile-time types of the
arguments are used, at compile time, to determine the signature of the
method that will be invoked (§15.12.2). If the method that is to be
invoked is an instance method, the actual method to be invoked will be
determined at run time, using dynamic method lookup (§15.12.4).
In your example, the Java compiler determines the closest match on the compile type of the instance you are invoking your method on. In this case:
A.method(AX)
The closest method is from type A, with signature A.method(A). At runtime, dynamic dispatch is performed on the actual type of A (which is an instance of AX), and hence this is the method that is actually called:
AX.method(A)
I will clarified it in more simple way. See when you making sub class object with super class reference like here you did.
Always one thing keep in your mind that when you call with super class reference, no matters object is of sub class it will go to the super class, check method with this name along with proper signature is there or not.
now if it will find it, than it will check whether it is overridden?? if yes than it will go to the sub class method like here it went. another wise it will execute the same super class method.
I can give you the example of it...just hide
public int method(A a) {
return 3;
}
method & check your answer you will get 1 2 1 2, why because it gives first priority to reference. because you overridden it & than calling it, so its giving 3..!! hope its big but easy to understand. Happy Learning
a2 referenced as an A and the JVM using the reference first (not the acutal object as you expected).
I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.