12

この共分散は 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 はこれら 2 つのコレクションが共分散であることを認識しません。

共分散を促進できる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 ジェネリックを使用した再利用可能なメソッドを取得しました。これは私たちの一部が望む構文ではありませんが、 it( <? 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 {}
4

3 に答える 3

12

Java ジェネリックは、より厳密なタイプ セーフを提供するために、ワイルドカードを介して明示的に宣言された場合にのみ共変性を許可します。これは機能します:

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

ただし、 A またはそのサブクラスである可能性がある特定の未知aのクラスのインスタンスを含むと宣言されているため、参照を介して何も追加できないことに注意してください。ワイルドカードの動作は直観に反することが多く、非常に複雑になる可能性があるため、適度に使用する必要があります。

于 2012-05-19T11:50:39.687 に答える
1

ジェネリックはJava では共変ではありません。C# がジェネリックで共分散をサポートしていなかったときのように、古い方法で行う必要があります。

ただし、Java では、一般的な iterable が、疑問符で示されるany の iterable であると見なすことができます。何かのリストには、オブジェクトのみが含まれます。

Iterable<A> a = new ArrayList<A>();
Iterable<?> b = a;
于 2012-05-19T11:23:40.047 に答える
0

ジェネリック コレクションでのこの種の共分散が悪い考えであるのには、十分な理由があります。

次のようにします。

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) に制限することです。

于 2012-05-19T11:37:17.357 に答える