Truyền đối số byte cho phương thức quá tải


12

Tôi đã lấy đoạn mã này từ một số bài kiểm tra, sử dụng IDE Tôi đã thực hiện nó và nhận được một kết quả dài, dài nhưng câu trả lời đúng là Byte, Byte , tại sao tôi lại nhận được kết quả khác? Câu hỏi liên quan đến 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);
    }
}

EDITED:

Mã được lấy tại đây: Tổng quan về Chứng nhận Oracle và Câu hỏi mẫu (Trang: 13, Câu hỏi: 5)


1
Bạn có chắc chắn rằng nó không Byte b = 5;có vốn B.
Joop Eggen

4
Tôi cũng nhận được long, longtrên Java8 FYI ... Không chắc tại sao phải trung thực, chờ đợi câu trả lời quá :)
sp00m

Câu trả lời:


6

Vì vậy, nếu bạn xem qua đặc tả ngôn ngữ Java để xác định chữ ký phương thức tại thời điểm biên dịch thì sẽ rõ ràng:

  1. Giai đoạn đầu tiên (§15.12.2.2) thực hiện giải quyết quá tải mà không cho phép chuyển đổi quyền anh hoặc bỏ hộp hoặc sử dụng lời gọi phương thức arity biến. Nếu không tìm thấy phương pháp áp dụng nào trong giai đoạn này thì quá trình xử lý sẽ tiếp tục đến giai đoạn thứ hai.

  2. Giai đoạn thứ hai (§15.12.2.3) thực hiện độ phân giải quá tải trong khi cho phép đấm bốc và bỏ hộp, nhưng vẫn không sử dụng lời gọi phương thức arity biến. Nếu không tìm thấy phương pháp áp dụng nào trong giai đoạn này thì quá trình xử lý sẽ tiếp tục đến giai đoạn thứ ba.

  3. Giai đoạn thứ ba (§15.12.2.4) cho phép quá tải được kết hợp với các phương pháp arity biến đổi, quyền anh và unboxing.

Vì vậy, từ các bước trên, rõ ràng trong trường hợp của bạn, trình biên dịch Java giai đoạn đầu tiên sẽ tìm thấy một phương thức phù hợp doCalc(long a,long b). Phương pháp của bạn doCalc(Byte s1, Byte s2)cần một hộp tự động trong suốt cuộc gọi để nó sẽ nhận được ít ưu tiên hơn.


1
Liên quan đến lý do tại sao longchấp nhận byte, dường như tuân theo chuyển đổi nguyên thủy mở rộng : docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.2 . Vì vậy, về cơ bản, +widening -boxing -varargssau +widening +boxing -varargsđó +widening +boxing +varargs.
sp00m

@kbo Tại sao bạn nghĩ rằng câu trả lời đúng là Byte, Byte?
Amit Bera

3
@kbo Tôi đoán câu trả lời đúng là không chính xác :) Có thể đáng để chỉ các tác giả cho câu hỏi này nếu bạn có thể.
sp00m

3
@ sp00m Tôi tìm thấy câu hỏi này trong các mẫu của Oracle, vui lòng xem phần đã chỉnh sửa
kbo

@kbo Wow ... Không biết làm thế nào để tiến hành rồi!
sp00m

2

Vui lòng đọc chương JLS về chuyển đổi .

Điều đang xảy ra trong trường hợp của bạn là trong thời gian chạy, JVM chọn thực hiện chuyển đổi mở rộng byte -> long vì đây là chuyển đổi an toàn hơn vì nó được đảm bảo rằng nó không gây ra RuntimeException.

Chuyển đổi từ byteđể Bytecòn gọi là đấm bốc có thể dẫn đến OutOfMemoryError như JVM phải phân bổ các đối tượng mới vào đống:

Một chuyển đổi quyền anh có thể dẫn đến OutOfMemoryError nếu một phiên bản mới của một trong các lớp bao bọc (Boolean, Byte, Ký tự, Ngắn, Số nguyên, Dài, Nổi hoặc Đôi) cần được phân bổ và không đủ dung lượng lưu trữ.

Do đó, byte -> long chuyển đổi mở rộng an toàn hơn được ưa thích.


2
Chỉ cần lưu ý, đấm bốc từ byteđể Bytekhông bao giờ gây ra OutOfMemoryException, vì tất cả các giá trị của Byte(-128 - 127) đều được nội cache. Nhưng nó có thể không giống với các loại khác, do đó, theo nguyên tắc thông thường, việc mở rộng chuyển đổi được ưu tiên.
Pavel Smirnov

1

Để tìm quá tải chính xác, thứ tự là:

  1. theo số lượng tham số
  2. đấm bốc / unboxing
  3. thông số

Vì thế

  • Nếu bnơi một Bytekết quả sẽ được Byte, Byte.
  • Nếu được thông qua sẽ có new byte[] { b, b }kết quả byte, byte.
  • Nếu truyền hai byte b, việc mở rộng từ byte sang int thành dài là có thể và kết quả là long, long.
  • Khi quá tải dài, dài được loại bỏ, Byte, Bytekết quả.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.