Java中的C# IEnumerable相当于什么?协变能力的,而不是可迭代的
本文关键字:迭代 能力 IEnumerable 中的 相当于 什么 Java | 更新日期: 2023-09-27 18:34:37
这种协方差在 C# 中是可能的:
IEnumerable<A> a = new List<A>();
IEnumerable<B> b = new List<B>();
a = b;
...
class A {
}
class B : A {
}
这在Java中是不可能的:(可迭代:在这个问题中看到Java Arrays & Generics:Java等同于C# IEnumerable
Iterable<A> a = new ArrayList<A>();
Iterable<B> b = new ArrayList<B>();
a = b;
...
class A {
}
class B extends A {
}
使用可迭代,Java看不到这两个集合是协方差的。
Java 中哪个可迭代/可枚举接口可以促进协方差?
协方差的另一个很好的例子,给定上面的 A 类和 B 类,这在 Java 和 C# 上都是允许的:
A[] x;
B[] y = new B[10];
x = y;
该功能在版本 1 的两种语言上都有。很高兴他们正在取得进展,使这在泛型上成为现实。C# 在语法方面的摩擦较小。
协方差是所有 OOP 语言的必备条件,否则 OOP 继承将是一个无用的练习,例如
A x;
B y = new B();
x = y;
这种力量也应该扩展到泛型。
感谢大家的回答和见解。现在有一个可重用的方法,现在有一个支持协变的 Java 泛型。这不是我们中的一些人想要的语法,但它(<? extends classHere>
(肯定符合要求:
import java.util.*;
public class Covariance2 {
public static void testList(Iterable<? extends A> men) {
for(A good : men) {
System.out.println("Good : " + good.name);
}
}
public static void main(String[] args) {
System.out.println("The A");
{
List<A> team = new ArrayList<A>();
{ A player = new A(); player.name = "John"; team.add(player); }
{ A player = new A(); player.name = "Paul"; team.add(player); }
testList(team);
}
System.out.println("The B");
{
List<B> bee = new ArrayList<B>();
{ B good = new B(); good.name = "George"; bee.add(good); }
{ B good = new B(); good.name = "Ringo"; bee.add(good); }
testList(bee);
}
}
}
class A { String name; }
class B extends A {}
输出:
The A
Good : John
Good : Paul
The B
Good : George
Good : Ringo
如果有人对它在 C# 中的外观感兴趣
using System.Collections.Generic;
using System.Linq;
public class Covariance2 {
internal static void TestList(IEnumerable<A> men) {
foreach(A good in men) {
System.Console.WriteLine("Good : " + good.name);
}
}
public static void Main(string[] args) {
System.Console.WriteLine("The A");
{
IList<A> team = new List<A>();
{ A player = new A(); player.name = "John"; team.Add(player); }
{ A player = new A(); player.name = "Paul"; team.Add(player); }
TestList(team);
}
System.Console.WriteLine("The A");
{
IList<B> bee = new List<B>();
{ B good = new B(); good.name = "George"; bee.Add(good); }
{ B good = new B(); good.name = "Ringo"; bee.Add(good); }
TestList(bee);
}
}
}
class A { internal string name; }
class B : A {}
Java 泛型只有在通过通配符显式声明时才允许协方差,以提供更严格的类型安全性。这有效:
Iterable<? extends A> a = new ArrayList<A>();
Iterable<B> b = new ArrayList<B>();
a = b;
但是,请注意,您现在无法通过引用a
添加任何内容,因为它声明包含某个特定但未知类的实例,这些类可能是 A 或其任何子类。通配符的行为通常是违反直觉的,并且可能会变得非常复杂,因此应适度使用。
型在Java中不是协变的。您必须以旧方式执行此操作,就像 C# 不支持泛型中的协方差时一样。
但是,在 Java 中,您可以假装通用可迭代对象是任何事物的可迭代对象,用问号表示。任何内容的列表仅包含对象。
Iterable<A> a = new ArrayList<A>();
Iterable<?> b = a;
泛型集合中的这种协方差是一个坏主意是有充分理由的:
假设您执行以下操作:
ArrayList<A> a = new ArrayList<A>();
ArrayList<B> b = new ArrayList<B>();
a.add(new A());
b = a;
B item=b.get(0);
Whoops - 一个旨在仅返回 B 类型的对象的函数已返回类型 A。这显然是行不通的。因此,Java 编译器不允许这样做,以确保类型安全。
不过这没什么大不了的 - 简单的解决方法是只使用非泛型集合类或将泛型类型参数限制为通用超类(在本例中为 A(。