【问题标题】:error: incompatible types: Collection<DB_Account> cannot be converted to Collection<Account>错误:不兼容的类型:Collection<DB_Account> 无法转换为 Collection<Account>
【发布时间】:2015-08-02 21:27:32
【问题描述】:

以下给出此错误:

public class Account
{
    ...
}

public class DB_Account extends Account implements DBObject
{
    ...
}

public class Cache<E extends DBObject>
{
    protected Map<Long,E> m_contents;

    ...

    public Collection<E> values()
    {
        return m_contents.values();
    }
}

public class DB_Imp implements Database
{
    protected Cache<DB_Account> m_accounts;

    ...

    @Override
    public Collection<Account> getAccounts()
    {
        if (m_accounts.isValid())
            /* Compiler gives error here */
            return m_accounts.values();
        ...
    }
}

我目前通过在对accounts.values() 的调用周围添加Collections.class.cast() 并添加@SuppressWarnings 来解决DB_Imp 类中的编译器错误。肯定有更好的办法。另一种方法是将Cache类修改为:

    @SuppressWarnings("unchecked")
    public <T> Collection<T> values()
    {
        return Collections.class.cast(m_contents.values());
    }

【问题讨论】:

标签: java generics unchecked incompatibletypeerror


【解决方案1】:

问题是您试图将Collection&lt;DB_Account&gt; 作为Collection&lt;Account&gt; 返回,而编译器不会让您这样做。 Collection 不是协变的,所以Collection&lt;DB_Account&gt; 不是Collection&lt;Account&gt; 的子类型。

解决这个问题的方法是将values中的Database方法修改为:

Collection<? extends Account> values();

编辑: 如果你不能做出改变,我会做的是:

@Override
public Collection<Account> getAccounts() {
    if (m_accounts.isValid())
      return Collections.unmodifiableCollection(m_accounts.values());
    ...
}

这将使用正确的参数类型 (Collection&lt;Account&gt;) 创建一个不可修改的 values() 视图。它为您提供了额外的安全性(在运行时),您的Cache 无法被客户端代码修改。 values() 返回 Cache 映射的视图,因此调用 getAccounts() 的人对其所做的每一次更改都会反映在 Cache 上。这是您通常希望避免的事情。

【讨论】:

  • 不幸的是,这将重写现有的库 API
  • 相应地编辑了我的答案
【解决方案2】:

首先看错误。据说:

  • 对于Cache&lt;DB_Account&gt; m_accounts,方法调用m_accounts.values() 返回Collection&lt;DB_Account&gt;
  • Ands getAccounts() 返回 Collection&lt;Account&gt;
  • 但这些不是多态的:Collection&lt;Account&gt; 不是Collection&lt;DB_Account&gt;不是超类型,因此编译器无法转换它们。

这是完全正确和预期的。

  • 对于超类型X
  • 和子类型Y
  • Foo&lt;Y&gt; 不是Foo&lt;X&gt; 的子类型

这是 Java 泛型中的一个关键概念,值得理解。你应该阅读The Java Tutorials > Generics, Inheritance and Subtypes

可能的解决方案

在不了解确切上下文的情况下很难提出解决方案。如果您能够更改Database 接口,一种可能的方法是将getAccounts 更改为使用通配符

public Collection<? extends Account> getAccounts();

但是,这只允许您从返回的Collection 中取出项目,而不是将它们放入其中(也许这就是您想要的)。要了解为什么您应该阅读 "Upper Bounded Wildcards""Guidelines for Wildcard Use"

【讨论】:

    猜你喜欢
    • 2021-04-27
    • 2017-10-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多