有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中C#IEnumerable的等价物是什么?是可协变的,不是可协变的

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

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

a = b;

...

class A {
}

class B : A {
}

这在Java中是不可能的:(Iterable:见这个问题Java Arrays & Generics : Java Equivalent to 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中哪个iterable/enumerable接口可以促进协方差


另一个很好的协方差示例是,给定上面相同的A类和B类,这在Java和C#上都是允许的:

   A[] x;
   B[] y = new B[10];

   x = y;

从版本1开始,这两种语言都具有此功能。很高兴他们在generics上取得了进展,实现了这一点。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 {}

共 (3) 个答案

  1. # 1 楼答案

    一般集合中的这种协方差是个坏主意,有一个很好的理由:

    假设你这样做:

    ArrayList<A> a = new ArrayList<A>();
    ArrayList<B> b = new ArrayList<B>();
    
    a.add(new A()); 
    b = a;
    B item=b.get(0); 
    

    哎哟-一个只返回类型B的对象的函数返回了类型a。这显然是行不通的。因此Java编译器不允许它,以确保类型安全

    不过这没什么大不了的-简单的解决方法是只使用非泛型集合类或将泛型类型参数限制为公共超类(在本例中为a)

  2. # 2 楼答案

    Java泛型仅在通过通配符显式声明以提供更严格的类型安全性时才允许协变。这项工作:

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

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

  3. # 3 楼答案

    Java中的Generics are not covariant。你必须用老办法,就像C#不支持泛型中的协方差一样

    然而,在Java中,您可以假设泛型iterable是任何的iterable,用问号表示。任何内容的列表只包含对象

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