How Java Picks an Overloaded Method in Polymorphism - java

I have two classes defined as:
public static class Mammal extends Animal {
public void info(String s) {
System.out.print("Mammal");
}
}
public static class Animal {
public void info(Object o) {
System.out.print("Animal");
}
}
Now I define two variables as:
Mammal m = new Mammal();
Animal a = new Mammal();
When I call m.info("test"), it will print
"Mammal"
When I call a.info("test"), it will print
"Animal"
Why does the Mammal type call the Mammal info() method and the Animal type call the Animal info() method when they are both Mammal objects?

You're overloading the method, not overriding it.
Overloads are chosen at compile time, and when the compile-time type of a is Animal, then a call to a.info("test") can only resolve to the info(Object) method in Animal.
If you want to override the method, you need to use the same signature - specify the #Override annotation to get the compiler to check that for you:
public static class Mammal extends Animal {
#Override public void info(Object s) {
System.out.print("Mammal");
}
}
Now it will print "Mammal" in both cases, because the implementation of the method is chosen at execution-time based on the actual type of the object. Remember the difference between them:
Overloading: takes place at compile time, chooses the method signature
Overriding: takes place at execution time, chooses the implementation of that signature
I also note that you're using nested classes (as otherwise the static modifier would be invalid). That doesn't change the behaviour here, but it does make other changes to the features of classes. I strongly suggest that you try to work with top-level classes most of the time, only using nested types when there's a really compelling reason to do so.

Because
public void info(Object o) {
System.out.print("Animal");
}
doesn't overrode
public void info(String s) {
System.out.print("Mammal");
}
Their signatures are different. I.e one is Object the other - String.

Related

Generic method not overriding similar generic method in superclass -> Which one is used?

Given this situation:
public class Animal {
public <T> void genericMethod(T t){
System.out.println("Inside generic method on animal with parameter " + t.toString());
}
}
public class Cat extends Animal {
public <T extends Cat> void genericMethod(T t){
System.out.println("Inside generic method on cat with parameter " + t.toString());
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Cat cat = new Cat();
cat.genericMethod(cat);
}
}
The method genericMethod() in class Cat is definitely NOT overriding the superclass method (and the compiler complains if I add #Override signature) which is reasonable, as the requirements to the type T are different.
But I do not quite understand, how the compiler decides which of the two methods to use in the call cat.genericMethod(cat) in the main method. Because actually both methods are visible and both are applicable. I would have expected a compiler error like "ambigous function call" here. Can someone explain this behavior?
These two methods have a different erasure due to the generic type bound of the sub-class method.
For the super class method the erasure is:
public void genericMethod(Object t)
For the sub class method the erasure is:
public void genericMethod(Cat t)
Method overloading resolution rules choose the method with the best matching arguments. Therefore when you pass a Cat argument, the second (sub-class) method is chosen.
Java, at compile time, will choose the most specific matching method.
In your example, this means the Cat implementation of the method.
THere are two things to notice:
If you pass to it an Animal, it is obvious that only the method declared in Animal will be used (since it doesn't match the T extends Cat constraint).
If you pass to it a Cat:
Java decides that the two methods match (because of the Cat parameter)
Because of the aforementioned rule, Java simply take the most specific one (it does not care anymore about the fact that the parameter is a Cat).

Type erasure and overriding generic method

My understanding about generic was that if I have public void saveAll(Collection<? extends Object> stuff) { then compile will determine the "most common type" of the input parameter to be Collection<Object>. Now, with that I wrote below code for overriding the generic methods, but I get following error message in the overriding method - Name clash: The method saveAll(Collection<? extends Object>) of type ChildWithGenericMethod has the same erasure as saveAll(Collection<Object>) of type ParentWithGenericMethod<T> but does not override it
public class ParentWithGenericMethod {
public void saveAll(Collection<Object> stuff) {
}
}
public class ChildWithGenericMethod extends ParentWithGenericMethod{
public void saveAll(Collection<? extends Object> stuff) {
}
}
What I want to know is that after type erasure how these methods would look like, I thought they would look like public void saveAll(Collection stuff) { and hence I should be able to override, because if I don't use generics then I can override like this.
Please note that I know that I can see the byte code after compilation using "javap" but it doesn't tell me how these methods would look like after "type erasure".
Update:
This question doesn't answer my question, if after type erasure both methods become public void saveAll(Collection stuff) { then why subclass is getting overriding error, because with public void saveAll(Collection<Object> stuff) { it passes the overriding rules.
It's worth remembering run time vs compile-time dispatch.
Take away generics for a second.
public class Parent {
public void saveAll(Object x) {
}
}
public class Child extends Parent {
public void saveAll(String x) {
}
}
public String x = "hello";
public Object y = new Integer(334);
public Object z = "goodbye";
public Child c1 = new Child();
c1.saveAll(x); // invokes Child.saveAll
c1.saveAll(y); // invokes Parent.saveAll
c1.saveAll(z); // invokes Parent.saveAll even though z contains a String
Now put generics back into the story.
public class Child<T extends Object> extends Parent {
public void saveAll(T x) {
}
}
Here, saveAll overloads, rather than overrides, the parent's saveAll.
replacing T with an anoymous ? doesn't really change that -- the compiler is trying to create a method that overloads the parent's method, but then realizes that it can't dispatch on compile-time type.
[edit, see Lew Block's comment on the original: the compiler needs to decide whether the child method overrides or overloads the parent's method before type erasure]
if after type erasure both methods become public void saveAll(Collection stuff) { then why subclass is getting overriding error, because with public void saveAll(Collection stuff) { it passes the overriding rules.
The problem (again see Lew Bloch's comment) is that overriding is determined before type erasure. Before type erasure, the parent and child method have different signatures, and so the compiler creates them as overloaded methods rather than overriding methods. After type erasure, the compiler realizes it is in a bind because it now has two methods with the same signature and no way to know how to dispatch.

Two methods when implementing interface containing only one

I created interface TwoMethods. Source code:
interface TwoMethods<T>
{
public void method(T t);
}
Then I created class implementing this interface and after disassembling I saw 2 methods.
Class:
class A implements TwoMethods<A>
{
#Override
public void method(A a) {}
}
After disassembling:
class A implements TwoMethods<A> {
A();
public void method(A); //first
public void method(java.lang.Object); //second
}
Similarly for Comparable interface. Why when I create parametrized interface I have 2 methods. It is always, when I use parameter? I have additionally method with Object as argument?
method(java.lang.Object) is called the bridge method and it's generated because of type-erasure at compile time.
See Effects of Type Erasure and Bridge Methods
If we look at interface TwoMethods bytecode we will see that the actual method is
public abstract method(Ljava/lang/Object;)V
that is at bytecode level information about type parameter does not exist, type is erased, JVM simply does not know about generics, type parameters are replaced either with Object or in case if T extends X with X. So from the point of view of JVM
class A implements TwoMethods<A> {
public void method(A a) {
...
method(A a) does not override interface method because in bytecode it is in method(Object obj) can override it. To fix this problem compiler builds an implicit method, so called bridge method, in class A
public void method(Object obj) {
method((A)obj);
}
visible in bytecode only. Now for this code
A a = new A();
TwoMethods<A> tm = a;
tm.method(a);
compiler will replace tm.method(a) with call to the bridge
INVOKEINTERFACE test/TwoMethods.method(Ljava/lang/Object;)V
and this will redirect the call to A.method(A a);

Avoiding unsafe casting with generics

Lets say I have an abstract class:
public abstract class Trainer<T extends Animal>{
...
}
I'd like all child classes to have a common method that checks the training status of a trainer on a given animal. So I have in my Trainer definition:
public abstract class Trainer<T extends Animal>{
public double getStatus(Animal a){
...
}
}
so that anyone can query a trainer regardless of it's specific type. However, to make the individual trainers responsible for reporting their own status, I requiring a that the individual trainers implement an internalGetStatus method which I'd then like my getStatus method to call. So what I'm currently doing is:
public abstract class Trainer<T extends Animal>{
protected abstract internalGetStatus(T theAnimal);
public double getStatus(Animal a){
return internalGetStatus((T) a);
}
}
The problem is, of course, return internalGetStatus((T) a); involves an unchecked type cast which throws up a warning I'd like to avoid.
Is there a way to do that?
Because of some design limitations beyond my control, when the status is being queried for a particular animal, it is provided as an object of the parent class Animal and not the specific animal type that the trainer is created for.
It depends on how the classes are used. However, you didn't say much about that. Let's start with the following code:
abstract class Animal { }
final class Lion extends Animal { }
abstract class Trainer<T extends Animal> {
public abstract double getStatus(T animal);
}
final class LionTrainer extends Trainer<Lion> {
public double getStatus(Lion lion) {
return 4.2;
}
}
You mentioned that the call-side of the getStatus method doesn't know the animal type. That means he isn't using Trainer<Lion>, but either the raw type, Trainer<Animal> or a wildcard type. Let's go through these three cases.
Raw Type: The type parameter doesn't matter for raw types. You can invoke the method getStatus with Animal. This works as long as the sub-types of Trainer and Animal match. Otherwise, you will see a ClassCastException at runtime.
void raw(Trainer trainer, Animal animal) {
trainer.getStatus(animal);
}
Trainer<Animal>: Obviously, you can invoke the method getStatus of an Trainer<Animal> with an Animal. It similar to the above case. The static type system doesn't ware, and at runtime you will see an exception, if the types don't match.
void base(Trainer<Animal> trainer, Animal animal) {
trainer.getStatus(animal);
}
Note that you can pass a LionTrainer to this method (with cast), because at runtime there is no difference between Trainer<Animal> and Trainer<Lion>.
Wildcard Type: Well, that does not work on the caller-side - without casting the Trainer<?> to something else. The ? stands for an unknown sub-type of Animal (including the base class itself).
void wildcard(Trainer<?> trainer, Animal animal) {
trainer.getStatus(animal); // ERROR
}
The result is, if the framework uses either the raw type or the base type, then there shouldn't be a problem. Otherwise it's simpler to add the cast to your code, suppress the warning with an annotation, and document why you have decided to go that way.

Java generic method inheritance and override rules

I have an abstract class that has a generic method and I want to override the generic method by substituting specific types for the generic parameter. So in pseudo-code I have the following:
public abstract class GetAndParse {
public SomeClass var;
public abstract <T extends AnotherClass> void getAndParse(T... args);
}
public class Implementor extends GetAndParse {
// some field declarations
// some method declarations
#Override
public <SpecificClass> void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
But for some reason I'm not allowed to do this? Am I making some kind of syntax error or is this kind of inheritance and overriding not allowed? Specifically I'm getting an error about #Override because the eclipse IDE keeps reminding me to implement getAndParse.
Here's how I want the above code to work. Somewhere else in my code there is a method that expects instances of objects that implement GetAndParse which specifically means that they have a getAndParse method that I can use. When I call getAndParse on that instance the compiler checks to see whether I have used specific instances of T in the proper way, so in particular T should extend AnotherClass and it should be SpecificClass.
What we are having here is two different methods with individual type parameters each.
public abstract <T extends AnotherClass> void getAndParse(Args... args);
This is a method with a type parameter named T, and bounded by AnotherClass, meaning each subtype of AnotherClass is allowed as a type parameter.
public <SpecificClass> void getAndParse(Args... args)
This is a method with a type parameter named SpecificClass, bounded by Object (meaning each type is allowed as a type parameter). Do you really want this?
Is the type parameter used inside Args? I think the problem would be there.
The meaning of
public abstract <T extends AnotherClass> void getAndParse(T... args);
is that the caller of the method can decide with which type parameter he wants to call the method, as long as this is some subtype of AnotherClass. This means that in effect the method can be called with any objects of type AnotherClass.
Since the caller can decide the type parameter, you can't in a subclass narrow down the parameter type to SpecificClass - this would not be an implementation of the method, but another method with same name (overloading).
Maybe you want something like this:
public abstract class GetAndParse<T extends AnotherClass> {
public SomeClass var;
public abstract void getAndParse(T... args);
}
public class Implementor extends GetAndParse<SpecificClass> {
// some field declarations
// some method declarations
#Override
public void getAndParse(SpecificClass... args) {
// method body making use of args
}
}
Now the getAndParse method implements the parent class' method.
You are seeing this problem because of the concept called "Erasure" in Java Generics.
Java uses "erasure" to support backward compatibility. i.e Java code which did not use generics.
Erasure Procedure:
The compiler will first do a type checking and then it will remove(erase) all the type parameters as much as possible, and also insert TypeCasting where ever necessary.
example:
public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass);
will become
public abstract void getAndParse(AnotherClass paramAnotherClass);
In class "Implementor.java",
The code
public <SpecificClass> void getAndParse(T paramAnotherClass)
will become
public void getAndParse(SpecificClass paramAnotherClass){ }
the compiler will see that you have not implemented the abstract method correctly.
There is a type mismatch between the abstract method and the implemented method. This is why you are seeing the error.
More details can be found here.
http://today.java.net/pub/a/today/2003/12/02/explorations.html
You cannot override to specific type T because there is in fact (at the bytecode level if you wish) only one method getAndParse because of type erasure (see other answer):
public abstract void getAndParse(AnotherClass... args); // (1)
For every type of T, the same method is used.
You can overload it (I think):
public void getAndParse(SpecificClass... args); // (2)
but this will not a different method from (1) ant it will not be called by generic code:
T x = whatever;
object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass
No, it's not valid. What would happen if someone with a GetAndParse reference called it with a different class extending AnotherClass?
That becomes a nonsense when someone has a reference to type GetAndParse and tries to call the getAndParse method. If Cat and Dog extend AnotherClass. I should expect to be able to call GetAndParse#getAndParse with either a Cat or a Dog. But the implementation has tried to restrict it and make it less compatible!
Static method can't override
class Vehicle{
static void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
#Override //error
void park(int location) { //error
System.out.println("Car Parking..");
}}
Private method can't override
class Vehicle{
private void park(int location){
System.out.println("Vehicle parking..");
}
void callPark(){
park(100);
}}
class Car extends Vehicle{
//#Override
void park(int location) {
System.out.println("Car Parking..");
}}
class Demo {
public static void main(String[] args) {
Vehicle v1=new Car();
v1.callPark();
}}
Final method can't override
class Vehicle{
final void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
//#Override
void park(int location) { //error
System.out.println("Car Parking..");
}}

Categories