4
public class GenericClass<T> {

    class MyClass {
    }

    public GenericClass(final T[] param) {
        MyClass myObject = new MyClass();                       // OK
        MyClass[] myArray = { new MyClass(), new MyClass() };   // Cannot create a generic array of GenericClass<T>.MyClass
    }
}

これは汎用配列を作成していません。コンパイラは を理解/決定するのMyClassに問題はないはずですよね?

4

6 に答える 6

2

内部クラスは、囲んでいるクラスのどのインスタンスがそれらを作成したかを「認識」しており、このインスタンスのフィールド/メンバーにアクセスできます。これは、それらをthis囲むクラスの具象型 ( などGenericClass<String>) を型とする 2 番目の変数があるかのようです。

この苦境を克服するには、MyClass static. これにより、囲んでいるクラスのインスタンスが完全に分離され (つまり、その secondthisがなくなります)、自由にインスタンス化できるようになります。

public class GenericClass<T> {

  static class MyClass {
  }

  public GenericClass(final T[] param) {
    MyClass myObject = new MyClass();                       // OK
    MyClass[] myArray = { new MyClass(), new MyClass() };   
  }
}
于 2013-07-20T06:29:06.380 に答える
1

これをカバーする JLS セクションは10.6です。具体的には、次の理由によります。

ClassOrInterfaceType が具体化可能な型を示さない場合、コンパイル時エラーになります (§4.7)。それ以外の場合、ClassOrInterfaceType は、抽象クラス型 (§8.1.1.1) またはインターフェイス型 (§9) であっても、任意の名前付き参照型に名前を付けることができます。

上記の規則は、配列作成式の要素の型が、無制限のワイルドカード以外のパラメーター化された型であってはならないことを意味します。

MyClass非静的であるため、外部クラスに依存しています。それは実際にGenericClass<T>.MyClassはパラメータ化された型です。それを宣言staticすると、その依存関係が削除され、問題が解決されます。

奇妙なのは、これを行う場合です。

class MyClass<T> {
}

public GenericClass(final T[] param) {
    MyClass[] myArray = { new MyClass(), new MyClass() };  
}

それは合法です。ずさんで不器用ですが、合法です。型を再宣言するため、外側の型が隠されます。次に...配列とジェネリックは混在しません...生の型を使用しない限り。下位互換性のために、最終的に を保持する rawtype 配列を持つことができますMyClass<Object>。それは本当にひどいことですが、コンパイルします。ここでクリエイティブなキャスティングを回避できますが、最終的には... ただ...しないでください。

于 2013-07-20T06:48:03.880 に答える
1
{ new MyClass(), new MyClass() }; //new MyClass() => new GenericClass<T>.MyClass()

上記のコードは、T が不明であるため、オブジェクトの配列として扱われます。これは、ジェネリックが (消去によって) 実装されているため、配列の型が明確に定義されていないためです。一方では MyClass の配列である必要があり、他方では Object の配列である必要があります

オブジェクト型の配列を作成し、それを型にキャストします

Object[] arr=new Object[]{this.new MyClass(), this.new MyClass()};
MyClass[]  myArray = Arrays.copyOf(arr,arr.length, Item.MyClass[].class);   

静的にすると機能します -静的なネストされたクラスまたはネストされたインターフェイス(ちなみに、常に静的です)は、名前空間のネストとプライベート変数へのアクセスを除いて、外部クラス(またはインターフェイス)とは関係がありません。標準 API の例として、インターフェイス Map 内にネストされたインターフェイス Map.Entry を探しますが、その型パラメーターにはアクセスできず、再度宣言する必要があります。

于 2013-07-20T06:24:42.957 に答える
1

追加情報を次に示します。リンクから...

Java 配列は、含まれる要素の型を識別する実行時の型情報を保持します。

コンパイラにとって、コードは次のようになります。

MyClass[] myArray = {new GenericClass<T>.MyClass(), ..} //T is unknown
于 2013-07-20T05:40:16.617 に答える
0

@ItayMamanには正しい理由があります。基本的に、refiable 型でMyClassはありません。

MyClass非静的内部クラスです。非静的であるため、それを囲むクラスの型パラメーターのスコープ内にあります。MyClassまた、 のインスタンス メソッドで単独で記述するたびにGenericClass、実際には の略ですGenericClass<T>.MyClass。そのため、見た目には見えないかもしれませんが、 (それ自体で) は実際にはに似たMyClass( によってパラメータ化された) パラメータ化された型TList<String>です。そのため、のようnew MyClass[2]に、パラメータ化された型の配列を作成しようとしていますnew List<String>[2]。そして、これが許可されていないことはすでにご存じだと思います。

あなたは何をするべきか?それはすべてあなたの意図にかかっています。人々が提案していることの 1 つは、MyClass静的にすることです。もちろん、それは の範囲外になりTます。しかし、それは との関係を完全に変えるので、あなたが望むものかもしれませんし、そうでないかもしれませんGenericClass。非静的内部クラスは、囲んでいるクラスのインスタンスにアクセスできます。これがおそらく、そもそもそのようにした理由です。非静的であることを意図していなかった場合 (そして誤って非静的にした場合)、これは明らかに進むべき道です。

非静的内部クラスが必要であり、単にこの型の配列を作成したい場合は、パラメータ化された型の配列を通常どのように処理するかを考えてみましょうList<String>[]

  • 1 つの解決策は、代わりに生の型の配列を作成することList[] foo = new List[2];です。このケースでこれを行う同等の方法は、 ですGenericClass.MyClass[] foo = new GenericClass.MyClass[2];。ここで行ったことに注目してください。生の型を記述するには、パラメータ化されていない外部クラス名で明示的に修飾する必要MyClassありました。明示的に修飾しなかった場合、上で説明したように暗黙的に で修飾されますが、これは私たちが望んでいるものではありません。これをあなたの例のコードに翻訳すると、次のようになりますGenericClass<T>GenericClass.MyClass[] myArray = { new MyClass(), new MyClass() };

  • 同様に、生の型を避けたい場合は、ワイルドカード型の配列を作成できますList<?>[] foo = new List<?>[2];。このケースでこれを行う同等の方法は、 ですGenericClass<?>.MyClass[] foo = new GenericClass<?>.MyClass[2];。これをあなたの例のコードに翻訳すると、次のようになりますGenericClass<?>.MyClass[] myArray = { new MyClass(), new MyClass() };

  • 最後に、代わりにワイルドカード型の配列を作成したいかもしれませんが、後で便利に使用できるように、パラメーター化された型の配列にキャストし直します。例えばList<String>[] foo = (List<String>[])new List<?>[2];。このケースでこれを行う同等の方法は、 ですMyClass[] myArray = (MyClass[])new GenericClass<?>.MyClass[] { new MyClass(), new MyClass() };。キャストは未チェックのキャストであることに注意してください。これの利点は、 から物事を取得するときに、上記のメソッドの生の型またはワイルドカード型の代わりにmyArraytype になることです。MyClassGenericClass.MyClassGenericClass<?>.MyClass

于 2013-07-22T08:08:17.190 に答える