การส่งอาร์กิวเมนต์ไบต์ไปยังเมธอดที่โอเวอร์โหลด


12

ฉันเอาข้อมูลโค้ดนี้จากแบบทดสอบบางส่วนโดยใช้ IDE ฉันดำเนินการแล้วและได้ผลลัพธ์ยาวยาวแต่คำตอบที่ถูกต้องคือByte, Byteทำไมฉันถึงได้ผลลัพธ์ที่แตกต่างกัน? คำถามเกี่ยวข้องกับ 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);
    }
}

แก้ไข:

มีการใช้รหัสที่นี่: ภาพรวมการรับรองของ Oracle และคำถามตัวอย่าง (หน้า: 13, คำถาม: 5)


1
คุณแน่ใจหรือว่าไม่ใช่Byte b = 5;เมืองหลวง B.
— Joop Eggen

4
ฉันlong, longใช้ Java8 ด้วย FYI ... ไม่แน่ใจว่าทำไมถึงต้องซื่อสัตย์รอคำตอบด้วย :)
— sp00m

คำตอบ:


6

ดังนั้นหากคุณทำตามข้อกำหนดภาษาจาวาเพื่อกำหนดลายเซ็นของเมธอด ณ เวลารวบรวมจะมีความชัดเจน:

  1. ในช่วงแรก (§15.12.2.2) ทำการแก้ไขความละเอียดเกินพิกัดโดยไม่อนุญาตให้ใช้การแปลงมวยหรือการแกะกล่องออกหรือการใช้วิธีการแปรผัน arity หากไม่พบวิธีการที่เหมาะสมระหว่างขั้นตอนนี้การประมวลผลจะดำเนินต่อไปยังขั้นตอนที่สอง

  2. ขั้นตอนที่สอง (.1215.12.2.3) ดำเนินการแก้ปัญหาการโอเวอร์โหลดในขณะที่อนุญาตการชกมวยและการเลิกทำกล่อง แต่ยังคงห้ามการใช้วิธีการแปรผันของวิธี arity หากไม่พบวิธีการที่เหมาะสมระหว่างขั้นตอนนี้การประมวลผลจะดำเนินต่อไปยังขั้นตอนที่สาม

  3. ขั้นตอนที่สาม (§15.12.2.4) อนุญาตให้มีการโหลดมากเกินไปที่จะรวมกับวิธี arity แบบต่างๆ, มวยและ unboxing

ดังนั้นจากขั้นตอนข้างต้นก็เป็นที่ชัดเจนว่าในกรณีของคุณในระยะแรก Java doCalc(long a,long b)คอมไพเลอร์จะได้พบกับวิธีการจับคู่ที่ไม่ วิธีการของคุณdoCalc(Byte s1, Byte s2)ต้องมีการล็อคอัตโนมัติระหว่างการโทรดังนั้นมันจะได้รับความพึงพอใจน้อยลง


1
เกี่ยวกับเหตุผลที่longยอมรับbyteดูเหมือนว่าจะเป็นไปตามการแปลงดั้งเดิมขยับขยาย : docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 ดังนั้นโดยทั่วไป+widening -boxing -varargsแล้วนั้น+widening +boxing -varargs +widening +boxing +varargs
— sp00m

@kbo ทำไมคุณถึงคิดว่าคำตอบที่ถูกต้องคือByte, Byteอะไร?
— Amit Bera

3
@kbo ฉันเดาว่าคำตอบที่ถูกต้องไม่ถูกต้อง :) อาจจะคุ้มค่าที่จะชี้ผู้แต่งคำถามนี้ถ้าคุณทำได้
— sp00m

3
@ sp00m ฉันพบคำถามนี้ในตัวอย่างของ Oracle โปรดดูที่ส่วนที่แก้ไข
— kbo

@kbo Wow ... ไม่รู้จะทำยังไงต่อ!
— sp00m

2

กรุณามีความอ่านของJLS บทที่เกี่ยวกับการแปลง

สิ่งที่เกิดขึ้นในกรณีของคุณคือว่าในช่วงรันไทม์ JVM เลือกที่จะดำเนินการแปลงขยับขยาย เช่นนี้เป็นแปลงจะปลอดภัยกว่าเพราะมันมีการรับประกันว่าจะไม่ก่อให้เกิดbyte -> longRuntimeException

การแปลงจากbyteเป็นByteเรียกอีกอย่างหนึ่งว่ามวยอาจส่งผลให้เกิดOutOfMemoryErrorเนื่องจาก JVM ต้องจัดสรรวัตถุใหม่เข้าสู่กอง:

การแปลงมวยอาจส่งผลให้ OutOfMemoryError ถ้าอินสแตนซ์ใหม่ของคลาส wrapper (Boolean, Byte, อักขระ, Short, Integer, Long, Float หรือ Double) ต้องมีการจัดสรรและมีที่เก็บไม่เพียงพอ

เพราะการที่มีความปลอดภัยbyte -> long ขยับขยายแปลงเป็นที่ต้องการ


2
เพียงเพื่อให้ทราบการชกมวยจากbyteถึงByteไม่เคยเกิดOutOfMemoryExceptionขึ้นเนื่องจากค่าทั้งหมดของByte(-128 - 127) จะถูกแคชภายใน แต่มันอาจไม่เหมือนกันกับประเภทอื่น ๆ ดังนั้นเมื่อกฎของหัวแม่มือการแปลงแบบขยายได้รับความสำคัญ
— Pavel Smirnov

1

สำหรับการค้นหาโอเวอร์โหลดที่ถูกต้องลำดับคือ:

  1. ตามจำนวนของพารามิเตอร์
  2. มวย / unboxing
  3. พารามิเตอร์ Variadic

ดังนั้น

  • ถ้าbที่ผลจะเป็นByteByte, Byte
  • ถ้าผ่านจะได้รับผลจะเป็นnew byte[] { b, b }byte, byte
  • ถ้าผ่านสองไบต์ขการขยับขยายจากไบต์ int long, longยาวเป็นไปได้และผลที่ได้คือ
  • เมื่อByte, Byteผลลัพธ์ที่ยาวเกินพิกัดยาวถูกลบออก
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.