【问题标题】:How to make a Java interface that extends Iterable with two different generic types?如何制作一个使用两种不同泛型类型扩展 Iterable 的 Java 接口?
【发布时间】:2013-06-06 18:59:20
【问题描述】:

理想情况下,它看起来像这样(上下文无关紧要):

public interface myInterface extends Iterable<Point>, Iterable<Segment> { ... }

但这在 Java 中是不允许的。我怎样才能实现这种行为?

【问题讨论】:

标签: java generics interface


【解决方案1】:

很遗憾您不能。在 Java 中,您不能有两种具有以下签名的方法:

Iterator<Point> iterator();
Iterator<Segment> iterator();

在一个类或接口中。

【讨论】:

  • 如果其中一个 iterator() 方法有参数怎么办?
  • 例如Comparable&lt;Number&gt;, Comparable&lt;String&gt; 它也不起作用,因为它会两次违反实现接口,请参阅@fge 答案。实际上我展示了两次实现接口的后果,
  • 不知道你能不能有这个:Iterator iterator();迭代器 迭代器(int i);从现在起签名不同了。
  • 是的,那些方法签名是不同的,因为参数。
  • @user2460978 它将实现 Iterable,因为 Iterator iterator(int i) 不是 Iterable 接口的一部分。
【解决方案2】:

正如其他人之前所说,这是不可能的。更好地使用委托而不是像这样的多个实现:

public interface MyInterface {
  Iterable<Point> points();
  Iterable<Segment> segments();
}

所以你可以使用 for 进行迭代:

MyInterface my = ...;
for (Point p : my.points()) {
  ...
}
for (Segment s : my.segments()) {
  ...
}

【讨论】:

    【解决方案3】:

    你不能。由于类型擦除,在字节码中,因此在运行时,Iterable&lt;Whatever&gt; 变为 Iterable

    因此,在运行时,您的类的原型将是:

    public interface myInterface extends Iterable, Iterable { ... }
    

    考虑到这一点,您如何确定要迭代的类?

    【讨论】:

      【解决方案4】:

      作为一种可能的解决方法,您可以为所需的迭代创建接口。

      public interface SegmentIterable{
          public Iterator<Segment> segmentIterator();
      }
      
      public interface PointIterable{
          public Iterator<Point> pointIterator();
      }
      

      这并不理想,但只要您想要迭代的东西数量有限,就可以通过。

      【讨论】:

      • 我猜他想要多态性,这如何提供,你仍然有两种不同的类型(更多的是混乱而不是批评)。
      • 这允许他拥有一个实现多个迭代器的类,因为它们具有不同的方法名称。它不允许他使用多态性,因为不允许具有不同返回类型的相同方法签名
      • 这没什么用。它不会在豪华的 for 循环或任何合理的方法中工作。
      • 虽然不太理想,但考虑到他想做的事情,它会起作用,而且你总是可以使用好看的while (iter.hasNext())
      【解决方案5】:

      其他人说这是不可能的。他们错了。这是可能的,但可能不是你想要的。

      public interface MyInterface<T extends Point & Segment> extends Iterable<T>
      {
      }
      

      如果您正在迭代的内容同时扩展了点和段,这将起作用。否则类型擦除意味着这将不起作用。

      【讨论】:

      • 这里T的类型擦除只是Point,而不是PointSegment的组合。引用 Angelika Langer 的泛型常见问题解答:“类型擦除。最左边的上限用于类型擦除并替换字节码中的类型参数。”所以,在运行时,你有一个Iterable&lt;Point&gt;
      • 在运行时,MyInterface 只会被视为Iterable&lt;Point&gt;
      • 从逻辑上思考这个问题:PointSegment是什么?这真的没有意义。
      • @WChargin,如果我们在谈论几何,那么长度为零的线段也将是一个点。我认为这样的概念没有用,但 OP 并没有具体说明。所以我会假设它在他/她的领域很有用。
      【解决方案6】:

      http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.5

      一个类不能同时是两个接口类型的子类型,这两种接口类型是同一个泛型接口(第 9.1.2 节)的不同调用,或者是泛型接口调用的子类型和命名为相同的通用接口,或发生编译时错误。

      【讨论】:

        【解决方案7】:

        不要从可迭代类型继承,而是尝试这样的事情:

        public interface MyInterface {
            public Iterable<Point> asPoints() { ... }
            public Iterable<Segment> asSegments() { ... }
        }
        

        那么当你想要迭代时,只需:

        for (Point p : myClass.asPoints()) {
            ...
        }
        

        这是一种非常常见的做法,如 Java Collections 类中所见。

        【讨论】:

        • 糟糕,上面没有看到 Arne Burmeister 的回答,它遵循相同的基本模式。
        【解决方案8】:

        您还可以考虑为 Point 和 Segment 创建通用接口、超类或包装器,并将其用作通用参数。

        【讨论】:

          猜你喜欢
          • 2019-04-06
          • 2018-07-13
          • 2021-10-09
          • 2010-11-20
          • 2019-04-07
          • 1970-01-01
          • 2023-02-21
          • 1970-01-01
          • 2018-01-10
          相关资源
          最近更新 更多