Java: Polymorphic Return Type in an Abstract Method?
-
07-06-2021 - |
문제
I have the following code in an abstract java class:
protected abstract <E extends HasText & IsWidget> E createNewDisplayWidget();
Which compiles fine. However if I call it anywhere, the compiler complains:
Bound mismatch: The generic method createNewDisplayWidget() of type DemoClass is not applicable for the arguments (). The inferred type HasText is not a valid substitute for the bounded parameter <E extends HasText & IsWidget>
Is there a way to require an abstract method to return something that should implement multiple interfaces?
Note: No, I cannot create a special interface that implements the two I like. GWT has widgets like Label which already implement said interfaces and I would like to use said widget.
Edit: I got the idea to do this from here (page 22):
해결책 2
The problem was in Eclipse. I upgraded from 3.7 to 3.7.2 and the compiler error went away.
I don't know the details of what effect this had. If someone has a clue please feel free to update my answer.
다른 팁
I have given a try on the basis of your question and i was able to get through without an error. Please check the classes that i have created.
TestClass
public abstract class TestClass {
protected abstract <E extends HasText & IsWidget > E createNewDisplayWidget();
}
HasText class
public class HasText {
}
IsWidget
public interface IsWidget {
}
DemoClass
public class DemoClass extends HasText implements IsWidget{
}
TestClass1
public class TestClass1 extends TestClass{
@Override
protected DemoClass createNewDisplayWidget() {
// TODO Auto-generated method stub
DemoClass type = new DemoClass();
return type;
}
public void checkOut(){
if(createNewDisplayWidget() instanceof HasText || createNewDisplayWidget() instanceof IsWidget){
System.out.println("Yes it works");
}
else{
System.out.println("It doesnt");
}
}
public static void main(String[] args){
TestClass1 check = new TestClass1();
check.checkOut();
}
}
When i run my main program i always get "Yes it works". Please let me know am i missing something.
So I tried doing the complete code to generate the error, but for some reason it didn't give an error. Will look into it in a bit:
import java.util.LinkedList;
public abstract class DemoClass {
public static void main(String[] args) {
DemoClass dc = new DemoClassImpl();
dc.createNewLivingAndDying().live();
dc.killAll();
}
LinkedList<Dies> dying = new LinkedList<Dies>();
public Lives createNewLivingAndDying() {
Lives ab = newLivingAndDying(); // This is where I expected an error
dying.add((Dies) ab);
return ab;
}
public void killAll() {
for (Dies dead : dying)
dead.die();
}
protected abstract <E extends Lives & Dies> E newLivingAndDying();
}
class DemoClassImpl extends DemoClass {
@SuppressWarnings("unchecked")
@Override
protected <E extends Lives & Dies> E newLivingAndDying() {
return (E) new SomePrivateClass(); // This is what I don't understand
}
}
interface Lives {
public void live();
};
interface Dies {
public void die();
};
class SomePrivateClass implements Lives, Dies {
@Override
public void die() {
System.out.println("Object Dies");
}
@Override
public void live() {
System.out.println("Object Lives");
}
}
This code compiles and runs fine on my home computer but giver the error on my work computer.
Bound mismatch: The generic method newLivingAndDying() of type DemoClass is not applicable for the arguments (). The inferred type Lives is not a valid substitute for the bounded parameter <E extends Lives & Dies>
At this point I think it's a project setup issue but I don't know what it is. JRE 1.6 both.
What you want to do is only possible if Java supports interception type directly, then you can simply
HasText&IsWidget createNewDisplayWidget();
any implementation must return an object that's a subtype of the type HasText&IsWidget
; in another word, the returned type must be a subtype of both HasText
and IsWidget
Unfortunately, Java does not support that.
The problem of your attempted solution can be understood from two angles:
1) constraints on a type variable are constraints on the caller; caller supplies the actual type argument, and it must satisfy the constraints. What you really want is constraints on the callee.
2) if a type variable only appears in the return type, but not types of method parameters, it is usually a sign of problem. In Java, due to the evil type erasure, the method body cannot know the runtime type argument, therefore it cannot return a value of proper type desired by caller, except for some trivial values like null
; another classic example of trivial return value is
java.util.Collections
<T> Set<T> emptySet()