これは本当にワイドニング対オートボクシングなのでしょうか?

StackOverflow https://stackoverflow.com/questions/4922

  •  08-06-2019
  •  | 
  •  

質問

これを見た 別の質問に対する答え, 、Java 仕様の欠点を参照して:

他にも欠点はありますが、これは微妙なトピックです。チェック これ 外:

public class methodOverloading{
     public static void hello(Integer x){
          System.out.println("Integer");
     }

     public static void hello(long x){
          System.out.println("long");
     }

     public static void main(String[] args){
         int i = 5;
         hello(i);
     }
}

ここでは、コンパイラが自動ボックス化ではなく拡張を選択するため、「long」が出力されます (私自身は確認していません)。自動ボクシングを使用する場合は注意するか、まったく使用しないでください。

これは実際にはオートボクシングではなくワイドニングの一例であると確信していますか、それともまったく別のものなのでしょうか?

最初のスキャンでは、出力が「長い」という意見に同意します。 i オブジェクトではなくプリミティブとして宣言されています。ただし、変更した場合は、

hello(long x)

hello(Long x)

出力には「Integer」が表示されます

ここで実際に何が起こっているのでしょうか?Javaのコンパイラ/バイトコードインタープリタについては何も知りません...

役に立ちましたか?

解決

最初のケースでは、拡大変換が発生します。これは、コンパイルされたクラスで「javap」ユーティリティ プログラム (JDK に含まれる) を実行すると確認できます。

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   i2l
   4:   invokestatic    #6; //Method hello:(J)V
   7:   return

}

明らかに、Integer-to-Long バイトコード拡張命令のニーモニックである I2L が表示されます。参考資料を参照 ここ.

もう 1 つのケースでは、「long x」をオブジェクトの「Long x」署名に置き換えると、メイン メソッドに次のコードが含まれます。

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   invokestatic    #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   6:   invokestatic    #7; //Method hello:(Ljava/lang/Integer;)V
   9:   return

}

したがって、コンパイラがラッパー内でプリミティブをボックス化する命令 Integer.valueOf(int) を作成したことがわかります。

他のヒント

はい、テストで試してみてください。「long」と印刷されているのが表示されます。これは、Java が int を Integer にオートボックス化する前に int を long に拡張することを選択するため、拡張されています。したがって、 hello(long) メソッドが呼び出されるように選択されます。

編集: 参照されている元の投稿.

さらに編集:2 番目のオプションが Integer を出力する理由は、オプションとしてより大きなプリミティブへの「拡張」がないためです。したがって、それをボックス化する必要があり、したがって Integer が唯一のオプションです。さらに、Java は元の型にオートボックス化するだけなので、hello(Long) を残して hello(Integer) を削除するとコンパイラ エラーが発生します。

この例のもう 1 つの興味深い点は、メソッドのオーバーロードです。型の拡張とメソッドのオーバーロードの組み合わせは、コンパイラがどのメソッドを選択するかを決定する必要があるためのみ機能します。次の例を考えてみましょう。

public static void hello(Collection x){
   System.out.println("Collection");
}

public static void hello(List x){
   System.out.println("List");
}

public static void main(String[] args){
   Collection col = new ArrayList();
   hello(col);
}

List である実行時型は使用せず、Collection であるコンパイル時型を使用するため、「Collection」が出力されます。

ぜひ読んでみてください 効果的なJava, 、これにより、JLS のいくつかの特殊なケースに目が開かれました。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top