5

Tôi đang cố gắng hiểu quá tải phương thức và tôi có các phương pháp này.Quá tải và chênh lệch phương thức Java

public void method(int a){ 
    System.out.println("int a"); 
} 

//implementing interface method 
@Override 
public void method() { 
    System.out.println("interface"); 
} 

//varargs 
public void method(int ... a){ 
    System.out.println("int ... a"); 
} 

Sau khi gọi chúng với các thông số này,

int[] a = new int[5]; 
stack.method(); 
stack.method(1); 
stack.method(5,6); 
stack.method(null); 
stack.method(a); 

tôi có những kết quả này:

giao diện
int a
int ... một int
... a
int ... a

Theo như tôi biết, chương trình không nên biên dịch, beacuse của sự mơ hồ, nhưng nó anyway. Không nên trình biên dịch ném một lỗi?

+1

int là một loại cơ sở, null là dành cho các đối tượng. Mỗi loại cơ sở có một giá trị mặc định (int = 0) nếu bạn không chỉ định bất kỳ giá trị nào.Khi một mảng là một đối tượng trên mỗi giá trị, thì null được hiểu là đối số vararg như là các kiểu cơ sở arent references và do đó không thể rỗng. Đơn giản như vậy –

Trả lời

2

Độ phân giải quá tải phương thức có ba giai đoạn. Giai đoạn đầu tiên và thứ hai không xem xét các phương thức có varargs (còn gọi là các phương thức arity biến) làm ứng cử viên, vì vậy chỉ khi không có phương thức đối sánh nào không có varargs, trình biên dịch xem xét phương thức với varargs là ứng cử viên.

Do đó, trong các cuộc gọi phương thức đầu tiên và thứ hai, số void method(int ... a) của bạn bị bỏ qua và không có sự mơ hồ.

15.12.2. Compile-Time Step 2: Determine Method Signature

Bước thứ hai tìm kiếm kiểu xác định trong bước trước đó cho phương pháp thành viên. Bước này sử dụng tên của phương thức và đối số các biểu thức để định vị các phương thức có thể truy cập và áp dụng được, nghĩa là các khai báo có thể được gọi chính xác trên các đối số nhất định.

Có thể có nhiều hơn một phương pháp như vậy, trong trường hợp này, nhất định được chọn. Bộ mô tả (chữ ký cộng với kiểu trả về) của phương pháp cụ thể nhất là phương pháp được sử dụng trong thời gian chạy để thực hiện công văn phương thức .

Phương pháp có thể áp dụng nếu được áp dụng bởi một trong những yêu cầu nghiêm ngặt (§15.12.2.2), yêu cầu lỏng lẻo (§15.12.2.3) hoặc biến số yêu cầu (§15.12.2.4).

Một số biểu thức luận có chứa ngầm gõ lambda biểu thức (§15.27.1) hoặc phương pháp tài liệu tham khảo không chính xác (§15.13.1) là bỏ qua các bài kiểm tra khả năng ứng dụng, vì ý nghĩa của chúng có thể không được xác định cho đến khi một loại mục tiêu là đã chọn.

Mặc dù lời gọi phương thức có thể là một biểu thức poly, chỉ biểu thức đối số - không phải là loại mục tiêu của yêu cầu - ảnh hưởng lựa chọn các phương pháp áp dụng.

Quy trình xác định khả năng ứng dụng bắt đầu bằng cách xác định các phương pháp có khả năng áp dụng (§15.12.2.1) .

Phần còn lại của quy trình được chia thành ba giai đoạn, để đảm bảo tương thích với các phiên bản của ngôn ngữ lập trình Java trước Java SE 5.0. Các giai đoạn là:

  1. Giai đoạn đầu (§15.12.2.2) thực hiện quá tải độ phân giải mà không cho phép đấm bốc hoặc chuyển đổi unboxing, hoặc sử dụng các biến arity phương pháp gọi. Nếu không tìm thấy phương pháp áp dụng trong giai đoạn thì việc xử lý tiếp tục đến giai đoạn thứ hai. Điều này đảm bảo rằng bất kỳ cuộc gọi nào hợp lệ trong ngôn ngữ lập trình Java trước Java SE 5.0 không được coi là mơ hồ là kết quả của việc giới thiệu các phương pháp xác định biến số, ngụ ý đấm bốc và/hoặc mở hộp. Tuy nhiên, việc khai báo phương thức có thể thay đổi phương thức được chọn cho phương thức phương thức đã cho biểu thức gọi, bởi vì phương pháp arity biến được coi là phương pháp tinh khiết cố định trong giai đoạn đầu tiên. Ví dụ, khai báo m (đối tượng ...) trong một lớp đã khai báo m (Object) làm cho m (đối tượng) không còn được chọn cho một số biểu thức gọi (chẳng hạn dưới dạng m (null)), như m (Đối tượng []) cụ thể hơn.

  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 boxing và unboxing, nhưng vẫn loại trừ việc sử dụng biến số invity method invocation. Nếu không tìm thấy phương pháp áp dụng trong giai đoạn này thì việc xử lý tiếp tục đến giai đoạn thứ ba. Điều này đảm bảo rằng một phương pháp không bao giờ được chọn thông qua lời gọi phương thức arity biến nếu nó được áp dụng thông qua phương pháp xác định phương pháp arity cố định .

  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 xác định biến số, quyền anh và unboxing.

+0

Cảm ơn bạn đã trả lời kịp thời. – kunedgard

+1

@ j2hEhE không có cảm ơn. Stackoverflow duy trì một hệ thống danh tiếng. Nếu bạn tìm thấy một câu trả lời hữu ích sử dụng các cơ chế upvote bên cạnh bài viết, nếu bạn không đồng ý nhận xét về những điều sai trái theo ý kiến ​​của bạn và downvote. Bạn có thể (và nên) cũng chấp nhận câu trả lời như một giải pháp cho vấn đề của bạn (hoặc câu hỏi) để trong tương lai câu hỏi tương tự có thể được tham chiếu đến giải pháp được chấp nhận –

+0

@Roman Vottner "không cần phải cảm ơn ???" không cấm để lịch sự :) – davidxxx

1

Một phương pháp với một danh sách đối số biến chỉ được coi là bởi trình biên dịch một lần tất cả các khả năng khác đã cạn kiệt.

Những "khả năng khác" này được xem xét theo cách thông thường.

Do đó trong trường hợp của bạn không có sự mơ hồ và do đó trình biên dịch không phát ra lỗi.

+0

Cảm ơn bạn rất nhiều! – kunedgard

1

Không có nó là tốt không có sự mơ hồ: passing "(5,6)" là tốt bởi vì phương pháp này expxects nhiều số nguyên, đi qua "(a)" cũng là tốt vì a là một mảng số nguyên passing"(null)" cũng là tốt + Nhà null có thể được đúc cho bất kỳ loại tài liệu tham khảo như một integer [] vì vậy nó có thể được sử dụng nơi bạn mong đợi int [];

vì vậy tất cả các cuộc gọi gọi phương thức thứ ba

public void method(int ... a){ 
    System.out.println("int ... a"); 
} 

hai cuộc gọi phương pháp đầu tiên là tự giải thích họ gọi là phương pháp

public void method(){ 
    System.out.println("interface"); 
} 

public void method(int a){ 
    System.out.println("int a"); 
} 

tương ứng

+0

Cảm ơn bạn đã trả lời! – kunedgard

3

Eran và Bathsheba đã nói lý do tại sao những người khác nhau không sử dụng null đã được chọn.

Phần còn lại của câu hỏi là: Tại sao stack.method(null); thậm chí biên dịch?

Câu trả lời là nó khớp với chữ ký varargs, bởi vì các varargs method(int...) có hiệu quả giống nhau từ quan điểm của trình biên dịch là method(int[]). Vì mảng được tham chiếu theo tham chiếu, nên có thể sử dụng null khi dự kiến ​​int[].

Vì vậy:

stack.method(); 

chính xác phù hợp cho các method() chữ ký trong giao diện. Không mơ hồ với method(int...) vì varargs chỉ được xem xét khi những người khác không khớp.

stack.method(1); 

Matches method(int). Không mơ hồ với cùng lý do như trên.

stack.method(5,6); 

Matches method(int...) vì không ai trong số các phi varargs những lần xuất hiện, nhưng varargs một đã làm.

stack.method(null); 

Xem giải thích trước đó.

stack.method(a); 

Matches match(int...) cho cùng một lý do method(null0 làm: Bởi vì match(int...) là có hiệu quả tương tự như match(int[]) để trình biên dịch.

+1

Bây giờ tôi hiểu, cảm ơn bạn! – kunedgard

Các vấn đề liên quan