泛型方法中的Java有界参数

泛型方法中的Java有界参数,java,generics,methods,Java,Generics,Methods,我在泛型方法中使用有界参数测试了一些东西,发现了一些奇怪的行为。 如果有人能在下面的代码片段中解释这两个错误,那就太好了 假设有两个类Class1和Class2都是从基类扩展而来的类2实现一个接口 在Class1中,我有一个方法,它通过以下方式返回Class2的实例: public class Class2 extends BaseClass implements Interface { @Override public void method() { Syst

我在泛型方法中使用有界参数测试了一些东西,发现了一些奇怪的行为。
如果有人能在下面的代码片段中解释这两个错误,那就太好了

假设有两个类
Class1
Class2
都是从
基类扩展而来的<代码>类2
实现一个接口

Class1
中,我有一个方法,它通过以下方式返回
Class2
的实例:

public class Class2 extends BaseClass implements Interface {

    @Override
    public void method() {
        System.out.println("test"); //$NON-NLS-1$
    }
}

public class Class1 extends BaseClass {

    public <T extends BaseClass & Interface> T getTwo() {
        return new Class2();
        // Error: Type mismatch: cannot convert from Class2 to T
    }

    public static void main(String[] args) {
        Interface two = new Class1().getTwo();
        // Error: Bound mismatch: The generic method getTwo() of type Class1 is
        // not applicable for the arguments (). The inferred type Interface is
        // not a valid substitute for the bounded parameter <T extends BaseClass
        // & Interface>
        System.out.println(two);
    }
}
公共类Class2扩展基类实现接口{
@凌驾
公开作废法(){
System.out.println(“测试”);//$NON-NLS-1$
}
}
公共类Class1扩展了基类{
公共T getTwo(){
返回新的Class2();
//错误:类型不匹配:无法从Class2转换为T
}
公共静态void main(字符串[]args){
接口2=newclass1().getTwo();
//错误:绑定不匹配:Class1类型的泛型方法getTwo()为
//不适用于参数()。推断的类型接口为
//不是有界参数的有效替代项
System.out.println(两个);
}
}

发生第一个编译错误是因为方法声明的类型参数是由调用方指定的,而不是由方法实现指定的。也就是说

class Class3 extends BaseClass implements Interface { ... }
打电话的人可以写信

Class3 c3 = new Class1().<Class3>getTwo();
class3c3=newclass1().getTwo();
,但方法实现返回一个
Class2
,它不是
t
=
Class3
的子类型

发生第二个编译错误的原因是,调用方未显式指定的类型参数是从方法参数和方法返回值分配给的变量类型推断出来的。这个推论在这里失败了。Java语言规范推荐的通常解决方法是在这种情况下显式指定类型参数(类型推断是为了方便简单的情况;它的目的不是覆盖所有情况)


至于如何正确声明此类型参数,我需要知道您试图用这些声明实现什么。

当您知道它是
Class2
时,为什么要对方法
getTwo
使用泛型?只需这样做:

public Class2 getTwo() {
    return new Class2();
}

如果您正在重写一个方法
public T getTwo()
,编译器将允许您在impl的
T
Class2

时,将impl声明为
public Class2 getTwo()
,这似乎是误用泛型。实际上
getTwo
必须具有返回类型,即
Class2
,或
BaseClass
,或
接口
。如果只为一个方法定义了
T
,编译器就无法知道在
new Class1().getTwo()
行中哪个类确切地替换了
T
。只有当
getTwo
具有此类型的输入参数时,才有可能实现此操作。+1回答正确。不过,我认为在第二个代码示例中,语法应该是
new Class1().getTwo()
。我明白第一个编译错误的意义,但我不确定第二个编译错误。调用
baseclasstwo=newclass1().getTwo()在我的系统上似乎正常,但在同事的系统上失败,调用
接口2=new Class1().getTwo()在我的系统上也会失败(如上所示)…那么,您是否尝试过以类似于我的
Class3
示例的方式明确指定类型参数?或者通过声明
Class2 two=new Class1().getTwo()来调整类型推断?我不能马上解释为什么它在你的系统上会有不同的行为。您是否使用具有相同设置的相同编译器尝试过完全相同的示例程序?假设“getwo()”-方法是接口的一部分,并且您不知道getwo的确切返回类型,您希望以通用方式使用返回的对象。你知道为什么“基类2=class1.getTwo();”是OK并且“接口2=class1.getTwo();”无法编译?好吧,我想是这样。我可能会定义
抽象类BaseClassWithInterface extends基类实现接口{}
,并要求
Class2
对其进行扩展。然后,任何调用方都可以使用
BaseClassWithInterface
变量来存储对象。关于您的为什么问题:可能是因为Java语言规范的算法这么说。在覆盖方面没有那么快。在您的场景中,您将重写一个方法,该方法可以返回满足约束的任何T,而返回Class2的方法则应该被禁止,原因与OP的代码被禁止的原因相同。我不确定Java是否能够用存在量词来表示返回类型。