为啥我会在这里收到类型安全警告? (泛型)

Posted

技术标签:

【中文标题】为啥我会在这里收到类型安全警告? (泛型)【英文标题】:Why do I get a Type safety warning here? (generics)为什么我会在这里收到类型安全警告? (泛型) 【发布时间】:2011-03-25 13:30:57 【问题描述】:

我最近想了解更多有关泛型方法的信息并创建了几个示例,但我不清楚以下类型安全性。举个例子:

public class GeneralMethod

  public static void main( String[] args )
  
    Repository rep = new Repository();

    Set<ConcreteObject> set = rep.getObject();
  



abstract class AbstractRepository

  public abstract <T extends SuperObject> Set<T> getObject();



class Repository extends AbstractRepository

  @Override
  public Set<ConcreteObject> getObject() //<- Type safety!
  
    return new HashSet<ConcreteObject>();
  


abstract class SuperObject




class ConcreteObject extends SuperObject



在 Eclipse 中 Repository.class 出现以下类型安全:

Type safety: The return type Set &lt; ConcreteObject &gt; for getObject() from the type Repository needs checked conversion to conform to Set &lt; SuperObject &gt; from the type AbstractRepository

为什么编译器要符合Set &lt; SuperObject &gt; instead of Set &lt; T extends Superobject &gt;

你会如何告诉每个 Repository 用自己的类型实现 getObject() 方法,并且只在方法签名中使用泛型? (意思是没有在类签名中定义泛型)。

谢谢你, 梅内

【问题讨论】:

【参考方案1】:

你会如何告诉每个 Repository 用自己的类型实现一个 getObject() 方法,只在方法签名中使用泛型? (意思是没有在类签名中定义泛型)。

你不能。当您说“它是自己的类型”时,您指的是 Repository 子类的泛型类型 - 除非您正在执行类似 FooRepository extends AbstractRepository&lt;Foo&gt; 的操作,否则它不存在。

在这种情况下,我会简单地将抽象类设为泛型:

public abstract class AbstractRepository<T extends SuperObject>
      abstract Set<T> getObjects();

顺便说一句,没有非抽象方法的抽象类可能更好地设计为接口。

【讨论】:

Idd,在没有泛型类的情况下尝试它的原因是,真正的抽象类已经有两个泛型,所以我不会为单个方法添加第三个,因为它可能会混淆更多比它有帮助。也许我只需要重新考虑该方法的当前类设计。谢谢!【参考方案2】:
class AbstractRepository

  Set<? extends SuperObject> getObject();


class Repository extends AbstractRepository

  Set<    ConcreteObject   > getObject()

这是因为Set&lt;ConcreteObject&gt;Set&lt;? extends SuperObject&gt; 的子类型

另见Overriding method with generic return type

【讨论】:

对不起,我的回复晚了,但谢谢。这正是我想要的!【参考方案3】:
AbstractRepository repository = new Repository();
Set<SuperObject> set = repository.getObject();

这应该可以编译,但您会将Set&lt;ConcreteObject&gt; 分配给Set&lt;SuperObject&gt; 变量。

返回Set&lt;? extends SuperObject&gt; 应该编译[未测试]。您可能希望使基类通用(或根本不返回集合)。

【讨论】:

示例已经编译。我只是不太清楚,为什么会有警告。 Idd 更好的解决方案可能是使基类通用。只是想避免它,因为原始基类已经有两个泛型。 编译,我的意思是编译没有警告。【参考方案4】:

“为什么编译器要符合Set而不是Set?”

因为你是这么告诉他的! 毕竟,可以替代 T 的最少类型是 Superobject。

【讨论】:

哦,好的,我不太清楚,谢谢。我以为这样我会告诉编译器我明确想要一个扩展 SuperObject 的类。【参考方案5】:

T extends SuperObjectT 绑定到extends(是SuperObject 的子类)的任何类。您正在覆盖 AbstractRepository.getObject() 方法,因此方法签名必须与其父类相同。

这应该是有效的(未经测试)

class Repository extends AbstractRepository

  @Override
  public Set<T extends SuperObject> getObject() //Valid
  
    return new HashSet<ConcreteObject>();
  

【讨论】:

不幸的是它无效,因为你不能在方法返回类型中使用'T extends xxx'。但感谢您的努力。 @ymene,不幸的是,您的代码就是这样设置的。如果你想知道具体的返回类型,你可以让你的类通用。

以上是关于为啥我会在这里收到类型安全警告? (泛型)的主要内容,如果未能解决你的问题,请参考以下文章

为啥我会收到来自 FxCop 的 InitializeReferenceTypeStaticFieldsInline 警告?

为啥我会收到 JDBC 驱动程序警告和 ThreadLocal 错误?

为啥我会收到带有 std::bind() 的“本地临时返回地址”警告?

为啥在 C# 10 中我会在初始化属性上收到编译器警告/错误 CS8618

为啥我会收到“从未使用过的参数 [E0392]”?

为啥我会收到警告:当 mysql-python 安装成功时,找不到与“MANIFEST”、“ChangeLog”、“GPL”匹配的文件