String.valueOf () กับ Object.toString ()


132

ใน Java มีความแตกต่างระหว่างString.valueOf(Object)และObject.toString()อย่างไร มีการกำหนดรหัสเฉพาะสำหรับสิ่งเหล่านี้หรือไม่?


10
ประเภทดั้งเดิมไม่มี "toString" .. จึงString.valueOfถูกนำมาใช้ สำหรับวัตถุที่แทนที่ toString ฉันคิดว่า String.valueOf อาจเรียกสิ่งนั้นแทน ไม่แน่ใจเกี่ยวกับส่วนนั้นว่า
Brandon

@ แบรนดอนคุณถูกต้องมันทำอย่างนั้นยกเว้นว่าจะตรวจสอบnullก่อน
azurefrog

ความคิดเห็นแรกที่นี่ฉันคิดว่าเหมาะสมที่สุดถ้าถูกต้อง คุณต้องใช้ String.valueOf ในบางสถานการณ์ที่เป้าหมายเป็นชนิดดั้งเดิม
Donato

คำตอบ:


177

ตามเอกสาร Java , String.valueOf()ผลตอบแทน:

ถ้าอาร์กิวเมนต์เป็นnullสตริงเท่ากับ"null"; มิฉะนั้นมูลค่าของobj.toString()จะถูกส่งกลับ

ดังนั้นจึงไม่ควรมีความแตกต่างจริงๆยกเว้นการเรียกใช้เมธอดเพิ่มเติม

นอกจากนี้ในกรณีของObject#toStringถ้าอินสแตนซ์nullที่NullPointerExceptionจะถูกโยนเพื่อให้เนื้อหามันน้อยปลอดภัย

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
นี่คือคำตอบที่ดีที่สุด อ่านและพึ่งพา javadocs ไม่ใช่โค้ด (โดยหลักการแล้วโค้ดอาจแตกต่างกันไปสำหรับ Java เวอร์ชัน / รีลีสที่แตกต่างกัน)
Stephen C

7
@ แบรนดอน - ไม่ถูกต้อง จะต้องเปลี่ยนก็ต่อเมื่อพฤติกรรมเปลี่ยนไปในทางที่ทำให้ javadoc ไม่ถูกต้อง 1) โอกาสที่จะเกิดขึ้นสำหรับวิธีนี้คือศูนย์ พวกเขาจะไม่ทำการเปลี่ยนแปลงที่รับประกันว่ามีการเปลี่ยนแปลงข้อมูลจำเพาะและหากทำเช่นนั้นพวกเขาจะเปลี่ยนข้อมูลจำเพาะ 2) คำแนะนำของฉันไม่ถูกต้อง หากคุณอ่าน javadoc คุณจะเห็นว่าพฤติกรรมในเอกสารเปลี่ยนไป!
Stephen C

2
วิธีที่ทำให้เกิดข้อยกเว้นจะปลอดภัยกว่าไม่ใช่หรือ? โดยปกติแล้วเมื่อโค้ดของคุณพ่น NullPointerException มันเป็นสิ่งที่ดี ในตอนนี้นักพัฒนาซอฟต์แวร์อาจรู้สึกไม่ดี ("ไม่เป็นไรตอนนี้ฉันต้องกลับไปแก้ไขโค้ด") แต่เนื่องจากข้อผิดพลาดเกิดขึ้นคุณจึงพบว่าคุณต้องแก้ไขบางอย่าง อีกวิธีหนึ่งคือคุณกำลังเปิดเผย "null" ให้กับผู้ใช้โดยตรงและไม่ได้รับรายงานข้อผิดพลาดเว้นแต่คุณจะตรวจสอบอย่างชัดเจนซึ่งดูเหมือนว่าฉันจะไม่ค่อยปลอดภัย
Tim M.

1
เพื่อความชัดเจนคุณไม่สามารถเรียกString.valueOf(null)ได้ว่าเป็น NPE ใช้ได้เฉพาะกับวัตถุที่เป็นโมฆะ
Noumenon

1
นั่นไม่ใช่คำอธิบาย String.valueOf(null)จริงจะช่วยแก้ปัญหาให้กับvalueOf(char[])การโอเวอร์โหลด นี้เป็นเพราะเป็นประเภทที่เฉพาะเจาะจงมากขึ้นกว่าchar[] Object
Stephen C

17

ความแตกต่างระหว่าง String.valueOf (Object) และ Object.toString () คือ:

1) ถ้าสตริงเป็นโมฆะ

String.valueOf(Object)จะกลับมาnullในขณะที่Object::toString()จะโยนข้อยกเว้นตัวชี้ว่าง

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) ลายเซ็น:

วิธี valueOf () ของคลาส String เป็นแบบคงที่ ในขณะที่วิธี toString () ของคลาส String ไม่คงที่

ลายเซ็นหรือไวยากรณ์ของวิธี valueOf () ของสตริงได้รับด้านล่าง:

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)

ลายเซ็นหรือไวยากรณ์ของtoString()วิธีการของสตริงได้รับด้านล่าง:

public String toString()

13

ใน Java มีความแตกต่างระหว่าง String.valueOf (Object) และ Object.toString () หรือไม่

ใช่. (และอื่น ๆ อีกมากมายหากคุณคิดว่าเกินกำลัง!)

ตามที่javadocอธิบายString.valueOf((Object) null)จะถือว่าเป็นกรณีพิเศษโดยvalueOfวิธีการและค่า"null"จะถูกส่งกลับ ในทางตรงกันข้ามnull.toString()จะให้ NPE แก่คุณ

การบรรทุกเกินพิกัด

แต่กลับกลายเป็นว่าString.valueOf(null)(โปรดสังเกตความแตกต่าง!) ไม่ให้ NPE ... แม้จะ Javadoc คำอธิบายคลุมเครือ:

  1. มีจำนวนเกินของมีString.valueOfมีสองที่มีความเกี่ยวข้องที่นี่ แต่: และString.valueOf(Object)String.valueOf(char[])

  2. ในนิพจน์String.valueOf(null)โอเวอร์โหลดทั้งสองแบบนั้นใช้ได้เนื่องจากการnullกำหนดเข้ากันได้กับประเภทการอ้างอิงใด ๆ

  3. เมื่อมีโอเวอร์โหลดที่เกี่ยวข้องตั้งแต่สองตัวขึ้นไป JLS จะบอกว่ามีการเลือกโอเวอร์โหลดสำหรับประเภทอาร์กิวเมนต์ที่เฉพาะเจาะจงที่สุด

  4. เนื่องจากchar[]เป็นชนิดย่อยของObjectมันเป็นเฉพาะเจาะจงมากขึ้น

  5. ดังนั้นจึงString.valueOf(char[])เรียกว่าโอเวอร์โหลด

  6. String.valueOf(char[])พ่น NPE หากอาร์กิวเมนต์เป็นอาร์เรย์ว่าง ต่างจากที่String.valueOf(Object)ไม่nullถือเป็นกรณีพิเศษ

(คุณสามารถยืนยันได้โดยใช้javap -cเพื่อตรวจสอบรหัสของวิธีการที่มีการString.valueOf(null)โทรสังเกตการโอเวอร์โหลดที่ใช้สำหรับการโทร)

อีกตัวอย่างหนึ่งแสดงให้เห็นถึงความแตกต่างของการvalueOf(char[])โอเวอร์โหลดที่ชัดเจนยิ่งขึ้น:

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

มีการกำหนดรหัสเฉพาะสำหรับสิ่งเหล่านี้หรือไม่?

เลขที่

ใช้สิ่งที่เคยเหมาะสมที่สุดกับข้อกำหนดของบริบทที่คุณกำลังใช้ (คุณต้องการการจัดรูปแบบเพื่อใช้งานได้nullหรือไม่?)

หมายเหตุ: นั่นไม่ใช่หลักการเขียนโค้ด มันเป็นเพียงการเขียนโปรแกรมสามัญสำนึก สิ่งสำคัญกว่าคือรหัสของคุณจะถูกต้องมากกว่าที่จะเป็นไปตามแบบแผนโวหารหรือหลักปฏิบัติที่ดีที่สุด


ความเห็นส่วนตัว:

นักพัฒนาบางรายได้รับ (IMO) นิสัยที่ไม่ดีในการ "ปกป้อง" จากค่าว่าง คุณจะเห็นการทดสอบจำนวนมากสำหรับค่าว่างและถือว่าค่าว่างเป็นกรณีพิเศษ แนวคิดนี้ดูเหมือนจะป้องกันไม่ให้ NPE เกิดขึ้น

ฉันคิดว่านี่เป็นความคิดที่ไม่ดี. โดยเฉพาะอย่างยิ่งฉันคิดว่ามันเป็นความคิดที่ไม่ดีถ้าสิ่งที่คุณทำเมื่อคุณพบnullคือการพยายาม "ทำให้ดี" ... โดยไม่พิจารณาว่าทำไมถึงมีสิ่งnullนั้น

โดยทั่วไปแล้วจะเป็นการดีกว่าที่จะหลีกเลี่ยงการnullอยู่ที่นั่นตั้งแต่แรก ... เว้นแต่ว่าจะnullมีความหมายที่เฉพาะเจาะจงมากในแอปพลิเคชันหรือการออกแบบ API ของคุณ ดังนั้นแทนที่จะหลีกเลี่ยง NPE ที่มีการเข้ารหัสป้องกันจำนวนมากจะเป็นการดีกว่าที่จะปล่อยให้ NPE เกิดขึ้นจากนั้นติดตามและแก้ไขแหล่งที่มาของสิ่งที่ไม่คาดคิดnullที่ทำให้เกิด NPE

สิ่งนี้ใช้ที่นี่ได้อย่างไร?

ถ้าลองคิดดูการใช้String.valueOf(obj) อาจเป็นวิธี "สร้างความดี" ที่จะหลีกเลี่ยง. ถ้ามันเป็นที่ไม่คาดคิดสำหรับการobjที่จะเป็นในบริบทที่มันจะดีกว่าที่จะใช้nullobj.toString()


5

คำตอบอื่น ๆ กล่าวถึงส่วนใหญ่แล้ว แต่ฉันแค่เพิ่มเพื่อความสมบูรณ์:

  1. Primitives ไม่มี a .toString()เนื่องจากไม่ใช่การนำไปใช้Object-class ดังนั้นจึงString.valueOfสามารถใช้ได้เท่านั้น
  2. String.valueOfจะเปลี่ยนวัตถุที่กำหนดซึ่งเป็นnullString "null"ในขณะที่.toString()จะโยนไฟล์NullPointerException.
  3. คอมไพเลอร์จะใช้String.valueOfโดยค่าเริ่มต้นเมื่อString s = "" + (...);มีการใช้สิ่งที่ต้องการ ซึ่งเป็นสาเหตุที่Object t = null; String s = "" + t;จะส่งผลให้ String "null"ไม่ใช่ใน NPE แก้ไข: อันที่จริงจะใช้StringBuilder.appendไม่ใช่String.valueOf. ดังนั้นอย่าสนใจสิ่งที่ฉันพูดที่นี่

นอกเหนือจากนั้นนี่เป็นกรณีการใช้งานที่String.valueOfและ.toString()มีผลลัพธ์ที่แตกต่างกัน:

สมมติว่าเรามีวิธีการทั่วไปดังนี้:

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

และเราจะเรียกมันด้วยIntegerประเภทดังนี้: Main.<Integer>test().

เมื่อเราสร้าง String โดยString.valueOfใช้งานได้ดี:

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

สิ่งนี้จะส่งออกtestไปยัง STDOUT

ด้วย.toString()แต่มันจะไม่ทำงาน:

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

ซึ่งจะส่งผลให้เกิดข้อผิดพลาดต่อไปนี้:

java.lang.ClassCastException: java.lang.Stringไม่สามารถส่งคลาสไปยังคลาสได้java.lang.Integer

ลองออนไลน์

สำหรับเหตุผลนั้นฉันสามารถอ้างถึงคำถามที่แยกออกมานี้และคำตอบของคำถามนั้นได้ อย่างไรก็ตามในระยะสั้น:

  • เมื่อใช้.toString()ครั้งแรกจะรวบรวมและประเมินวัตถุที่โยนไปT(ซึ่งเป็นStringไปIntegerโยนในกรณีนี้) ClassCastExceptionจะส่งผลให้
  • เมื่อใช้String.valueOfมันจะเห็นทั่วไปTเป็นในระหว่างการรวบรวมและไม่ได้ดูแลเกี่ยวกับเรื่องนี้เป็นObject Integerดังนั้นมันจะส่งObjectไปยังObject(ซึ่งคอมไพเลอร์ก็เพิกเฉย) จากนั้นก็จะใช้งานString.valueOf(Object)ได้ผลStringตามที่คาดไว้ ดังนั้นแม้ว่าString.valueOf(Object)จะดำเนินการ.toString()กับพารามิเตอร์ภายในเราได้ข้ามการแคสต์ไปแล้วและถือว่าเป็นเช่นObjectนั้นดังนั้นเราจึงหลีกเลี่ยงสิ่งClassCastExceptionที่เกิดขึ้นกับการใช้.toString().

แค่คิดว่ามันควรค่าแก่การกล่าวถึงความแตกต่างเพิ่มเติมระหว่างString.valueOfและ.toString()ที่นี่เช่นกัน


ครั้งสุดท้ายที่ฉันสนใจเรื่องนี้ซึ่งน่าจะอยู่ที่ประมาณ JDK 1.2 ("" + x)รวบรวมถึงString.valueOf(x)แต่สิ่งที่ซับซ้อนกว่านั้นก็ใช้ a StringBuffer(เรายังไม่มีStringBuilder)
นีล

4

String.valueOf(Object)และObject.toString()เป็นสิ่งเดียวกันอย่างแท้จริง

หากคุณดูการใช้งานString.valueOf (Object)คุณจะเห็นว่าString.valueOf(Object)โดยพื้นฐานแล้วเป็นเพียงการเรียกtoString()ใช้อ็อบเจ็กต์ที่เหมาะสมโดยไม่มีค่าว่าง:

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();
}

ไม่เป็นความจริงให้ใช้ทั้ง valueOf และ toString ในอาร์เรย์ถ่านและฉลองดวงตาของคุณ
Artanis

3

ความแตกต่างที่สำคัญที่สุดคือวิธีจัดการการอ้างอิง null String

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

เมื่ออาร์กิวเมนต์เป็นnullที่String.valueOfผลตอบแทน"null"แต่Object.toStringโยนNullPointerExceptionว่าเป็นความแตกต่างเพียง


0

มีอีกหนึ่งความแตกต่างที่สำคัญระหว่างสองวิธีคือเมื่อวัตถุที่เรากำลังแปลงเป็นอาร์เรย์

เมื่อคุณแปลงอาร์เรย์โดยใช้ Object.toString () คุณจะได้รับค่าขยะบางประเภท (@ ตามด้วยแฮชโค้ดของอาร์เรย์)

ในการรับ toString () ที่มนุษย์อ่านได้คุณต้องใช้ String.valueOf (char []); โปรดทราบว่าวิธีนี้ใช้ได้กับ Array ของ type char เท่านั้น ฉันอยากจะแนะนำให้ใช้ Arrays.toString (Object []) สำหรับการแปลงอาร์เรย์เป็น String

ความแตกต่างประการที่สองคือเมื่อวัตถุเป็นโมฆะ ValueOf () จะส่งคืน String "null" ในขณะที่ toString () จะส่งกลับข้อยกเว้นของตัวชี้ค่าว่าง


สวัสดี @Tom นี่เป็นจริงสำหรับอาร์เรย์ทุกประเภทอย่างไรก็ตามหากคุณใช้ Arrays.toString (Object []) คุณสามารถแปลงอาร์เรย์ประเภทใดก็ได้เป็นสตริง
chintan thakker

สวัสดี @Tom Object.toString () การส่งคืนค่าขยะเป็นจริงสำหรับอาร์เรย์ทุกประเภทคุณคิดถูกที่ String.valueOf (Array) จะให้สตริงที่ถูกต้องสำหรับอาร์เรย์ประเภทถ่านเท่านั้น ฉันควรจะพูดถึงเรื่องนั้นขอบคุณฉันจะแก้ไข
chintan thakker

1
นั่นไม่ใช่ค่าขยะ แต่เป็นชื่อคลาสและแฮชโค้ด ( JavaDoc )
ทอม

-1

ฉันไม่สามารถบอกได้อย่างชัดเจนว่าความแตกต่างคืออะไร แต่ดูเหมือนจะมีความแตกต่างเมื่อทำงานในระดับไบต์ ในสถานการณ์จำลองการเข้ารหัสต่อไปนี้ Object.toString () สร้างค่าที่ไม่สามารถถอดรหัสได้ในขณะที่ String.valueOf () ทำงานตามที่ตั้งใจไว้ ...

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()

ทำไมถึงล้มเหลว? มีปัญหาอะไร?
Yousha Aleayoub

คำอธิบายก็คือว่าคุณเป็นจริงโทรมากกว่าvalueOf(char[]) valueOf(Object)ลักษณะการทำงานของอย่างมีนัยสำคัญที่แตกต่างกันไปvalueOf(char[]) char[].toString()แต่ไม่ว่าจะด้วยวิธีใดคำตอบนี้ไม่ใช่aproposเพราะคุณกำลังเรียกโอเวอร์โหลดที่แตกต่างจากคำถามที่ถามถึง
Stephen C


-2

ด้านล่างแสดงการใช้งานสำหรับ java.lang.String.valueOf ตามที่อธิบายไว้ในซอร์สสำหรับ jdk8u25 ตามความคิดเห็นของฉันไม่มีความแตกต่าง เรียกว่า "Object.toString" สำหรับประเภทดั้งเดิมจะรวมไว้ในรูปแบบวัตถุและเรียก "toString"

ดูด้านล่าง:

/*
 * 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);
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.