Độ phân giải quá tải, phương thức nào được gọi là


8

Giả sử tôi có một ComponentBaselớp học, là con ObjectContextDecoratorvà cháu của ObjectContext.

public class ComponentBase extends ObjectContextDecorator {
}

public class ObjectContextDecorator extends ObjectContext {

    public void set(String objectTypePath, String characteristicName, Object value) {
        //...
    }
}

public class ObjectContext {
    public void set(String characteristicName, Object value, boolean forced) {
       //...
    }
}

Các setphương pháp trên ObjectContextDecoratorObjectContextrất simillar. Xem xét mã mẫu này:

ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);

Chữ ký của cả hai phương thức phù hợp với chữ ký được gọi chính xác. Tôi không thể thay đổi chữ ký của phương thức vì đó không phải là mã của tôi.

Làm thế nào để trình biên dịch biết phương pháp nào tôi dự định gọi?

Tôi biết rằng trên IDE bạn có thể chỉ ra phương thức nào bạn thực sự có ý định gọi, nhưng trong tình huống này, tôi đang sử dụng trình nạp lớp để tải một lớp có phương thức chứa mã mẫu.


Chúng giống nhau, nhưng khác nhau - không có sự mơ hồ nếu bạn đi vào String, String, boolean. Phương pháp cụ thể nhất sẽ được gọi. Đây là tất cả trong JLS.
Dave Newton

Cái nào là cụ thể nhất? Theo hiểu biết của tôi, cả hai đều cụ thể như nhau.
Gabriel Robaina

3
Vui lòng tham khảo JLS §15.12.2. Thời gian biên dịch Bước 2: Xác định Chữ ký phương thức trong đó các quy tắc cho việc này được mô tả chi tiết. Đặc biệt là 15.12.2.5. Chọn phương pháp cụ thể nhất .
Zabuzard

1
Điều đó nói rằng, ngay cả khi trình biên dịch và các IDE có thể tìm ra cái nào được gọi, các quy tắc rất phức tạp và thật khó để một kẻ ngu ngốc tìm ra nó. Vì vậy, tôi sẽ đổi tên một trong những phương pháp để làm cho nó rõ ràng.
JB Nizet

2
Lưu ý bên lề, chuỗi java chỉ sử dụng một trích dẫn kép (như "this")
OscarRyz

Câu trả lời:


2

Làm thế nào để trình biên dịch biết phương pháp nào tôi dự định gọi?

Nó kiểm tra các đối số và xác định xem đối số nào cụ thể hơn theo các quy tắc được mô tả JLS §15.2

Trong trường hợp của bạn, cuộc gọi:

base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)

các đối số String, String,boolean

Khớp với lớp đầu tiên ( tên tham số thay đổi cho ngắn gọn )

public class ObjectContext {
    public void set(String s, Object o, boolean b){
       //...
    }
}

Lớp thứ hai không được gọi vì tham số thứ ba là Object:

public class ObjectContextDecorator extends ObjectContext {

    public void set(String s, String ss, Object thisOneRightHere) {
        //...
    }
}

và trong khi giá trị boolean truecó thể khớp nếu nó được autoboxed thì giá trị đầu tiên cụ thể hơn. Quy tắc được áp dụng ở đây là:

Giai đoạn đầu tiên (§15.12.2.2) thực hiện độ phân giải quá tải mà không cho phép chuyển đổi quyền anh hoặc bỏ hộp

Nhưng, ví dụ, nếu bạn sử dụng trình bao bọc đối tượng Booleantrong chữ ký:

public class ObjectContext {
    public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
       //...
    }
}

Sau đó, cả hai sẽ khớp và trình biên dịch sẽ cho bạn biết với thông báo sau:

> A.java:25: error: reference to set is ambiguous
>     base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
>         ^   both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match

Nhưng đó không phải là trường hợp trong ví dụ của bạn.


4

Tất cả được giải thích trong Biểu thức gọi phương thức JLS §15.2 . Nó cho bạn biết tất cả về cách chọn phương thức đúng để gọi. Và lưu ý rằng điều này không phải lúc nào cũng thành công.

Trong trường hợp cụ thể của bạn, hai phương thức là quá tải lẫn nhau, vì vậy §15.2.2 "Thời gian biên dịch Bước 2: Xác định chữ ký phương thức" được áp dụng - quá tải để gọi được xác định tại thời điểm biên dịch. Bước này được chia thành 3 giai đoạn.

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.

Trong giai đoạn đầu tiên, trình biên dịch cố gắng tìm các phương thức áp dụng mà không cho phép chuyển đổi quyền anh. Trong trường hợp của bạn, để gọi quá tải cần có Object, một chuyển đổi quyền anh là cần thiết để chuyển đổi boolean truesang loạiObject , do đó, quá tải sẽ không được chọn trong giai đoạn đầu tiên.

Nếu không tìm thấy phương pháp áp dụng theo yêu cầu nghiêm ngặt, việc tìm kiếm các phương thức áp dụng sẽ tiếp tục với giai đoạn 2 (§15.12.2.3).

Mặt khác, phương pháp cụ thể nhất (§15.12.2.5) được chọn trong số các phương pháp được áp dụng bằng cách gọi nghiêm ngặt.

Vâng, chúng tôi đã tìm thấy chính xác một phương thức, vì vậy chúng tôi sẽ chỉ chọn phương pháp đó. Không có sự mơ hồ.

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.