If there's 3 classes. A, B and C. class B extends A and class C extends B.
class A has equals method:
public boolean equals(A other)
{...}
class B has equals method:
public boolean equals(B other)
{...}
and class C has euals method:
public boolean equals(Object other)
{...}
And the main has these code lines:
A a = new A();
C c = new C();
a=c;
System.out.println(a.equals(c));
I can't understand why the equals method of class A is being executed.
I know that overloaded methods are bonded using static binding. But a points to the "C part of the object" after aliasing and there's the method equals of class C. Why isn't it the equals method of class C that will execute?
A method in a subclass overrides a method in the superclass only if the parameters have the same types.
The Object class defines an equals() method:
class Object {
public boolean equals(Object obj) {...}
}
When you define class A, it inherits the equals routine from Object. You define a new equals, but the parameter type is different, so it doesn't override the one in Object; instead, it becomes an overload. The result is that A has two overloaded equals methods:
class A {
public boolean equals(Object obj) {...} // inherited
public boolean equals(A other) {...} // the one you wrote
}
Similarly, the equals in B won't override either equals, so the result is three overloaded equals methods:
class B {
public boolean equals(Object obj) {...} // inherited from Object
public boolean equals(A other) {...} // inherited from A
public boolean equals(B other) {...} // doesn't override anything
}
In class C, the new equals method does override the one in Object, so there are still three equals methods:
class C {
public boolean equals(Object other) {...} // overrides the one in Object
public boolean equals(A other) {...} // inherited from A
public boolean equals(B other) {...} // inherited from B
}
Now, here's your code:
A a = new A();
C c = new C();
a=c;
System.out.println(a.equals(c));
When you say a.equals(c), the compiler sees that a has type A. Therefore it looks at the methods in A to see which one to execute. (The compiler doesn't know that a will have type C at run time; therefore, it won't look at the methods in C.)
There are two methods to choose from, as shown above:
public boolean equals(Object obj) {...} // inherited
public boolean equals(A other) {...} // the one you wrote
Both of them could be used on the parameter c, since c is an Object and it is an A. In that case, when one parameter is a subclass of the other, the compiler chooses the "closest" one, in essence. C is only two subclasses away from A, and it's three subclasses away from Object, so it chooses the overload with parameter A, which is the one you defined in A. And note that this equals method was never overridden. So it executes the code that you wrote in class A.
But suppose you had written:
System.out.println(a.equals((Object)c));
By casting c to an Object, you're forcing the compiler to look at it as an Object. Now when it chooses between the overloads, it must choose the one with the Object parameter, because an Object cannot automatically be converted to an A (because not every Object is an A). Thus, it would choose the inherited method. And since, at run time, the object actually is of class C, and since class C has an equals method that overrides the one in Object, in this case it would execute the code written in class C.
Your code is a nice example for demonstrating how overloading and overriding work. In real life, however, it's a bad idea to write an equals() method whose parameter is anything other than Object, because it won't override and it could lead to confusion. Also, it's a good practice to put #Override on any method that you think will override a method in a superclass. That way, if you goof and use the wrong parameters, the compiler will catch it before you get a run-time bug that could be very difficult to track down.
Short answer
Your method in child class gets overridden only when it have same method signature as that of parent class. Otherwise it doesn't.
Consider these two examples
Example 1
class A {
public boolean equals(A Other) {
System.out.println("A's method");
return true;
}
}
class C extends A {
public boolean equals(Object Other) {
System.out.println("C's method");
return true;
}
}
public class Driver {
public static void main(String[] args) {
A a = new C();
a.equals(null);
}
}
Output 1
A's method
Example 2
class A {
public boolean equals(A Other) {
System.out.println("A's method");
return true;
}
}
class C extends A {
public boolean equals(A Other) {
System.out.println("C's method");
return true;
}
}
public class Driver {
public static void main(String[] args) {
A a = new C();
a.equals(null);
}
}
Output 2
C's method
In example #1, you have changed the method signature when equals() method is defined in child class and so it doesn't qualify for method overriding. And so when calling this method from Driver class, parent's gets called.
whereas in example #2, the method signature in both parent and child are exactly the same and so method overriding takes place here and thus you get output that you were expecting in your question.
In Simple words, java handles aliasing during runtime. as overloaded method use static binding(compile time), it is calling A's equals method.
if you override equals method in class A.
#Override
public boolean equals(Object o){ ...}
it will be overridden method which uses dynamic binding(runtime) and C's equals method will be called.
Related
I need to achieve this result:
public class question{
public static void main(String[]arg){
A a1=new A();
A a2=new A(2);
assert a2.equals(a1);
}
}
So I have tried:
class A{
A(){
return;
}
A(int x){
return;
}
}
public class d22 {
public static void main(String[]arg){
A a1=new A();
A a2=new A(2);
assert a2.equals(a1);
}
}
But obviously it's not working, is there any way to achieve the code upper? Thx.
There's nothing particularly magical about equals - it's a plain jane method defined in java.lang.Object.
You can override it.
This weird idea would work:
class A {
#Override public boolean equals(Object other) {
return other instanceof A;
}
}
would mean any A is equal to any other.
actually,the java object which is created by the key word new is allocated in the heap.So the result is false if you want compare a1 with a2,because the default equals method is to compare the object memory address.If you want compare two object ,you should rewrite the equals method to achieve your goal.
All classes in Java extends default Object class which contains method's equals() and toString(). Equals() method is used to compare instance of that particular class against another variable. You can override this method to define how equals should behave.
class A {
#Override
public boolean equals(Object other) {
if (!other instance of A) return false; // other is not same type as this class
if (other == this) return true; // both variables point to same object
return true; // you can compare other class attributes here
}
}
By default equals will return true if you are comparing two variables that point to same object. That means in your case that you obtain false when calling equals since your two variables point to different object created by new operator and you have not overriden equals() method to get different behavior than default one.
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.
Why should a super method hand out it's this reference as super type instead of own type?
I don't understand the practicality of this behavior. I learned to code against Types/Interfaces and not against classes, but considering this kind of behavior I'm confused about everything I thought OOP was standing for. This breaks possibility of clean code and forces me to fill it with verbose control flow like heavy use of the instanceof operator. Why does that kind of behavior make even sense?
Abstract:
Consider this code:
abstract class A {
public void visit(Target t) {
t.method(this);
}
}
If Target overloads method() with A and different child classes of A in it's signature and these children don't override visit(Target t) themselves then overloaded method(A a) will be choosen by compiler always.
Working example:
http://pastebin.com/EGNpY7pF
Code Snip
public class Target {
public static abstract class A {
void visit(Target t) {
t.method(this);
}
}
public static class B extends A {}
public static class C extends A {
#Override
void visit(Target t) {
t.method(this);
}
}
void method(A a) { System.out.println("A");}
void method(B b) { System.out.println("B");}
void method(C c) { System.out.println("C");}
public static void main(String[] args) {
Target t = new Target();
A ab = new B();
B b = new B();
A ac = new C();
C c = new C();
ab.visit(t);
b.visit(t);
ac.visit(t);
c.visit(t);
}
}
Output
A A C C
Which is really akward since ac is referenced to as A-Type but still C's overriden visit() method is called.
Your question is unclear. When a function is called on an instance of an object the child's method will be called, even if it is referenced as its parent's type; polymorphism. If the child does not override the method then the parent class' implementation of the method will be called; inheritance from hierarchy.
If a class calls its own method prefixing it with super it will find the nearest implementation up the hierarchy which matches the signature.
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.
Hi I am facing a design problem which I think it should be quite common:
public abstract class Parent
{
...
public boolean itsOk()
{
return true;
}
public void execute()
{
if (itsOk()){
System.out.println("done");
}
}
}
I need to be able to override itsOK() function in any subclass inherited from 'Parent' even if arguments are different.
public class Example extends Parent
{
public boolean itsOK(int a)
{
if (a==1) return true;
else return false;
}
}
Then when I call execute, I want the subclass' itsOk() method to be invoked.
public static void main(String[] args) {
Example e=new Example();
e.execute();
}
This works ok if the subclass' itsOk() method has no arguments (like the 'Parent's method), so it's an overriding case, but how can I make it when arguments are different?
Call super.itsOk(); in your subclass' itsOk method.
That is, I'm assuming what you mean is you want to have an overload of itsOk defined in your subclass which does something new but also invokes the parent class' default implementation of itsOk.
As an aside, note the terminology: you're not overriding: to do that, the itsOk in your subclass must have the same method signature as in the parent class. Instead you're overloading creating a brand new method that just happens to have the same name.
You can use generics:
public abstract class Parent
{
...
public <T> boolean itsOk(T t)
{
return true;
}
public void execute()
{
if (itsOk()){
System.out.println("done");
}
}
}
public class Example extends Parent<Integer>
{
public boolean itsOK(Integer a)
{
if (a==1) return true;
else return false;
}
}
In such a case I would rather try to have the same method signature in the parent and the child class, ie. a real overwriting and not an overloading. Then, your parameter a could be a member of the class Example which would avoid the need for a parameter. Of course it strongly depends on the rest of the code.
The itsOk(int a) method in class Example is not overriding the itsOk() method in class Parent - it is an entirely separate method that doesn't have anything to do with the method in class Parent.
With what value of a do you want itsOk(int a) in Example to be called when you call itsOk() in Parent?
You could ofcourse add an itsOk(int a) method to class Parent; then the version in Example would be overriding that version, and in the execute() method you could call it:
public abstract class Parent {
public boolean itsOk() {
return true;
}
public abstract boolean itsOk(int a);
public void execute() {
if (itsOk(0)) {
System.out.println("done");
}
}
}
Without declaring an itsOk(int a) method in class Parent, you cannot call that method on a Parent object (or on an Example object, if the type of the variable referring to the object is Parent).
I don't think this is a common design problem.
When arguments are different it no longer is a case of Overriding. It is called Overloading which basically means that you have two distinct methods to call.