2016-11-09 100 views
3
abstract class AbsClass {} 

class MyAbs extends AbsClass {} 

class MyClass<S extends AbsClass> { 
    S getObj() { 
     return new MyAbs(); 
    } 
} 

获取编译器的问题:Java泛型和不兼容的类型<S伸展{}类>

Error:(33, 16) java: incompatible types: MyAbs cannot be converted to S

什么是做这种正确的方法是什么?

编辑: 我希望能够初始化MyClass {MyAbs},然后调用getObj(),它将返回MyAbs对象。随着安迪的回答,我将不得不将AbsClass施加到MyAbs或MySecondAbs,这正是我试图避免

+2

删除'',并更改单曲getObj()'要么'MyAbs getObj( )'或'AbsClass getObj()'。就目前而言,没有理由有一个类型变量。 –

+1

你能说出“做这个”时你想要什么吗? – Simon

+0

我希望能够初始化MyClass ,然后调用getObj(),它将返回MyAbs对象。随着安迪的回答,我将不得不将AbsClass投给MyAbs或MySecondAbs,这正是我试图避免的 – mwong56

回答

3

S扩展MyAbs,而不是相反。 S类型的任何对象都可以投射到MyAbs,但MyAbs不能投射到它的派生类中。

请解释你想达到的目标。

+1

所有的贵宾狗都是狗,但并非所有的狗都是贵宾狗。 – Taylor

5

Andy已经描述了如何解决这个问题,我会尽力解释原因。

S不保证可指定为MyAbs,只能指定为AbsClass,每个实例将指定AbsClass的子类。

考虑:

class MyOtherAbs extends AbsClass {} 

MyClass myClass = new MyClass<MyOtherAbsClass>{}; 

这跟你有什么冲突。

UPDATE:

根据您的意见,它看起来像你想实现以上。挑战是如果MyOtherAbs有一个带参数的构造函数?或者被实现为单例(即私有构造函数和静态getInstance())。总之,没有保证统一的方式可以构建这些。此外,由于类型擦除,在运行时,S的概念没有了,所以你不能这样做:

return new S(); 

你基本上有两种选择,一种是使用子类:

public interface AbsClassFactory<S extends AbsClass>{ //takes the place of MyClass 
    public S getInstance(); 
} 

MyAbsFactory implements AbsClassFactory<MyAbs>{ 
    public MyAbs getInstance(){ 
     return new MyAbs(); //or however MyAbs is instantiated 
    } 
} 

另一种选择是反思:

class MyClass { 
    public <S extends AbsClass> S getObj(Class<S> clazz) throws InstantiationException, IllegalAccessException { 
     return clazz.newInstance(); 
    } 
} 

注意,第二个假设有可用的无参数的构造函数,将抛出一个运行时异常,如果一个不是。

+0

你的例子就是我想要完成的事情,对不清楚的事情感到抱歉。 – mwong56

+0

我会扩大答案以提供替代方案 – Taylor

1

从您的评论似乎可以使用Supplier接口来完成相同的:

Supplier<MyAbs> supp = MyAbs::new; // Constructor reference 
MyAbs obj = supp.get(); 

Supplier<MySecondAbs> supp2 = MySecondAbs::new; 
MySecondAbs obj2 = supp2.get();