Tại sao String.valueOf (null) ném NullPulumException?


127

theo tài liệu, phương thức String.valueOf(Object obj)trả về:

nếu đối số là null, thì một chuỗi bằng "null"; mặt khác, giá trị của obj.toString()được trả lại.

Nhưng làm thế nào khi tôi thử làm điều này:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

thay vào đó nó ném NPE? (hãy tự thử nếu bạn không tin!)

    Ngoại lệ trong luồng "chính" java.lang.NullPulumException
    tại java.lang.String. (Nguồn không xác định)
    tại java.lang.String.valueOf (Nguồn không xác định)

Làm thế nào điều này đang xảy ra? Là tài liệu nói dối với tôi? Đây có phải là một lỗi lớn trong Java?

Câu trả lời:


201

Vấn đề là String.valueOfphương pháp đó bị quá tải :

Ngôn ngữ đặc tả Java yêu cầu rằng trong các loại trường hợp này, quá tải cụ thể nhất được chọn:

JLS 15.12.2.5 Chọn phương pháp cụ thể nhất

Nếu có nhiều hơn một phương thức thành viên có thể truy cập và áp dụng được cho một lời gọi phương thức, thì cần phải chọn một phương thức để cung cấp bộ mô tả cho công văn phương thức thời gian chạy. Ngôn ngữ lập trình Java sử dụng quy tắc mà phương thức cụ thể nhất được chọn.

A char[] là-an Object , nhưng không phải tất cả Object là-a char[] . Vì vậy, char[]cụ thể hơn so với Object, và theo quy định của ngôn ngữ Java, String.valueOf(char[])tình trạng quá tải đã được chọn trong trường hợp này.

String.valueOf(char[])hy vọng mảng không phải là null, và vì nullđược đưa ra trong trường hợp này, nên nó sẽ ném NullPointerException.

Cách "khắc phục" dễ dàng là chuyển nullmột cách rõ ràng Objectnhư sau:

System.out.println(String.valueOf((Object) null));
// prints "null"

Câu hỏi liên quan


Đạo đức của câu chuyện

Có một vài điều quan trọng:

  • Phiên bản Java 2 hiệu quả, Mục 41: Sử dụng quá tải một cách thận trọng
    • Chỉ vì bạn có thể quá tải, không có nghĩa là bạn nên mỗi lần
    • Chúng có thể gây nhầm lẫn (đặc biệt là nếu các phương thức làm những việc cực kỳ khác nhau)
  • Sử dụng IDE tốt, bạn có thể kiểm tra quá tải nào được chọn tại thời điểm biên dịch
    • Với Eclipse, bạn có thể di chuột qua biểu thức trên và thấy rằng thực sự , valueOf(char[])quá tải đã được chọn!
  • Đôi khi bạn muốn phân phát rõ ràng null(ví dụ để làm theo)

Xem thêm


Đang đúc null

Có ít nhất hai tình huống trong đó việc truyền rõ ràng nullđến một loại tham chiếu cụ thể là cần thiết:

  • Để chọn quá tải (như trong ví dụ trên)
  • Để cung cấp nulldưới dạng một đối số cho một tham số vararg

Một ví dụ đơn giản về sau là như sau:

static void vararg(Object... os) {
    System.out.println(os.length);
}

Sau đó, chúng ta có thể có những điều sau đây:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

Xem thêm

Câu hỏi liên quan


5
Một đề xuất khác: Khi bạn quá tải một phương thức và một đối số có thể được gọi bằng hai lần quá tải (chẳng hạn như nulltrong trường hợp này), hãy đảm bảo rằng cả hai quá tải đều hoạt động như nhau đối với giá trị đó!
Joachim Sauer

3
@Joachim: Tôi vừa đọc mục này, và đã ngạc nhiên khi thấy rằng hai phương pháp này đã được thảo luận rõ ràng! Bloch đã tiến thêm một bước và tuyên bố rằng dù thế nào String.valueOf(Object)valueOf(char[])làm những việc hoàn toàn khác nhau (không phân biệt nullhay không) rằng có lẽ họ không nên quá tải ngay từ đầu.
đa gen

Có một câu hỏi ... nếu bạn có một phương thức trả về một Object thì câu lệnh return null;sẽ giống hệt như return (Object) null;thế nào?
user972276

17

Vấn đề là bạn đang gọi String.valueOf(char[])không String.valueOf(Object) .

Lý do cho điều này là Java sẽ luôn chọn phiên bản cụ thể nhất của một phương thức quá tải hoạt động với các tham số được cung cấp. nulllà một giá trị hợp lệ cho một Objecttham số, nhưng nó cũng là một giá trị hợp lệ cho một char[]tham số.

Để làm cho Java sử dụng Objectphiên bản, hãy chuyển nullqua một biến hoặc chỉ định truyền rõ ràng cho Object:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));

5

Một lỗi, được đánh số 4867608 đã được đệ trình theo cách này vào năm 2003, đã được giải quyết là "sẽ không sửa chữa" với lời giải thích này.

Chúng tôi không thể thay đổi điều này do các hạn chế tương thích. Lưu ý rằng đó là phương thức StringOf (char data []) tĩnh công khai cuối cùng được gọi và nó không đề cập đến việc thay thế "null" cho các đối số null.

@ ###. ### 2003-05-23


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.