String.valueOf () vs. Object.toString ()


132

Чи є в Java різниця між String.valueOf(Object)і Object.toString()? Чи існує для них певна норма коду?


10
Примітивні типи не мають "toString" .. тому String.valueOfвикористовується. Для об'єктів, які перекривають toString, я думаю, що String.valueOf може зателефонувати до цього. Не впевнений у цій частині, хоча.
Брендон

@Brandon Ви маєте рацію, вона робить саме це, за винятком того, що перевіряє nullспочатку.
azurefrog

Перший коментар тут, я думаю, має найбільше значення, якщо він правильний. Ви повинні використовувати String.valueOf у певних ситуаціях, коли ціль примітивного типу.
Донато

Відповіді:


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
@Brandon - Неправильно. Це потрібно змінити лише в тому випадку, якщо поведінка змінюється способом, який визнає недійсним javadoc. 1) Шанси, що відбудеться для цього методу, є ZERO. Вони не внесуть змін, які б обґрунтували зміну специфікації, і якщо вони це зробили, вони змінили б специфікацію. 2) Це не скасовує мою пораду. Якщо ви прочитаєте javadoc, то побачите, що задокументована поведінка змінилася!
Стівен С

2
Чи не був би метод, який кидає виняток, більш безпечним? Зазвичай, коли ваш код кидає NullPointerException, це щось добре. Можливо, розробнику зараз не здається ("aww, no, зараз мені потрібно повернутися і виправити код"), але оскільки помилка була викинута, ви дізналися, що вам потрібно щось виправити. Залишивши інший шлях, ви виставляєте "null" безпосередньо користувачеві і не отримуєте повідомлення про помилку, якщо ви чітко не перевірите його, що здається мені менш безпечним.
Тім М.

1
Щоб було зрозуміло, ви насправді не можете зателефонувати String.valueOf(null), це NPE. Він працює лише для об’єктів, які є недійсними.
Ноумен

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бути nullв контексті, то краще використовувати obj.toString().


5

Більшість вже згадувалися іншими відповідями, але я просто додаю це для повноти:

  1. Примітиви не мають, .toString()оскільки вони не є реалізацією Objectкласу, тому String.valueOfїх можна використовувати лише.
  2. String.valueOfперетворить заданий об'єкт, що знаходиться nullу String "null", тоді як .toString()кине a NullPointerException.
  3. Компілятор буде використовувати String.valueOfза замовчуванням, коли використовується щось подібне String s = "" + (...);. Ось чому Object t = null; String s = "" + t;це призведе до рядка "null", а не до NPE. EDIT: Насправді, він використовуватиме StringBuilder.append, а не String.valueOf. Тому ігноруйте те, що я тут сказав.

На додаток до них, тут є фактичний випадок використання, де String.valueOfі .toString()є різні результати:

Скажімо, у нас є такий загальний метод:

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

І ми будемо називати його з Integerтипом , як це: Main.<Integer>test().

Коли ми створюємо рядок, 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: class 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()параметр внутрішньо, ми вже пропустили команду та її обробляємо як an Object, тому ми уникнули того, ClassCastExceptionщо відбувається з використанням .toString().

Просто подумав, що варто згадати цю додаткову різницю між String.valueOfі .toString()тут.


Востаннє я піклувався про це, що було б близько JDK 1.2, ("" + x)зібраного String.valueOf(x), але все, що складніше, було використано 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, на масиві char та бенкетуйте очі.
Артаніс

3

Найголовніша відмінність - це те, як вони обробляють нульові посилання 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 []); Зауважте, що цей метод працює лише для масиву типу char. Я б рекомендував використовувати Arrays.toString (Object []) для перетворення масивів у String.

Друга відмінність полягає в тому, що коли об'єкт є null, ValueOf () повертає String "null", тоді як toString () повертає виключення null pointer.


Привіт @Tom це справедливо для масиву будь-якого типу. Однак якщо ви використовуєте Arrays.toString (Object []), ви можете перетворити масив будь-якого типу в рядок.
chintan thakker

Привіт @Tom Object.toString (), що повертає значення сміття, справедливо для масиву будь-якого типу, ви праві, що String.valueOf (Array) надасть правильну рядок лише для масиву типу char. Я мав би сказати, що, дякую, я це відредагую.
Чінтан Тхаккер

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(). Але так чи інакше, ця відповідь не по приводу , тому що ви викликаєте іншу перевантаження в один Питання запитує о.
Стівен С

-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);
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.