错误:不兼容的类型:Collection <db_account>无法转换为Collection <account>

时间:2015-08-02 21:27:32

标签: java generics unchecked incompatibletypeerror

以下内容给出了此错误:

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();
        ...
    }
}

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

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

2 个答案:

答案 0 :(得分:1)

问题是你试图将Collection<DB_Account>作为Collection<Account>返回编译器不会让你。 Collection不是协变的,因此Collection<DB_Account>不是Collection<Account>的子类型。

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

Collection<? extends Account> values();

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

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

这会使用正确的参数类型(values())创建Collection<Account>的不可修改的视图。它为您提供额外的安全性(在运行时),您的Cache无法通过客户端代码进行修改。 values()会返回Cache地图的视图,因此呼叫getAccounts()的人对其进行的每次更改都会反映在Cache上。这是你通常想要避免的事情。

答案 1 :(得分:0)

首先看一下错误。这是说:

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

这是完全正确和预期的。

  • 对于超类型X
  • 子类型Y
  • Foo<Y> 不是Foo<X>
  • 的子类型

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

可能的解决方案

如果不了解确切的背景,很难提出解决方案。如果您能够更改Database界面,一种可能的方法是更改​​getAccounts以使用通配符

public Collection<? extends Account> getAccounts();

然而,这只会让你从退回的Collection中获取项目,而不是将它们设置为它(也许这就是你想要的)。要了解您应该阅读"Upper Bounded Wildcards""Guidelines for Wildcard Use"的原因。