Java generic method inheritance and override rules - java

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..");
}}

Related

error overriding method of class that extends generic class

i have a class A that extends a class B and the class B extends a generic Class
my class A is:
public class MyCustomerReviewConverter<SOURCE extends CustomerReviewModel, TARGET extends ReviewData> extends CustomerReviewConverter{
#Override
public void populate(final SOURCE source, final TARGET target) {.....}
the extended class B is
public class CustomerReviewConverter extends AbstractPopulatingConverter<CustomerReviewModel, ReviewData>{
#Override
public void populate(final CustomerReviewModel source, final ReviewData target)
{..........}
but i'm getting the error
Name clash: The method populate(SOURCE, TARGET) of type MyCustomerReviewConverter<SOURCE,TARGET> has the same erasure as populate(CustomerReviewModel, ReviewData) of type
CustomerReviewConverter but does not override it
what's wrong?
As second parameter in the populate method i have to pass a class
MyReviewData extends ReviewData{...}
thanks in advance
Andrea
Tricky and difficult to explain.
The type parameters are defined in the generic AbstractPopulatingConverter.
The type parameters are concretized in CustomerReviewConverter.
Then, you try to make the concretized type parameters generic again in MyCustomerReviewConverter.
And that just doesn't work. You're trying to override a method with a method that has a different method signature (different parameter types).
The only way you can override that method is as follows:
#Override
public void populate(final CustomerReviewModel source,
final ReviewData target) { /* ... */ }
However, instead of overriding the method, you can overload it:
public void populate(final MyCustomerReviewModel source,
final MyReviewData target) { /* ... */ }
If the populate() method is called on an object of type MyCustomerReviewConverter with a MyCustomerReviewModel and MyReviewData parameter, the compiler will select the most specific populate method, being the overloaded one.
The types of the generic types for <SOURCE, TARGET> have already been concreted in by B as <CustomerReviewModel, ReviewData>.
If you want to extend B, your A should simply be:
public class MyCustomerReviewConverter extends CustomerReviewConverter {
#Override
public void populate(final CustomerReviewModel source, final ReviewData target)
{ ... }
}
Otherwise you need to extend AbstractPopulatingConverter directly, and perhaps write a delegate to perform the shared logic within B so you can re-use it elsewhere.
#Robby Cornelissen explains it better than me in his answer though.
You should extend CustomerReviewConverter<SOURCE, TARGET> (probably, you haven't added its definition to the question) instead of the raw type. Then you need to override public void populate(SOURCE source, TARGET target).

Cannot implement abstract method with a subclass of an abstract argument

Say I'm making a class that implements an interface, and have code like this:
public void setGoalLocation(Location loc)
{
goal = loc;
}
The code doesn't compile, because it demands that I implement a "setGoalLocation(Ilocation loc)" method, where "Ilocation" is an interface and "Location" is an actual concrete class that implements it.
This means that I have to do something like this:
public void setGoalLocation(ILocation loc)
{
goal = (Location)loc;
}
That just seems really awkward. And funnily enough, Java doesn't seem to care about other methods returning Location instead of the interface ILocation. This works:
public Location getStartLocation()
{
return start;
}
...even though the "required" method would be a "public ILocation getStartLocation". Can anyone explain why this is, and any help for making the code less awkward? I'd like to be able to use a Location as a parameter, not an ILocation.
The problem is that the interface requires a method that accepts anything as an argument that is a subtype of ILocation, not just an object of the specific type Location. If you had another concrete type Position that was a subtype of ILocation, then implementing the interface would require you to accept a Position object as well as a Location object.
Note that in your work-around using a cast, you'd get a ClassCastException at run time if you happened to pass a Position instead of a Location object.
As a design issue, to get around this you could define your interface as a generic:
interface <T extends ILocation> TheInterface {
void setGoalLocation(T loc);
}
Then your concrete class can bound the generic parameter:
public class MyClass implements TheInterface<Location> {
public void setGoalLocation(Location loc) {
. . .
}
}
As to return types, that works because any Location object is an ILocation, so when you return a Location you are returning an ILocation.
Java supports covariant return types where the return type of a method in a subclass (or interface implementation) can return a subclass (or implementation) of the declared type. So in general, the following is allowed
public class A {}
public class B extends A {}
public class C {
A getSomething();
}
public class D extends C {
B getSomething();
}
If the interface has a method that takes an interface type, you cannot override it with a different signature.
public interface I {
void setSomething(ISomething somethingInterface);
}
You cannot do
public class Something implements ISomething {}
public class MyI implements I {
void setSomething(Something somethingInterface);
}

How Java Picks an Overloaded Method in Polymorphism

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.

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);

Same method with different return types in abstract class and interface

Just extending the question..
Same method in abstract class and interface
Suppose a class implements an interface and extends an abstract class and both have the same method (name+signature), but different return types. Now when i override the method it compiles only when i make the return type same as that of the interface declaration.
Also, what would happen if the method is declared as private or final in the abstract class or the interface?
**On a side note. Mr. Einstein stuck to this question for an abominable amount of time during an interview. Is there a popular scenario where we do this or he was just showing off?
If the method in abstract class is abstract too, you will have to provide its implementation in the first concrete class it extends. Additionally, you will have to provide implementation of interface. If both the methods differ only in return type, the concrete class will have overloaded methods which differ only in return type. And we can't have overloaded methods which differ only in return type, hence the error.
interface io {
public void show();
}
abstract class Demo {
abstract int show();
}
class Test extends Demo implements io {
void show () { //Overloaded method based on return type, Error
}
int show() { //Error
return 1;
}
public static void main (String args[]) {
}
}
No, same method names and parameters, but different return types is not possible in Java. The underlying Java type system is not able* to determine differences between calls to the methods at runtime.
(*I am sure someone will prove me wrong, but most likely the solution is considered bad style anyways.)
Regarding private/final: Since you have to implement those methods, neither the interface method nor the abstract method can be final. Interface methods are public by default. The abstract method can't be private, since it must be visible in the implementing class, otherwise you can never fulfill the method implementation, because your implementing class can't "see" the method.
With Interfaces the methods are abstract and public by default ,
so they cant have any other access specifier and they cant be final
With abstract class , abstract methods can have any access specifier other than private and because they are abstract they cant be final
While overriding , the method signature has to be same ; and covariant(subclass of the declared return type) return types are allowed
A class cannot implement two interfaces that have methods with same name but different return type. It will give compile time error.
Methods inside interface are by default public abstract they don't have any other specifier.
interface A
{
public void a();
}
interface B
{
public int a();
}
class C implements A,B
{
public void a() // error
{
//implementation
}
public int a() // error
{
//implementation
}
public static void main(String args[])
{
}
}

Categories