String.valueOf () a Object.toString ()


139

Czy w Javie jest jakaś różnica między String.valueOf(Object)i Object.toString()? Czy istnieje dla nich określona konwencja kodowa?


10
Typy pierwotne nie mają „toString” .. więc String.valueOfjest używane. W przypadku obiektów, które przesłaniają toString, myślę, że String.valueOf może to wywołać. Nie jestem pewien co do tej części.
Brandon

@Brandon Masz rację, robi dokładnie to, z wyjątkiem tego, że nullnajpierw sprawdza .
azurefrog

Myślę, że pierwszy komentarz tutaj ma największy sens, jeśli jest poprawny. Musisz użyć String.valueOf w niektórych sytuacjach, gdy cel jest typem pierwotnym.
Donato,

Odpowiedzi:


189

Według dokumentacji Java , String.valueOf()Powroty:

jeśli argumentem jest null, to łańcuch równy "null"; w przeciwnym razie zwracana obj.toString()jest wartość .

Więc tak naprawdę nie powinno być żadnej różnicy, z wyjątkiem dodatkowego wywołania metody.

Ponadto w przypadku Object#toString, gdy instancja jest null, NullPointerExceptionzostanie wyrzucona a, więc prawdopodobnie jest mniej bezpieczny .

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
To najlepsza odpowiedź. Przeczytaj javadoc i polegaj na nim, a nie na kodzie. (Kod może zasadniczo być inny dla różnych wersji / wydań Java.)
Stephen C,

8
@Brandon - niepoprawne. Musi się zmienić tylko wtedy, gdy zachowanie zmieni się w sposób, który unieważnia javadoc. 1) Szanse na to w przypadku tej metody wynoszą ZERO. Nie dokonają zmiany, która uzasadniałaby zmianę specyfikacji, a gdyby to zrobili, to zmieniliby specyfikację. 2) Nie unieważnia mojej rady. Jeśli przeczytasz javadoc, zobaczysz, że udokumentowane zachowanie się zmieniło!
Stephen C

2
Nie metoda, która zgłasza wyjątek być bardziej bezpieczne? Zwykle, gdy kod rzuca wyjątek NullPointerException, jest to w pewnym sensie dobra rzecz. Może to nie być przyjemne dla programisty w tej chwili („aww, nie, teraz muszę wrócić i naprawić mój kod”), ale ponieważ został zgłoszony błąd, okazało się, że trzeba coś naprawić. W przeciwnym razie ujawniasz wartość „null” bezpośrednio użytkownikowi i nie otrzymujesz zgłoszenia błędu, chyba że wyraźnie go sprawdzisz, co wydaje mi się mniej bezpieczne.
Tim M.

1
Żeby było jasne, nie możesz faktycznie zadzwonić String.valueOf(null), to jest NPE. Działa tylko dla obiektów, które są zerowe.
Noumenon

1
To nie jest wyjaśnienie. W String.valueOf(null)rzeczywistości rozwiązuje to valueOf(char[])przeciążenie. Dzieje się tak, ponieważ char[]jest to bardziej szczegółowy typ niż Object.
Stephen C

17

Różnice między String.valueOf (Object) i Object.toString () to:

1) Jeśli string jest pusty,

String.valueOf(Object) wróci null , podczas gdy Object::toString()zgłosi wyjątek wskaźnika o wartości 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) Podpis:

valueOf () klasy String jest statyczna. natomiast metoda toString () klasy String nie jest statyczna.

Podpis lub składnię metody valueOf () ciągu znaków podano poniżej:

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)

Podpis lub składnia metody string toString()jest podana poniżej:

public String toString()

13

Czy w Javie jest jakaś różnica między String.valueOf (Object) i Object.toString ()?

Tak. (I bardziej, jeśli weźmiesz pod uwagę przeciążenie!)

Jak wyjaśnia javadoc , metoda String.valueOf((Object) null)będzie traktowana jako specjalny przypadek valueOfi zwracana "null"będzie wartość . Natomiast null.toString()po prostu da ci NPE.

Przeciążenie

Okazuje się, że String.valueOf(null)(uwaga różnicę!) Nie dają NPE ... mimo javadoc. Prawdziwe wyjaśnienie 1 jest niejasne:

  1. Istnieje wiele przeciążeń String.valueOf, ale są dwa, które są tutaj istotne: String.valueOf(Object)i String.valueOf(char[]).

  2. W wyrażeniu String.valueOf(null)oba te przeciążenia mają zastosowanie , ponieważ nullprzypisanie jest zgodne z dowolnym typem odwołania.

  3. Gdy istnieją dwa lub więcej odpowiednich przeciążeń, JLS mówi, że wybrano przeciążenie dla najbardziej określonego typu argumentu.

  4. Ponieważ char[]jest podtypem Object, jest bardziej szczegółowy .

  5. Dlatego String.valueOf(char[])wywoływane jest przeciążenie.

  6. String.valueOf(char[])zgłasza NPE, jeśli jego argument jest tablicą zerową. W przeciwieństwie do String.valueOf(Object)tego nie traktuje to nulljako przypadku specjalnego.

Inny przykład valueOf(char[])jeszcze wyraźniej ilustruje różnicę w przeciążeniu:

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

Czy istnieje dla nich określona konwencja kodowa?

Nie.

Użyj tego, który kiedykolwiek jest najbardziej odpowiedni dla wymagań kontekstu, w którym go używasz. (Czy potrzebujesz formatowania do pracynull ?)

Uwaga: to nie jest konwencja kodowa. To po prostu programowanie oparte na zdrowym rozsądku. To jest ważniejsze , że kod jest poprawny , niż jest przestrzegać pewnych konwencji stylistycznej lub „najlepsze praktyki” dogma 2 .


1 - Możesz to potwierdzić, javap -csprawdzając kod metody, która ma String.valueOf(null)wywołanie. Obserwuj przeciążenie używane w wywołaniu.

2 - Przeczytaj „Brak dobrych praktyk” i przekaż to odniesienie następnej osobie, która powie Ci, że „najlepszą praktyką” jest zrobienie czegoś w dziedzinie programowania lub IT.


Osobista opinia

Niektórzy programiści nabierają (IMO) złego nawyku „obrony” przed zerami. Widzisz więc wiele testów dla wartości null i traktuje je jako przypadki specjalne. Wydaje się, że chodzi o to, aby zapobiec wystąpieniu NPE.

Myślę, że to zły pomysł. W szczególności uważam, że złym pomysłem jest, jeśli to, co robisz, gdy znajdujesz, nullto próba „naprawienia dobra” ... bez zastanowienia się, dlaczego tak się nullstało.

Ogólnie rzecz biorąc, lepiej jest unikać nullbycia tam w pierwszej kolejności ... chyba że nullma to bardzo konkretne znaczenie w twojej aplikacji lub projekcie API. Dlatego zamiast unikać NPE z dużą ilością kodowania obronnego, lepiej pozwolić, aby NPE się wydarzyło, a następnie wyśledzić i naprawić źródło nieoczekiwanegonull które wywołało NPE.

Więc jak to się ma tutaj?

Cóż, jeśli się nad tym zastanowić, używanie String.valueOf(obj) może być sposobem na „poprawę”. Tego należy unikać. Jeśli jest to nieoczekiwane, objaby znaleźć się nullw kontekście, lepiej użyć obj.toString().


6

Większość z nich została już wspomniana w innych odpowiedziach, ale dodam to tylko dla kompletności:

  1. Prymitywy nie mają .toString()znaku, ponieważ nie są implementacją Object-class, więc String.valueOfmożna ich używać tylko.
  2. String.valueOfprzekształci dany obiekt, który jest nullna String "null", podczas gdy .toString()wyrzuci NullPointerException.
  3. Kompilator użyje String.valueOfdomyślnie, gdy String s = "" + (...);zostanie użyte coś podobnego . Dlatego też Object t = null; String s = "" + t;spowoduje powstanie ciągu "null", a nie NPE. EDYCJA: Właściwie użyje StringBuilder.append, nie String.valueOf. Więc zignoruj ​​to, co tutaj powiedziałem.

Oprócz tych, tutaj jest faktycznie przypadek użycia, w którym String.valueOfi .toString()mają różne wyniki:

Powiedzmy, że mamy taką ogólną metodę:

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

Nazwiemy to następującym Integertypem:Main.<Integer>test() .

Kiedy tworzymy z String.valueOfnim String , działa dobrze:

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

Spowoduje to wyjście testdo STDOUT.

Z .toString()jednak, że nie będzie działać:

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

Spowoduje to następujący błąd:

java.lang.ClassCastException: klasa java.lang.Stringnie może być rzutowana na klasęjava.lang.Integer

Wypróbuj online.

Jeśli chodzi o dlaczego, mogę odnieść się do tego oddzielnego pytania i odpowiedzi na nie . W skrócie jednak:

  • Podczas korzystania .toString()będzie to pierwsza kompilacja i ocena obiektu, gdzie obsada do T(który jest Stringdo Integerobsady w tym przypadku) spowoduje ClassCastException.
  • Podczas korzystania z String.valueOfniego zobaczysz ogólny Tjak Objectpodczas kompilacji i nawet nie przejmuje się tym, że jest to plik Integer. Więc będzie to rzutować Objectna Object(co kompilator po prostu ignoruje). Wtedy użyje String.valueOf(Object), dając Stringzgodnie z oczekiwaniami. Więc nawet jeśli funkcja String.valueOf(Object)zrobi a .toString()na parametrze wewnętrznie, już pominęliśmy rzutowanie i jest traktowane jak an Object, więc uniknęliśmy tego, ClassCastExceptionco występuje przy użyciu .toString().

Pomyślałem, że warto wspomnieć o tej dodatkowej różnicy między String.valueOfi .toString()tutaj.


Ostatni raz przejmowałem się tym, który byłby w okolicach JDK 1.2, ("" + x)skompilowany do String.valueOf(x), ale cokolwiek bardziej skomplikowanego używało a StringBuffer(nie mieliśmy StringBuilderwtedy).
Neil

4

String.valueOf(Object)i Object.toString()są dosłownie tym samym.

Jeśli spojrzysz na implementację String.valueOf (Object) , zobaczysz, że String.valueOf(Object)jest to po prostu bezpieczne wywołanie toString()odpowiedniego obiektu z wartością null :

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

Nieprawda, użyj zarówno valueOf, jak i toString na tablicy znaków i ciesz się oczami.
Artanis,

3

Najważniejszą różnicą jest sposób, w jaki obsługują one zerowe odwołania typu 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

Gdy argument to null, String.valueOfzwraca "null", ale Object.toStringrzuca NullPointerException, to jedyna różnica.


0

Jest jeszcze jedna główna różnica między tymi dwiema metodami, gdy konwertowany obiekt jest tablicą.

Kiedy konwertujesz tablicę za pomocą Object.toString (), otrzymasz jakiś rodzaj śmieci (@, po którym następuje hashcode tablicy).

Aby uzyskać czytelną dla człowieka metodę toString (), należy użyć String.valueOf (char []); plz zauważ, że ta metoda działa tylko dla Array typu char. Poleciłbym użycie Arrays.toString (Object []) do konwersji tablic na String.

Druga różnica polega na tym, że gdy obiekt ma wartość null, ValueOf () zwraca String „null”, a toString () zwróci wyjątek wskaźnika zerowego.


Cześć @Tom, to prawda dla tablicy dowolnego typu, jednak jeśli używasz Arrays.toString (Object []), możesz przekonwertować tablicę dowolnego typu na ciąg.
chintan thakker

Cześć, @Tom Object.toString () zwracająca wartość śmieciową jest prawdą dla tablicy dowolnego typu, masz rację, że String.valueOf (Array) poda poprawny ciąg tylko dla tablicy typu char. Powinienem był o tym wspomnieć, dzięki, będę go edytować.
chintan thakker

1
To nie jest wartość śmieciowa, to nazwa klasy i kod skrótu ( JavaDoc ).
Tom

-1

Poniżej przedstawiono implementację java.lang.String.valueOf zgodnie z opisem w źródle jdk8u25. Więc jak na mój komentarz, nie ma różnicy. Wywołuje „Object.toString”. W przypadku typów pierwotnych opakowuje go w postać obiektu i wywołuje na nim „toString”.

Zobacz poniżej:

/*
 * 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);
    }

-1

Nie mogę dokładnie powiedzieć, na czym polega różnica, ale wydaje się, że istnieje różnica podczas pracy na poziomie bajtów. W następującym scenariuszu szyfrowania Object.toString () wygenerował wartość, której nie można było odszyfrować, podczas gdy String.valueOf () działało zgodnie z zamierzeniami ...

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

Dlaczego się nie udało? jaki jest problem?
Yousha Aleayoub

Wyjaśnienie jest takie, że faktycznie dzwonisz, valueOf(char[])a nie valueOf(Object). Zachowanie valueOf(char[])znacznie różni się od char[].toString(). Ale tak czy inaczej, ta odpowiedź nie jest apropos ponieważ dzwonisz inny przeciążenie na jednym pytaniem pyta o.
Stephen C
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.