28

私は Java の一般的な機能を勉強していますが、次のmainメソッドの 3 行目をどのように説明すればよいかわかりません。

public class Example4 {
    public static void main(final String[] args) {
        System.out.println(Util.<String>compare("a", "b"));
        System.out.println(Util.<String>compare(new String(""), new Long(1)));
        System.out.println(Util.compare(new String(""), new Long(1)));
    }
}

class Util {
    public static <T> boolean compare(T t1, T t2) {
        return t1.equals(t2);
    }
}

最初の行は、(予想どおり) コンパイル、実行、および戻りますfalse

Stringと を明示的に混合しているため、2 行目は期待どおりにコンパイルされませんLong

3 行目はコンパイル、実行、および false を返しますが、それがどのように機能するのかよくわかりません: コンパイラ/JVM はパラメーターの型Tを としてインスタンス化しますObjectか? (また、この宣言された型のTランタイムを取得する方法はありますか?)

ありがとうございました。

4

3 に答える 3

21

Stringとの共有継承型Longは ですObject

この関数を実行するとUtil.<String>compare(、コンパイラは 2 つの文字列入力を期待し、見つからない場合はエラーを返します。ただし、これを実行せずに実行<String>すると、最も近い共有継承型 (この場合はObject.

したがって、 と をcompare受け入れるt1t2、それらは としてキャストされObject、コードは正常に実行されます。

実行時に実際の型を取得するには、他のオブジェクトで使用するのと同じ手法を使用します。getClass()これはObjectクラスから継承されます。

于 2013-04-08T08:52:13.563 に答える
11

答えは@Telthienと@newacctの答えを超えているようです。私は次の違いを自分で「見る」ことに興味がありました。

System.out.println(Util.<String>compare("a", "b"));

明示的な入力、および:

System.out.println(Util.compare(new String(""), new Long(1)));

暗黙の型付けで。

これら 2 つの前の行のバリエーションを使用して、いくつかの実験を行いました。これらの実験は、匿名/ローカル クラス トリックを使用しない限り、コンパイラはコンパイル中に型をチェックしますが、生成されたバイトコードObjectは最初の行の場合でも のみを参照することを示しています。

Object次のコードは、明示的な型引数の場合でも、型キャストを安全に実行できることを示しています<String>

public final class Example44 {
    public static void main(final String[] args) {
        System.out.println(new Util44<String>().compare("a", "b"));
        System.out.println(new Util44().compare(new String(""), new Long(1)));
    }
}

final class Util44<T> {
    private T aT;
    public boolean compare(T t1, T t2) {
        System.out.println(this.aT);
        // I was expecting the second and third assignments to fail
        // with the first invocation because T is explicitly a String
        // and then to work with the second invocation because I use
        // a raw type and the compiler must infer a common type for T.
        // Actually, all these assignments succeed with both invocation. 
        this.aT = (T) new String("z");
        this.aT = (T) new Long(0);
        this.aT = (T) new Object();
        return t1.equals(t2);
    }
}

メソッドのバイトコードは次のmainようになります。

  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 7, Locals: 1
  public static void main(java.lang.String[] args);
     0  getstatic java.lang.System.out : java.io.PrintStream [16]
     3  new ca.polymtl.ptidej.generics.java.Util44 [22]
     6  dup
     7  invokespecial ca.polymtl.ptidej.generics.java.Util44() [24]
    10  ldc <String "a"> [25]
    12  ldc <String "b"> [27]
    14  invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29]
    17  invokevirtual java.io.PrintStream.println(boolean) : void [33]
    20  getstatic java.lang.System.out : java.io.PrintStream [16]
    23  new ca.polymtl.ptidej.generics.java.Util44 [22]
    26  dup
    27  invokespecial ca.polymtl.ptidej.generics.java.Util44() [24]
    30  new java.lang.String [39]
    33  dup
    34  ldc <String ""> [41]
    36  invokespecial java.lang.String(java.lang.String) [43]
    39  new java.lang.Long [46]
    42  dup
    43  lconst_1
    44  invokespecial java.lang.Long(long) [48]
    47  invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29]
    50  invokevirtual java.io.PrintStream.println(boolean) : void [33]
    53  return
      Line numbers:
        [pc: 0, line: 24]
        [pc: 20, line: 25]
        [pc: 53, line: 26]
      Local variable table:
        [pc: 0, pc: 54] local: args index: 0 type: java.lang.String[]

別の質問/回答でObject説明されているように、すべての呼び出しが常に正式なパラメーター型を持つメソッドに対するものであることは実際には理にかなっています。結論として、明示的な型引数 (最初の行) または暗黙的な型引数があるかどうかに関係なく、コンパイラは生成されたバイトコードに常に を使用しますが、オブジェクトは とは異なる共通のスーパークラスを持つことができます。ObjectObject

于 2013-04-15T07:54:40.920 に答える
2

はい、コンパイルできるようにするためObjectの選択です。T概念的には、コンパイラはの型を推測Tします。特に何を推測するかは問題ではありません。何らかの型が で機能すると推測できる限り、Tコンパイルされます。コンパイルされたコードには影響しないため、推論された型が何であるかは問題ではありません。

于 2013-04-08T20:27:48.773 に答える