Java:抽象方法中的多态返回类型?

Java:抽象方法中的多态返回类型?,java,gwt,parametric-polymorphism,Java,Gwt,Parametric Polymorphism,我在抽象java类中有以下代码: protected abstract <E extends HasText & IsWidget> E createNewDisplayWidget(); 受保护的抽象E createNewDisplayWidget(); 这很好。但是,如果我在任何地方调用它,编译器都会抱怨: Bound mismatch: The generic method createNewDisplayWidget() of type DemoClass is

我在抽象java类中有以下代码:

protected abstract <E extends HasText & IsWidget> E createNewDisplayWidget();
受保护的抽象E createNewDisplayWidget();
这很好。但是,如果我在任何地方调用它,编译器都会抱怨:

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>
绑定不匹配:DemoClass类型的泛型方法createNewDisplayWidget()不适用于参数()。推断的类型HasText不是有界参数的有效替代品
有没有一种方法需要一个抽象方法来返回应该实现多个接口的东西

注意:不,我无法创建实现我喜欢的两个接口的特殊接口。GWT有像Label这样的小部件,它已经实现了上述接口,我想使用上述小部件

编辑:我从这里得到了这样做的想法(第22页):


根据您的问题,我已经尝试过了,我能够顺利通过。请检查我创建的类

TestClass

public abstract class TestClass {

    protected abstract <E extends HasText & IsWidget > E createNewDisplayWidget();

}
public class HasText {

}
 public class DemoClass extends HasText implements IsWidget{

    }
IsWidget

public interface IsWidget {

}
DemoClass

public abstract class TestClass {

    protected abstract <E extends HasText & IsWidget > E createNewDisplayWidget();

}
public class HasText {

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

    }

}

当我运行我的主程序时,我总是得到“是的,它能工作”。请让我知道我是否遗漏了什么。

只有在Java直接支持拦截类型的情况下,您才可能想做什么,然后您可以简单地

   HasText&IsWidget createNewDisplayWidget();
任何实现都必须返回属于
HasText&IsWidget
类型的子类型的对象;换句话说,返回的类型必须是
HasText
IsWidget

不幸的是,Java不支持这一点

您试图解决的问题可以从两个角度来理解:

1) 对类型变量的约束是对调用方的约束;调用者提供实际的类型参数,并且它必须满足约束。您真正想要的是对被调用方的约束

2) 如果类型变量只出现在返回类型中,而不出现在方法参数的类型中,则通常是问题的迹象。在Java中,由于邪恶的类型擦除,方法体无法知道运行时类型参数,因此它无法返回调用者所需的正确类型的值,除了一些琐碎的值,如
null
;另一个简单返回值的经典示例是

java.util.Collections  
    <T> Set<T> emptySet()
java.util.Collections
设置清空集()

所以我尝试编写完整的代码来生成错误,但由于某种原因,它没有给出错误。我们将在稍后进行调查:

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");
    }
}
import java.util.LinkedList;
公共抽象类DemoClass{
公共静态void main(字符串[]args){
DemoClass dc=新的DemoClassImpl();
dc.createnewlivingandding().live();
dc.killAll();
}
LinkedList=新建LinkedList();
公共生活创造新生活和新死亡(){
Lives ab=newlivingandding();//这就是我预期的错误所在
死亡。添加((死亡)ab);
返回ab;
}
公众假期{
因为(死了:死了)
死了,死了;
}
受保护的摘要E newliving and ding();
}
类DemoClassImpl扩展了DemoClass{
@抑制警告(“未选中”)
@凌驾
受保护的新生活和死亡(){
return(E)new SomePrivateClass();//这是我不明白的
}
}
接口寿命{
公共空间活动();
};
接口{
公共无效死亡();
};
类someprivate类实现生命,死亡{
@凌驾
公共空间(){
System.out.println(“对象死亡”);
}
@凌驾
公共生活{
System.out.println(“对象寿命”);
}
}
此代码在我的家用计算机上编译并运行良好,但在我的工作计算机上给出了错误

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>
绑定不匹配:DemoClass类型的泛型方法newlivingandding()不适用于参数()。推断的类型不是有界参数的有效替代品

在这一点上,我认为这是一个项目设置问题,但我不知道它是什么。JRE 1.6两者都有。

问题出在Eclipse中。我从3.7升级到3.7.2,编译器错误消失了


我不知道这有什么影响的细节。如果有人有线索,请随时更新我的答案。

您是否尝试用逗号而不是and?逗号表示绑定以IsWidget结尾。然后HasText就被忽略了。编译器抛出一个警告,说第二种类型是“隐藏的”。你能给我们看一下你的一个/一些调用站点吗?@McTrafik Ok,很高兴知道:)我认为这实际上是不可能的。返回该交叉点中的一个实际类。您正在从同一个类调用
createNewDisplayWidget()
,在该类中,您为它提供了一个更具体的返回类型。我尝试从
DemoClass
调用它,但无法重现OP的错误。也许这是GWT特有的问题,是的。我试图解决的问题是不必创建另一种类型,如“DemoClass”。这实际上是我使用的解决方案,但不是我想要的,因为现在我必须为我想要使用的GWT中的每个类创建自定义类型。答案是不正确的,您不应该接受它。正确的是,这样的方法签名可能是问题的标志。但是对于创建特定子类型集的工厂来说,这可能是可以的(为了方便),并且它可以在Java中工作(只需添加“@SuppressWarnings”(“unchecked”),如果您愿意的话。您可能会在运行时得到ClassCastException,这可能不是最好的方法,但这并不能解释您得到的编译器错误!对我来说,在Java中,由于邪恶的类型擦除,方法体无法知道运行时类型参数,因此它无法返回调用者所需的正确类型的值de sense作为原因。我尝试向签名添加类型为
E
的参数,编译器停止抱怨。当然,然后该方法变得不可用。换句话说,通过使用
Object
(隐式)作为类型参数和