【问题标题】:Problem when trying to use generics尝试使用泛型时出现问题
【发布时间】:2011-04-05 06:34:07
【问题描述】:

我有课

public abstract class AbstractE<T, E extends Enum<E> & Flags>
{
     public interface Flags{} /*marker interface*/
     //... 
     //other code
}

还有一个界面

public interface IXYZAdapter
{
   public <E extends Enum<E> & Flags> Set<E> getFlags();
}

Flags 是 AbstractE 本身定义的接口。

M 因而扩展了 AbstractE:

public class M extends AbstractE<Long, M.EF> implements IXYZAdapter
{
    public enum EF implements AbstractE.Flags{flag1, flag2}
    @Override /*from IXYZAdapter*/
    public Set<M.EF> getFlags()
    {return EnumSet.allOf(EF.class);}
    
}

现在,从主代码中,我尝试获取接口 IXYZAdapter 的句柄并调用 getFlags 方法

IXYZAdapter adapter = (IXYZAdapter)m; //where m is an instance of AbstractE
Set s = adapter.getFlags();

我在主程序最后一行得到以下编译时错误(Set s = adapter.getFlags();)

E 的推断类型无效;推断类型不符合声明的边界

inferred: AbstractE.Flags

bound(s): java.lang.Enum<AbstractE.Flags>,AbstractE.Flags

我做错了什么? 我正在使用 Java 6

已编辑以指定错误位置

【问题讨论】:

  • 哪一行触发编译器错误?
  • 当我尝试编译时,行 Set s = adapter.getFlags() - 生成错误
  • return new EnumSet.allOf(EF.class); 应该是什么意思/做什么?
  • 我把EnumSet.allOf前面的“new”关键字去掉了,是那里打错了
  • 还有你的第一行public abstract class AbstractE&lt;T, E extends Enum&lt;E&gt; &amp; Flags&gt; 给了我编译器错误,它必须是public abstract class AbstractE&lt;T, E extends Enum&lt;E&gt; &amp; AbstractE.Flags&gt;。询问此类复杂问题时,请使用复制/粘贴 :)

标签: java generics


【解决方案1】:

试试这个:

public interface IXYZAdapter <E extends Enum<E> & AbstractE.Flags>
{
   public Set<E> getFlags();
}

public class M extends AbstractE<Long, M.EF> implements IXYZAdapter<M.EF> 
{
}

或者

Set<M.EF> s = adapter.getFlags();

问题在于Set s = adapter.getFlags(); 系统不知道要为 IXYZAdapter 中的 E 推断哪种类型,因此 AbstractE 中的 E 不匹配。

编辑:

另一个选项可能是:

interface IXYZAdapter <E extends Enum<E> & AbstractE.Flags>
{
  public Set<? extends E> getFlags();
}

class M extends AbstractE<Long, M.EF> implements IXYZAdapter<M.EF>
{
  public enum EF implements AbstractE.Flags{flag1, flag2}
  public Set<? extends M.EF> getFlags()
  {return EnumSet.allOf(EF.class);}

}

还有电话:Set&lt;? extends AbstractE.Flags&gt; s = adapter.getFlags();

这将允许您在不强制转换的情况下获得一组标志并强制将标志声明为枚举。

【讨论】:

  • 这两种解决方案都要求程序员在调用getFlags时知道枚举类型,否则至少会有警告。
  • 好吧,实际上这不是真的。看你怎么写main方法了:)我举个例子!
【解决方案2】:

使用 thomas 提供的第一个解决方案,main 方法可以这样编写,从而无需实际了解枚举类型

public static void main(String[] args) {
    M m = new M();
    IXYZAdapter<?> adapter = (IXYZAdapter<?>)m;
    Set<?> flags = adapter.getFlags();
    Iterator<?> it = flags.iterator();

    while(it.hasNext()) {
        System.out.println(it.next());
    }
}

【讨论】:

  • 您不会收到警告,但您仍然必须将集合的元素转换为 AbstractE.Flags。在这种情况下,我会将签名更改为Set&lt;? extends AbstractE.Flags&gt; getFlags();,然后调用Set&lt;? extends AbstractE.Flags&gt; s = adapter.getFlags();
  • 您能详细说明一下吗?这段代码运行良好,我得到了枚举的名称以这种方式打印。听起来好像您暗示上面的代码不应该工作。我错过了什么吗?
  • 不,上面的代码有效。但是试试这个:AbstractE.Flags f = it.next();。你必须这样做:AbstractE.Flags f = (AbstractE.Flags)it.next();
猜你喜欢
  • 1970-01-01
  • 2019-09-13
  • 1970-01-01
  • 1970-01-01
  • 2022-10-15
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多