简体   繁体   English

Java泛型和不兼容的类型使用

[英]Java generics & incompatible types using <S extends {class}>

abstract class AbsClass {}

class MyAbs extends AbsClass {}

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

Getting compiler issue: 获取编译器问题:

Error:(33, 16) java: incompatible types: MyAbs cannot be converted to S 错误:(33,16)java:不兼容的类型:MyAbs无法转换为S.

What is the correct way to do this? 这样做的正确方法是什么?

Edit: I was hoping to be able to intialize MyClass{MyAbs} then call getObj() which would return me a MyAbs object. 编辑:我希望能够初始化MyClass {MyAbs},然后调用getObj(),这将返回一个MyAbs对象。 With Andy's answer, I would have to cast the AbsClass to MyAbs or MySecondAbs which was what I was trying to avoid 有了Andy的回答,我必须将AbsClass转换为MyAbs或MySecondAbs,这是我试图避免的

Andy has described how to fix the problem, I'll try to explain why. 安迪已经描述了如何解决问题,我将尝试解释原因。

S is not guaranteed to be assignable to MyAbs , only to AbsClass , and each instance will specify a subclass of AbsClass . S不保证可分配给MyAbs ,只有AbsClass ,每个实例将指定的子类AbsClass

Consider: 考虑:

class MyOtherAbs extends AbsClass {}

MyClass myClass = new MyClass<MyOtherAbsClass>{};

This would conflict with what you have. 这会与你所拥有的相冲突。

UPDATE: 更新:

Based on your comments it looks like you want to achieve the above. 根据您的评论,您希望实现上述目标。 The challenge is what if MyOtherAbs has a constructor with arguments? 如果MyOtherAbs有一个带参数的构造函数,那么挑战是什么呢? Or is implemented as a Singleton (ie a private constructor and static getInstance() ). 或者实现为Singleton(即私有构造函数和静态getInstance() )。 In short, there is no guaranteed unified way you can construct these. 简而言之,没有保证统一的方法可以构建这些。 Further, due to type erasure, at runtime, the concept of S is gone, so you cannot do something like: 此外,由于类型擦除,在运行时,S的概念消失了,所以你不能做类似的事情:

return new S();

You basically have two alternatives, one is to use subclassing: 你基本上有两个选择,一个是使用子类:

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
    }
}

The other option is reflection: 另一种选择是反思:

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

Note that the second assumes there is a no arg constructor available and will throw a runtime exception if one is not. 请注意,第二个假设没有可用的arg构造函数,如果不是,则会抛出运行时异常。

S extends MyAbs , not the other way around. S扩展了MyAbs ,而不是相反。 any object of type S can be cast into MyAbs , but MyAbs cannot be cast into it's derived classes. 类型S任何对象都可以转换为MyAbs ,但MyAbs不能转换为它的派生类。

Please explain what you are trying to achieve. 请解释一下你想要实现的目标。

From your comment it seems that you can accomplish the same using the Supplier interface: 从您的评论中,您似乎可以使用“ Supplier界面完成相同的操作:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM