Melewati argumen byte ke metode kelebihan beban

12

Saya mengambil potongan kode ini dari beberapa kuis, menggunakan IDE saya mengeksekusinya dan mendapatkan hasil yang lama, lama tetapi jawaban yang benar adalah Byte, Byte , mengapa saya mendapat hasil yang berbeda? Pertanyaannya terkait dengan JDK 11

public class Client {
    static void doCalc(byte... a) {
        System.out.print("byte...");
    }

    static void doCalc(long a, long b) {
        System.out.print("long, long");
    }

    static void doCalc(Byte s1, Byte s2) {
        System.out.print("Byte, Byte");
    }

    public static void main(String[] args) {
        byte b = 5;
        doCalc(b, b);
    }
}

Diedit:

Kode diambil di sini: Tinjauan Sertifikasi Oracle dan Contoh Pertanyaan (Halaman: 13, Pertanyaan: 5)

kbo
sumber
1
Apakah Anda yakin itu bukan Byte b = 5;dengan huruf kapital B.
Joop Eggen
4
Saya long, longmenggunakan Java8 terlalu FYI ... Tidak yakin mengapa harus jujur, menunggu jawaban juga :)
sp00m
Kemungkinan rangkap dari Metode Java Overloading dengan Boxing / Widening
Pavel Smirnov

Jawaban:

6

Jadi, jika Anda pergi melalui spesifikasi bahasa Jawa untuk menentukan tanda tangan metode pada waktu kompilasi, akan menjadi jelas:

  1. Fase pertama (§15.12.2.2) melakukan resolusi kelebihan tanpa mengizinkan konversi tinju atau unboxing atau penggunaan pemanggilan metode arity variabel. Jika tidak ada metode yang berlaku ditemukan selama fase ini maka pemrosesan berlanjut ke fase kedua.

  2. Fase kedua (§15.12.2.3) melakukan resolusi kelebihan sementara membiarkan tinju dan unboxing, tetapi masih menghalangi penggunaan pemanggilan metode arity variabel. Jika tidak ada metode yang berlaku ditemukan selama fase ini maka pemrosesan berlanjut ke fase ketiga.

  3. Fase ketiga (§15.12.2.4) memungkinkan kelebihan beban untuk dikombinasikan dengan metode arity variabel, tinju, dan unboxing.

Jadi, dari langkah-langkah di atas, jelas bahwa dalam kasus Anda pada kompiler Java fase pertama akan menemukan metode yang cocok yang tidak doCalc(long a,long b). Metode Anda doCalc(Byte s1, Byte s2)membutuhkan autoboxing selama panggilan sehingga kurang mendapat preferensi.

Amit Bera
sumber
1
Mengenai alasan longmenerima byte, tampaknya mengikuti konversi primitif pelebaran : docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 . Jadi pada dasarnya, +widening -boxing -varargsmaka +widening +boxing -varargskemudian +widening +boxing +varargs.
sp00m
@ kbo Mengapa menurut Anda jawaban yang benar adalah Byte, Byte?
Amit Bera
3
@ kbo Saya kira jawaban yang benar salah :) Mungkin layak menunjuk penulis ke pertanyaan ini jika Anda bisa.
sp00m
3
@ sp00m Saya menemukan pertanyaan ini dalam sampel Oracle, silakan lihat bagian yang diedit
kbo
@ kbo Wow ... Tidak tahu bagaimana melanjutkannya!
sp00m
2

Silakan baca bab JLS tentang konversi .

Apa yang terjadi dalam kasus Anda adalah bahwa selama runtime, JVM memilih untuk melakukan konversi pelebaran byte -> long karena ini adalah konversi yang lebih aman karena dijamin tidak menyebabkannya RuntimeException.

Mengubah dari bytemenjadi Bytejuga disebut tinju dapat mengakibatkan OutOfMemoryError karena JVM harus mengalokasikan objek baru ke tumpukan:

Konversi tinju dapat menghasilkan OutOfMemoryError jika turunan baru dari salah satu kelas pembungkus (Boolean, Byte, Character, Short, Integer, Long, Float, atau Double) perlu dialokasikan dan penyimpanan yang kurang tersedia.

Karena itu, byte -> long konversi pelebaran yang lebih aman lebih disukai.

diginoise
sumber
2
Sebagai catatan, tinju dari bytemenjadi Bytetidak pernah menyebabkan OutOfMemoryException, karena semua nilai Byte(-128 - 127) di-cache secara internal. Tetapi mungkin tidak sama dengan jenis lain, sehingga sebagai aturan praktis, pelebaran konversi mendapat prioritas.
Pavel Smirnov
1

Untuk menemukan kelebihan beban yang benar, urutannya adalah:

  1. dengan jumlah parameter
  2. tinju / unboxing
  3. parameter variadik

Begitu

  • Jika di bmana Bytehasilnya akan Byte, Byte.
  • Jika lulus akan menjadi new byte[] { b, b }hasilnya byte, byte.
  • Jika melewati dua byte b, pelebaran dari byte ke int ke panjang dimungkinkan dan hasilnya adalah long, long.
  • Ketika lama, kelebihan yang lama dihilangkan, Byte, Bytehasilnya.
Joop Eggen
sumber