Phương thức quá tải cho đối số null


133

Tôi đã thêm ba phương thức với các tham số:

public static  void doSomething(Object obj) {
    System.out.println("Object called");
}

public static  void doSomething(char[] obj) {
    System.out.println("Array called");
}

public static  void doSomething(Integer obj) {
    System.out.println("Integer called");
}

Khi tôi gọi doSomething(null), trình biên dịch sẽ ném lỗi dưới dạng các phương thức mơ hồ . Vì vậy, vấn đề là bởi vì Integerchar[]phương pháp hay IntegerObjectphương pháp?


3
Chỉ cần thay đổi Integerthành int.
Mudassir

2
@Mudassir: và chính xác thì điều gì sẽ giải quyết?
Joachim Sauer

2
@Joachim Sauer: Nếu thay đổi từ Integer thành int, thì null không được đề cập đến các kiểu nguyên thủy trong Java, vì vậy trình biên dịch sẽ không đưa ra lỗi.
Phani

@Joachim Sauer: Nó sẽ không ném reference to doSomething is ambiguouslỗi.
Mudassir

Câu trả lời:


211

Java sẽ luôn cố gắng sử dụng phiên bản áp dụng cụ thể nhất của phương thức có sẵn (xem JLS §15.12.2 ).

Object, char[]Integertất cả có thể mất nullnhư một giá trị hợp lệ. Do đó, cả 3 phiên bản đều có thể áp dụng được, vì vậy Java sẽ phải tìm một phiên bản cụ thể nhất.

Objectlà siêu kiểu char[], phiên bản mảng cụ thể hơn so với đảo ngược Object. Vì vậy, nếu chỉ có hai phương thức đó tồn tại, char[]phiên bản sẽ được chọn.

Khi cả hai phiên bản char[]Integerphiên bản đều khả dụng, thì cả hai phiên bản đều cụ thể hơn Objectnhưng không phiên bản nào cụ thể hơn phiên bản kia, vì vậy Java không thể quyết định nên gọi cái nào. Trong trường hợp này, bạn sẽ phải đề cập rõ ràng đến cái nào bạn muốn gọi bằng cách chuyển đối số thành loại thích hợp.

Lưu ý rằng trong thực tế, vấn đề này hiếm khi xảy ra hơn nhiều so với người ta tưởng. Lý do cho điều này là nó chỉ xảy ra khi bạn gọi một phương thức rõ ràng bằng nullhoặc với một biến có kiểu khá không cụ thể (chẳng hạn như Object).

Ngược lại, lời mời sau đây sẽ hoàn toàn không rõ ràng:

char[] x = null;
doSomething(x);

Mặc dù bạn vẫn truyền giá trị null, Java biết chính xác nên gọi phương thức nào, vì nó sẽ đưa loại biến vào tài khoản.


1
Điều này được nêu cho Java 7. Điều đó cũng áp dụng cho các phiên bản Java trước? Ý tôi là: Nếu bạn có một số chữ ký phương thức với các tham số chỉ dọc theo một hệ thống phân cấp loại, thì bạn có ở bên lưu với giá trị thực không? Và nếu bạn đã xây dựng một "hệ thống phân cấp cho" như trong ví dụ ở đây, thì bạn không?
Christian Gosch

2
Tôi khá chắc chắn rằng các quy tắc này giống nhau cho ít nhất là mọi thứ kể từ Java 1.1 (ngoại trừ việc bổ sung các tổng quát, rõ ràng).
Joachim Sauer

Điều này có nghĩa là nếu trình biên dịch được chọn ở giữa doS Something (String str) và doS Something (Object obj) trong thời gian chạy với doS Something (null), doS Something (String str) sẽ được gọi.
Sameer

42

Mỗi cặp của ba phương thức này đều mơ hồ khi được gọi bằng một nullđối số. Bởi vì mỗi loại tham số là một loại tham chiếu.

Sau đây là ba cách để gọi một phương thức cụ thể của bạn bằng null.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

Tôi có thể đề nghị loại bỏ sự mơ hồ này nếu bạn thực sự có kế hoạch gọi các phương thức này bằng các nullđối số. Thiết kế như vậy mời các lỗi trong tương lai.


1
Chỉ Integer- char[]cặp là mơ hồ, vì trong hai trường hợp khác, trình biên dịch Java có thể chọn lựa chọn cụ thể nhất, như @JoachimSauer đã mô tả.
kajacx

1
@kajacx: ​​Câu hỏi ban đầu của OP là về việc gọi các phương thức này với nulltham số. Theo điều kiện tiên quyết đó, cả ba cặp đều mơ hồ. Đối với trường hợp chung, tôi đồng ý rằng chỉInteger - char[] cặp là mơ hồ.
jmg

những gì về doSomething(null)cho public static void doSomething(String str) { System.out.println("String called"); } này sẽ trở lại chuỗi gọi.
Tương tự

Có thể sử dụng một anotation như "nullable" hoặc "không nullable" và thiết lập các khai báo để chỉ một phương thức bạn muốn nhận null để một đối số rõ ràng "null" (loại ẩn ẩn) luôn luôn chọn một cách rõ ràng một quá tải cụ thể ??
cựu binh

4

nulllà một giá trị hợp lệ cho bất kỳ trong ba loại; vì vậy trình biên dịch không thể quyết định sử dụng chức năng nào. Sử dụng một cái gì đó như doSomething((Object)null)hoặc doSomething((Integer)null)thay vào đó.


Tôi đã loại bỏ phương thức với tham số Integer, nó gọi hàm và trả lại đầu ra là "Mảng được gọi là" , vậy hợp đồng giữa Array và Object là gì?
Phani

2
Mảng Java cũng là đối tượng.
Zds

2

Mỗi lớp trong Java đều mở rộng lớp Object.Even Integer cũng mở rộng Object. Do đó cả Object và Integer đều được coi là đối tượng Object. Vì vậy, khi bạn truyền null làm tham số hơn trình biên dịch sẽ bị nhầm lẫn rằng phương thức đối tượng nào sẽ gọi tức là Với tham số Object hoặc tham số Integer vì cả hai đều là đối tượng và tham chiếu của chúng có thể là null. Nhưng các nguyên thủy trong java không mở rộng Object.


1

Tôi đã thử điều này và khi có chính xác một cặp phương thức bị quá tải và một trong số chúng có kiểu tham số Object thì trình biên dịch sẽ luôn chọn phương thức có kiểu cụ thể hơn. Nhưng khi có nhiều hơn một loại cụ thể, thì trình biên dịch sẽ đưa ra một lỗi phương thức mơ hồ.

Vì đây là một sự kiện thời gian biên dịch, điều này chỉ có thể xảy ra khi một người cố tình chuyển null sang phương thức này. Nếu điều này được thực hiện có chủ ý thì tốt hơn là quá tải lại phương thức này mà không có tham số hoặc tạo phương thức khác hoàn toàn.


0

có một sự mơ hồ vì doS Something (char [] obj) và doS Something (Integer obj).

char [] và Integer đều vượt trội như nhau đối với null đó là lý do tại sao chúng không rõ ràng.


0
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

Đầu ra là Int được gọi là null và do đó sự mơ hồ là với char [] và Integer

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.