String.valueOf () so với Object.toString ()


132

Trong Java, có sự khác biệt nào giữa String.valueOf(Object)Object.toString()không? Có một quy ước mã cụ thể cho những điều này?


10
Các kiểu nguyên thủy không có "toString" .. vì vậy String.valueOfđược sử dụng. Đối với các đối tượng ghi đè lênString, tôi nghĩ String.valueOf có thể gọi điều đó thay thế. Không chắc chắn về phần đó mặc dù.
Brandon

@Brandon Bạn đúng, nó thực hiện chính xác điều đó, ngoại trừ việc nó kiểm tra nulllần đầu tiên.
azurefrog

Nhận xét đầu tiên ở đây tôi nghĩ có ý nghĩa nhất nếu nó là chính xác. Bạn phải sử dụng String.valueOf trong một số tình huống trong đó mục tiêu là loại nguyên thủy.
Donato

Câu trả lời:


177

Theo tài liệu Java , String.valueOf()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.

Vì vậy, không nên thực sự có một sự khác biệt ngoại trừ một lời gọi phương thức bổ sung.

Ngoài ra, trong trường hợp Object#toString, nếu ví dụ là null, một cái NullPointerExceptionsẽ bị ném, vì vậy có thể nói, nó kém an toàn hơn .

public static void main(String args[]) {  
    String str = null;
    System.out.println(String.valueOf(str));  // This will print a String equal to "null"        
    System.out.println(str.toString()); // This will throw a NullPointerException
} 

6
Đây là câu trả lời tốt nhất. Đọc và dựa vào javadocs, không phải mã. (Về nguyên tắc, mã có thể khác nhau đối với các phiên bản / bản phát hành Java khác nhau.)
Stephen C

7
@Brandon - Không chính xác. Nó chỉ cần thay đổi nếu hành vi thay đổi theo cách làm mất hiệu lực javadoc. 1) Cơ hội xảy ra cho phương pháp này là KHÔNG. Họ sẽ không thực hiện thay đổi để đảm bảo thay đổi thông số kỹ thuật và nếu họ làm như vậy thì họ sẽ thay đổi thông số kỹ thuật. 2) Nó không làm mất hiệu lực lời khuyên của tôi. Nếu bạn đọc javadoc, thì bạn sẽ thấy rằng hành vi được ghi lại!
Stephen C

2
Liệu phương pháp ném ngoại lệ có an toàn hơn không? Thông thường, khi mã của bạn ném NullPulumException, đó là một điều tốt. Nó có thể không cảm thấy tốt cho nhà phát triển vào lúc này ("aww, không, bây giờ tôi cần quay lại và sửa mã của mình"), nhưng vì lỗi đã bị ném, bạn phát hiện ra rằng bạn cần phải sửa một cái gì đó. Nói cách khác, bạn đang phơi bày "null" trực tiếp cho người dùng và không nhận được lỗi được báo cáo trừ khi bạn kiểm tra rõ ràng một lỗi, điều này có vẻ như tôi kém an toàn hơn.
Tim M.

1
Để rõ ràng, bạn thực sự không thể gọi String.valueOf(null), đó là một NPE. Nó chỉ hoạt động cho các đối tượng là null.
Noumenon 17/03/19

1
Đó không phải là lời giải thích. Việc String.valueOf(null)thực sự giải quyết đến valueOf(char[])quá tải. Điều này là do char[]một loại cụ thể hơn Object.
Stephen C

17

Sự khác nhau giữa String.valueOf (Object) và Object.toString () là:

1) Nếu chuỗi là null,

String.valueOf(Object)sẽ trở lại null, trong khi Object::toString()sẽ ném một ngoại lệ con trỏ null.

public static void main(String args[]){  
    String str = null;

    System.out.println(String.valueOf(str));  // it will print null        
    System.out.println(str.toString()); // it will throw NullPointerException        
}  

2) Chữ ký:

Phương thức valueOf () của lớp String là tĩnh. trong khi phương thức toString () của lớp String là không tĩnh.

Chữ ký hoặc cú pháp của phương thức valueOf () của chuỗi được đưa ra dưới đây:

public static String valueOf(boolean b)  
public static String valueOf(char c)  
public static String valueOf(char[] c)  
public static String valueOf(int i)  
public static String valueOf(long l)  
public static String valueOf(float f)  
public static String valueOf(double d)  
public static String valueOf(Object o)

Chữ ký hoặc cú pháp của toString()phương thức chuỗi được đưa ra dưới đây:

public String toString()

13

Trong Java, có sự khác biệt nào giữa String.valueOf (Object) và Object.toString () không?

Đúng. (Và hơn thế nữa nếu bạn xem xét quá tải!)

Như javadoc giải thích, String.valueOf((Object) null)sẽ được coi là trường hợp đặc biệt theo valueOfphương thức và giá trị "null"được trả về. Ngược lại, null.toString()sẽ chỉ cung cấp cho bạn một NPE.

Quá tải

Nó chỉ ra rằng String.valueOf(null)(lưu ý sự khác biệt!) Không đưa ra một NPE ... mặc dù javadoc. Lời giải thích không rõ ràng:

  1. Có một số tình trạng quá tải String.valueOf, nhưng có hai điều có liên quan ở đây: String.valueOf(Object)String.valueOf(char[]).

  2. Trong biểu thức String.valueOf(null) , cả hai quá tải đó đều có thể áp dụng được , vì nullphép gán tương thích với bất kỳ loại tham chiếu nào.

  3. Khi có hai hoặc nhiều hơn quá tải áp dụng , JLS nói rằng quá tải cho loại đối số cụ thể nhất được chọn.

  4. Từ char[] là một kiểu con của Objectnó, nó là cụ thể hơn .

  5. Do đó, String.valueOf(char[])quá tải được gọi là.

  6. String.valueOf(char[])ném một NPE nếu đối số của nó là một mảng null. không giốngString.valueOf(Object) , nó không được coi nulllà một trường hợp đặc biệt.

(Bạn có thể xác nhận điều này bằng cách sử dụng javap -cđể kiểm tra mã của phương thức có String.valueOf(null)cuộc gọi. Quan sát tình trạng quá tải được sử dụng cho cuộc gọi.)

Một ví dụ khác minh họa sự khác biệt trong valueOf(char[])tình trạng quá tải thậm chí rõ ràng hơn:

char[] abc = new char[]('a', 'b', 'c');
System.out.println(String.valueOf(abc));  // prints "abc"
System.out.println(abc.toString());       // prints "[C@...."

Có một quy ước mã cụ thể cho những điều này?

Không.

Sử dụng cái nào phù hợp nhất với yêu cầu của bối cảnh bạn đang sử dụng nó. (Bạn có cần định dạng để làm việc chonull không?)

Lưu ý: đó không phải là quy ước mã. Nó chỉ là lập trình thông thường. Điều quan trọng hơn là mã của bạn là chính xác hơn là tuân theo một số quy ước về phong cách hoặc giáo điều "thực hành tốt nhất".


Ý kiến ​​cá nhân:

Một số nhà phát triển có được thói quen xấu là "phòng thủ" chống lại null. Vì vậy, bạn thấy rất nhiều bài kiểm tra cho null và coi null là trường hợp đặc biệt. Ý tưởng dường như ngăn chặn NPE xảy ra.

Tôi nghĩ rằng đây là một ý tưởng tồi. Cụ thể, tôi nghĩ rằng đó là một ý tưởng tồi nếu những gì bạn làm khi bạn tìm thấy mộtnull là cố gắng "làm cho tốt" ... mà không xem xét lý do tại sao có một nullđó.

Nói chung, tốt hơn hết là tránh nullở đó ngay từ đầu ... trừ khi nó nullcó ý nghĩa rất cụ thể trong ứng dụng hoặc thiết kế API của bạn. Vì vậy, thay vì tránh NPE với nhiều mã hóa phòng thủ, tốt hơn là để NPE xảy ra, sau đó theo dõi và khắc phục nguồn không mong muốnnull đã kích hoạt NPE.

Vậy làm thế nào để áp dụng ở đây?

Chà, nếu bạn nghĩ về nó, sử dụng String.valueOf(obj) có thể là một cách "làm cho tốt". Đó là phải tránh. Nếu nó là bất ngờ objđể được nulltrong bối cảnh, nó là tốt hơn để sử dụng obj.toString().


5

Hầu hết đã được đề cập bởi các câu trả lời khác, nhưng tôi chỉ cần thêm nó cho đầy đủ:

  1. Người nguyên thủy không có .toString()vì chúng không phải là một triển khai của Objectlớp, vì vậy chỉ String.valueOfcó thể được sử dụng.
  2. String.valueOfsẽ biến đổi một đối tượng đã cho là nullChuỗi "null", trong khi đó .toString()sẽ ném a NullPointerException.
  3. Trình biên dịch sẽ sử dụng String.valueOftheo mặc định khi một cái gì đó giống như String s = "" + (...);được sử dụng. Đó là lý do tại sao Object t = null; String s = "" + t;sẽ dẫn đến Chuỗi "null"chứ không phải trong NPE. EDIT: Trên thực tế, nó sẽ sử dụng StringBuilder.append, không String.valueOf. Vì vậy, bỏ qua những gì tôi nói ở đây.

Ngoài những thứ đó, đây thực sự là một trường hợp sử dụng trong đó String.valueOf.toString() có kết quả khác nhau:

Hãy nói rằng chúng ta có một phương pháp chung như thế này:

public static <T> T test(){
  String str = "test";
  return (T) str;
}

Và chúng ta sẽ gọi nó với một Integerloại như thế này:Main.<Integer>test() .

Khi chúng ta tạo một Chuỗi với String.valueOfnó hoạt động tốt:

String s1 = String.valueOf(Main.<Integer>test());
System.out.println(s1);

Điều này sẽ xuất test STDOUT.

Với .toString()tuy nhiên, nó sẽ không làm việc:

String s2 = (Main.<Integer>test()).toString();
System.out.println(s2);

Điều này sẽ dẫn đến lỗi sau:

java.lang.ClassCastException: lớp java.lang.Stringkhông thể được chuyển đến lớpjava.lang.Integer

Hãy thử trực tuyến.

Về lý do tại sao, tôi có thể tham khảo câu hỏi riêng biệt này và câu trả lời của nó . Tuy nhiên, trong ngắn hạn:

  • Khi sử dụng .toString()đầu tiên nó sẽ biên dịch và đánh giá các đối tượng, nơi các diễn viên để T(mà là một Stringđể Integercast trong trường hợp này) sẽ dẫn đến việc ClassCastException.
  • Khi sử dụng String.valueOfnó sẽ thấy chung chung Tnhư Objecttrong quá trình biên dịch và thậm chí không quan tâm đến việc nó là một Integer. Vì vậy, nó sẽ đúc một Objectđến Object(mà trình biên dịch chỉ cần bỏ qua). Sau đó, nó sẽ sử dụng String.valueOf(Object), dẫn đến một Stringmong đợi. Vì vậy, mặc dù nội bộ String.valueOf(Object)sẽ thực hiện một .toString()tham số trong nội bộ, chúng tôi đã bỏ qua các diễn viên và nó được đối xử như một Object, vì vậy chúng tôi đã tránh được ClassCastExceptionđiều đó xảy ra với việc sử dụng .toString().

Chỉ cần nghĩ rằng nó là giá trị đề cập đến sự khác biệt bổ sung giữa String.valueOf.toString()ở đây là tốt.


Lần cuối cùng tôi quan tâm đến điều này, có lẽ là về JDK 1.2, ("" + x)được biên dịch String.valueOf(x), nhưng bất cứ điều gì phức tạp hơn đều sử dụng một StringBuffer(chúng tôi không có StringBuildersau đó).
Neil

4

String.valueOf(Object)Object.toString()theo nghĩa đen là điều tương tự.

Nếu bạn xem qua việc triển khai String.valueOf (Object) , bạn sẽ thấy String.valueOf(Object)về cơ bản đó chỉ là một lời gọi null an toàn của toString()đối tượng thích hợp:

Returns the string representation of the Object argument.

Parameters:
    obj an Object.
Returns:
    if the argument is null, then a string equal to "null"; 
    otherwise, the value of obj.toString() is returned.
See also:
    Object.toString()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Không đúng, sử dụng cả valueOf và toString trên một mảng char và đánh mắt bạn.
Artanis

3

Sự khác biệt quan trọng nhất là cách họ xử lý các tham chiếu Chuỗi null.

String str = null;
System.out.println("String.valueOf gives : " + String.valueOf(str));//Prints null
System.out.println("String.toString gives : " + str.toString());//This would throw a NullPointerExeption

1

Khi tranh luận là null, String.valueOftrả về "null", nhưng Object.toStringném NullPointerException, đó là sự khác biệt duy nhất.


0

Có một sự khác biệt lớn hơn giữa hai phương thức là khi đối tượng chúng ta đang chuyển đổi là một mảng.

Khi bạn chuyển đổi một mảng bằng Object.toString (), bạn sẽ nhận được một số loại giá trị rác (@ theo sau là mã băm của mảng).

Để có được một toString () có thể đọc được của con người, bạn phải sử dụng String.valueOf (char []); Xin lưu ý rằng phương pháp này chỉ hoạt động đối với Mảng kiểu char. Tôi khuyên bạn nên sử dụng Arrays.toString (Object []) để chuyển đổi mảng thành Chuỗi.

Sự khác biệt thứ hai là khi đối tượng là null, ValueOf () trả về một chuỗi "null", trong khi toString () sẽ trả về ngoại lệ con trỏ null.


Xin chào @Tom điều này đúng với một mảng thuộc bất kỳ loại nào, tuy nhiên Nếu bạn đang sử dụng Arrays.toString (Object []), bạn có thể chuyển đổi một mảng thuộc bất kỳ loại nào thành chuỗi.
chintan thakker

Xin chào @Tom Object.toString () trả về giá trị rác là đúng với một mảng thuộc bất kỳ loại nào, bạn đúng rằng String.valueOf (Array) sẽ chỉ cung cấp một chuỗi đúng cho một mảng kiểu char. Tôi nên đã đề cập rằng, cảm ơn, tôi sẽ chỉnh sửa nó.
chintan thakker

1
Đó không phải là một giá trị rác, nó là tên lớp và mã băm ( JavaDoc ).
Tom

-1

Tôi không thể nói chính xác sự khác biệt là gì nhưng dường như có sự khác biệt khi hoạt động ở mức byte. Trong kịch bản mã hóa sau đây Object.toString () đã tạo ra một giá trị không thể giải mã được trong khi String.valueOf () hoạt động như dự định ...

private static char[] base64Encode(byte[] bytes) 
{   
    return Base64.encode(bytes);
}

private static String encrypt(String encrypt_this) throws GeneralSecurityException, UnsupportedEncodingException 
{
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
    SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
    pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));

     //THIS FAILED when attempting to decrypt the password
    //return base64Encode(pbeCipher.doFinal(encrypt_this.getBytes("UTF-8"))).toString(); 

    //THIS WORKED
    return String.valueOf(base64Encode(pbeCipher.doFinal(encrypt_this.getBytes("UTF-8"))));
}//end of encrypt()

Tại sao thất bại? có vấn đề gì vậy
Yousha Aleayoub

Giải thích là bạn thực sự đang gọi valueOf(char[])chứ không phải valueOf(Object). Các hành vi của valueOf(char[])là khác nhau đáng kể để char[].toString(). Nhưng dù bằng cách nào, câu trả lời này không phải là apropos bởi vì bạn đang gọi một tình trạng quá tải khác với câu hỏi mà bạn hỏi.
Stephen C

-2

Dưới đây cho thấy việc triển khai cho java.lang.String.valueOf như được mô tả trong nguồn cho jdk8u25. Vì vậy, theo nhận xét của tôi, không có sự khác biệt. Nó gọi "Object.toString". Đối với các kiểu nguyên thủy, nó bọc nó ở dạng đối tượng và gọi "toString" trên nó.

Xem bên dưới:

/*
 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */


    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

    public static String valueOf(char data[]) {
        return new String(data);
    }

    public static String valueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    public static String copyValueOf(char data[]) {
        return new String(data);
    }

    public static String valueOf(boolean b) {
        return b ? "true" : "false";
    }

    public static String valueOf(char c) {
        char data[] = {c};
        return new String(data, true);
    }

    public static String valueOf(int i) {
        return Integer.toString(i);
    }

    public static String valueOf(long l) {
        return Long.toString(l);
    }

    public static String valueOf(float f) {
        return Float.toString(f);
    }

    public static String valueOf(double d) {
        return Double.toString(d);
    }
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.