Java 中的 C# IEnumerable 相当于什么?协变能力,而不是可迭代的

2022-09-03 14:52:29

此协方差在 C# 中是可能的:

IEnumerable<A> a = new List<A>();
IEnumerable<B> b = new List<B>();

a = b;

...

class A {
}

class B : A {
}

这在Java中是不可能的:(可迭代:在这个问题中看到Java Arrays和Generatives:Java相当于C# IEnumerable<T>)。

Iterable<A> a = new ArrayList<A>();
Iterable<B> b = new ArrayList<B>();

a = b;

...

class A {
}

class B extends A {
}

使用Iterable,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 {}

答案 1

Java 泛型仅当通过通配符显式声明时才允许协方差,以便提供更严格的类型安全性。这有效:

    Iterable<? extends A> a = new ArrayList<A>();
    Iterable<B> b = new ArrayList<B>();
    a = b;

但是,请注意,您现在无法通过引用添加任何内容,因为它被声明为包含某些特定但未知类的实例,这些类可能是A或其任何子类。通配符的行为通常是违反直觉的,并且可能会变得非常复杂,因此应适度使用它们。a


答案 2

泛型在Java中不是协变的。你必须以旧的方式做到这一点,就像C#不支持泛型中的协方差一样。

但是,在Java中,您可以假装通用可迭代是任何内容的可迭代对象,用问号表示。任何内容的列表仅包含对象。

Iterable<A> a = new ArrayList<A>();
Iterable<?> b = a;

推荐