1

学習のためだけに、このクラスがあります。

public class MyClass{ //Looking for a solution without making my class also generic <Type>  

    //Private Arraylist var to hold the value called myvar 

   public MyClass(ArrayList<MyDesiredType> incoming) {
        //CODE   myVar=incoming  
    }

    public MyDesiredType getType() {
        return myVar.get(0);
    }   
}

コンストラクターからメソッドの戻り値の型に着信オブジェクトを推論する方法はありますか? そうでない場合、これがコンパイラにとって実行可能ではないと考える必要があるのはなぜですか?

これは私がすでに行った再定式化された質問ですが、それは私の最初の質問であり、誰も理解していなかったので、それを明確に明らかにする方法を学びました. 元の質問を後で編集しようとしましたが、すべてが埋もれていました。例を変更して単純化し、簡単にしようとしました。元の質問: Java Generics Silly Thing (型を推測できないのはなぜですか?) .

問題がある場合は、私に言ってください。削除します。

4

5 に答える 5

8

いいえ、ありません。コンパイラはどの型を返すかをどのように知るのでしょうか? コンストラクター内の ArrayList のジェネリック型は、コンパイル時には認識されません。クラス全体をジェネリックにするか、別のアプローチを取る必要があります。

このことを考慮:

public class Test {
    public static void main(String[] args) {
        List<String> arrList = new ArrayList<String>();
        arrList.add("FOO");
        Test test = new Test(arrList);
        String testStr = test.returnWhat();
        System.out.println("testStr");
    }

    private final List myList; //warning

    public <T> Test(List<T> ttype) {
        myList = ttype;
    }

    public <T> T returnWhat() {
        return (T) myList.get(0); //warning
    }
}

これは機能しますが、マークされた行に警告が表示されます。したがって、クラス全体をジェネリックにすることなく、説明していることを達成する方法は実際にはありません。なぜなら、次の場合:

public class Test {


 public static void main(String[] args) {
        List<String> arrList = new ArrayList<String>();
        arrList.add("FOO");
        Test test = new Test(); // now what?
        String testStr = test.returnWhat(0); // no warning...
        JPanel p = test.returnWhat(0); // goes through without warning, real nice...
        test.returnWhat(0); // returns Object

        Test test2 = new Test(arrList);
        test2.addElement(new Object()); // boom, inserted object into list of string.
        String nono = test2.returnWhat(1); // the universe goes down. assign an object to string without warning. even
                                           // though one COULD think the class is generic.
    }

    // private List<T> myList = new ArrayList<T>(); compiler error, T is unknown
    private List myList = new ArrayList();

    public Test() {
        myList.add(new Object());
    }

    public <T> Test(List<T> ttype) {
        myList = ttype;
    }

    public <T> T returnWhat(int index) {
        return (T) myList.get(index);
    }

    public <T> void addElement(T el) {
        myList.add(el);
    }
}

2 番目のものは、myList がジェネリックになるとコンパイルされません。デフォルトのコンストラクターが使用されている場合、コンパイラーはどのようにして <T> の型を判別できますか?

さらに、これにより、特定のタイプのみが挿入されるという事実に依存するコレクション内のオブジェクトで深刻な問題が発生する可能性があります。

これにより、次の例外が生成されます。

Exception in thread "main" java.lang.ClassCastException:
java.lang.Object cannot be cast to java.lang.String     at
Test.main(Test.java:27)

私はあなたを納得させることができましたか?

本当にいい質問ですね。私はこれについてかなり考えなければなりませんでした。

于 2012-04-26T15:52:40.090 に答える
2

getType()コンパイラーに「コンストラクターからの着信オブジェクトを、警告やキャストを行わず、型安全性を失うことなく、メソッドの戻り値の型に推論する」ようにすると言うとき、入力からの結果を推論する必要があると言っているようです。コンストラクタの。両方が同じ関数で発生する場合は、発生する可能性があります。問題は、オブジェクトが 1 つの関数だけに存在するわけではないため、関数間でこの種のオブジェクトを渡すには、追加の型情報 (ジェネリック型) が必要になることです。

たとえば、MyClassオブジェクトを受け取る関数を作成する場合、戻り値を使用できるように、何getType()が返されるかを知る必要があります。のジェネリック型を追加することMyClassで、それが何を保持しているかを説明しています。

それを見る別の方法は、それがMyClassコンテナです。ジェネリックを追加することで、特定の種類のもののコンテナーであると言えます。そのため、そこから何が得られるかをより簡単に予測できます。

于 2012-04-26T15:59:36.500 に答える
1

コンパイラが実行時に配列リストの型を知る方法はありません。私は本当にこれに沿って何かを使用して問題を見ていません:

 public class MyClass<TYPE> {
     private ArrayList<TYPE> incoming;

     public MyClass(ArrayList<TYPE> incoming) {
         this.incoming = incoming;
     }

     public TYPE getType() {
         return incoming.get(0);
     }
 }

このようにして、次のことができます。

ArrayList<Integer> numbers = createListOfNumbers();
MyClass<Integer> myClass = new MyClass<>(numbers);
Integer number = myClass.getType();

または、質問を誤解していて、実行時にクラスを知りたいですか?

于 2012-04-26T15:54:43.857 に答える
0

いいえ、パラメーター化された型のリストを保持できるクラスが必要な場合。

はい、ちょうど 1 つのタイプのリストを保持できるクラスが必要な場合。その型は、フィールド、コンストラクター、およびアクセサーで明示的に宣言できます。

于 2012-04-26T15:50:52.060 に答える
0

あなたが忘れているのは、実行する可能性のあるすべてのコードがコンパイラーに見えるわけではないということです! jar は、実行時に追加、削除、置換することができますが、コンパイラーには表示されませんでした。次のようなインターフェイスに対してコンパイルできます。

public interface MyClassFactory {
  MyClass getInstance();
}

次に、実行時に JVM に実装を提供します。そのため、コンパイラは、使用する MyClass を作成する実際のコードを見たことがないため、そのようなコンパイル時の推論を実行する方法はありません。クラスをジェネリックにするか、タイプ セーフがないことを受け入れる必要があります。

于 2012-04-26T15:51:20.233 に答える