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

132

Gibt es in Java einen Unterschied zwischen String.valueOf(Object)und Object.toString()? Gibt es eine spezielle Code-Konvention für diese?

MCMastery
quelle
10
Primitive Typen haben keinen "toString". Wird also String.valueOfverwendet. Für Objekte, die toString überschreiben, könnte String.valueOf dies stattdessen aufrufen. Ich bin mir jedoch nicht sicher.
Brandon
@Brandon Sie sind richtig, es macht genau das, außer dass es zuerst prüft null.
Azurefrog
Der erste Kommentar hier ist meiner Meinung nach am sinnvollsten, wenn er richtig ist. Sie müssen String.valueOf in bestimmten Situationen verwenden, in denen das Ziel ein primitiver Typ ist.
Donato

Antworten:

177

Nach der Java - Dokumentation , String.valueOf()kehrt:

Wenn das Argument ist null, dann ist eine Zeichenfolge gleich "null"; Andernfalls wird der Wert von obj.toString()zurückgegeben.

Es sollte also keinen wirklichen Unterschied geben, außer einem zusätzlichen Methodenaufruf.

Auch im Fall von Object#toString, wenn die Instanz ist null, wird ein NullPointerExceptionWurf ausgelöst, so dass es wohl weniger sicher ist .

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
} 
Kuba Rakoczy
quelle
6
Dies ist die beste Antwort. Lesen und verlassen Sie sich auf die Javadocs, nicht auf den Code. (Der Code kann im Prinzip für verschiedene Versionen / Versionen von Java unterschiedlich sein.)
Stephen C
7
@Brandon - Falsch. Es muss sich nur ändern, wenn sich das Verhalten so ändert, dass das Javadoc ungültig wird. 1) Die Wahrscheinlichkeit, dass dies bei dieser Methode passiert, ist NULL. Sie werden keine Änderungen vornehmen, die eine Änderung der Spezifikation rechtfertigen, und wenn sie dies tun würden , würden sie die Spezifikation ändern. 2) Es macht meinen Rat nicht ungültig. Wenn Sie das Javadoc lesen, werden Sie feststellen, dass sich das dokumentierte Verhalten geändert hat!
Stephen C
2
Wäre nicht das Verfahren, das die Ausnahme sein wirft mehr sicher? Wenn Ihr Code eine NullPointerException auslöst, ist dies normalerweise eine gute Sache. Es mag sich für den Entwickler im Moment nicht gut anfühlen ("aww, nein, jetzt muss ich zurückgehen und meinen Code reparieren"), aber da der Fehler ausgelöst wurde, haben Sie herausgefunden, dass Sie etwas reparieren müssen. In der anderen Richtung setzen Sie die "Null" direkt dem Benutzer aus und erhalten keinen Fehler gemeldet, es sei denn, Sie suchen explizit nach einem, was mir weniger sicher erscheint.
Tim M.
1
Nur um klar zu sein, man kann eigentlich nicht anrufen String.valueOf(null), das ist eine NPE. Es funktioniert nur für Objekte, die null sind.
Noumenon
1
Das ist nicht die Erklärung. Das String.valueOf(null)löst sich tatsächlich zur valueOf(char[])Überlastung auf. Dies liegt daran, dass char[]es sich um einen spezifischeren Typ als handelt Object.
Stephen C
17

Unterschiede zwischen String.valueOf (Object) und Object.toString () sind:

1) Wenn der String null ist,

String.valueOf(Object)wird zurückgegeben null, während Object::toString()eine Nullzeigerausnahme ausgelöst wird.

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) Unterschrift:

Die valueOf () -Methode der String-Klasse ist statisch. Die toString () -Methode der String-Klasse ist nicht statisch.

Die Signatur oder Syntax der valueOf () -Methode des Strings ist unten angegeben:

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)

Die Signatur oder Syntax der String- toString()Methode ist unten angegeben:

public String toString()
Shipra Sharma
quelle
13

Gibt es in Java einen Unterschied zwischen String.valueOf (Object) und Object.toString ()?

Ja. (Und mehr noch, wenn Sie eine Überlastung in Betracht ziehen!)

Wie der Javadoc erklärt, String.valueOf((Object) null)wird er von der valueOfMethode als Sonderfall behandelt und der Wert "null"zurückgegeben. Im Gegensatz,null.toString() dazu erhalten Sie nur eine NPE.

Überlastung

Es stellt sich heraus , dass String.valueOf(null)(beachten Sie den Unterschied!) Hat eine NPE geben ... trotz der javadoc. Die Erklärung ist dunkel:

  1. Es gibt eine Reihe von Überlastungen von String.valueOf, aber es gibt zwei, die hier relevant sind: String.valueOf(Object)und String.valueOf(char[]).

  2. Im Ausdruck String.valueOf(null) sind diese beiden Überladungen anwendbar , da nulldie Zuweisung mit jedem Referenztyp kompatibel ist.

  3. Wenn zwei oder mehr zutreffen Überladungen vorliegen, gibt das JLS an, dass die Überladung für den spezifischsten Argumenttyp ausgewählt wird.

  4. Da char[]ist ein Subtyp vonObject , ist er spezifischer .

  5. Deshalb, die String.valueOf(char[]) Überlastung aufgerufen.

  6. String.valueOf(char[])löst eine NPE aus, wenn ihr Argument ein Null-Array ist. nicht wieString.valueOf(Object) wird es nicht nullals Sonderfall behandelt .

(Sie können dies mit bestätigen javap -c den Code einer Methode untersuchen, die einen String.valueOf(null)Aufruf hat. Beobachten Sie die Überlastung, die für den Aufruf verwendet wird.)

Ein weiteres Beispiel verdeutlicht den Unterschied in der valueOf(char[])Überlastung noch deutlicher:

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

Gibt es eine spezielle Code-Konvention für diese?

Nein.

Verwenden Sie, was für die Anforderungen des Kontexts, in dem Sie es verwenden, am besten geeignet ist. (Do Sie müssen die Formatierung Arbeit fürnull ?)

Hinweis: Dies ist keine Codekonvention. Es ist nur gesunder Menschenverstand Programmierung. Es ist wichtiger, dass Ihr Code korrekt ist, als einer Stilkonvention oder einem "Best Practice" -Dogma zu folgen.


Persönliche Meinung:

Einige Entwickler haben die schlechte Angewohnheit (IMO), sich gegen Nullen zu "verteidigen". Sie sehen also viele Tests für Nullen und behandeln Nullen als Sonderfälle. Die Idee scheint zu sein, NPE zu verhindern.

Ich denke, das ist eine schlechte Idee. Insbesondere denke ich, dass es eine schlechte Idee ist, wenn Sie nullversuchen, "gut zu machen", ohne zu überlegen, warum es dort eine nullgab.

Im Allgemeinen ist es besser, zu vermeiden, nulldass Sie überhaupt da sind ... es sei denn, das nullhat eine ganz bestimmte Bedeutung in Ihrer Anwendung oder Ihrem API-Design. Anstatt die NPE mit viel defensiver Codierung zu vermeiden, ist es besser, die NPE passieren zu lassen und dann die Quelle des Unerwarteten aufzuspüren und zu beheben null, das die NPE ausgelöst hat.

Wie trifft dies hier zu?

Nun, wenn Sie darüber nachdenken, String.valueOf(obj) könnte die Verwendung eine Möglichkeit sein, "Gutes zu tun". Das ist zu vermeiden. Wenn es unerwartet ist obj, nullim Kontext zu sein, ist es besser zu verwenden obj.toString().

Stephen C.
quelle
5

Das meiste wurde bereits in anderen Antworten erwähnt, aber ich füge es der Vollständigkeit halber hinzu:

  1. Primitive haben keine, .toString()da sie keine Implementierung der ObjectKlasse sind und daher nur String.valueOfverwendet werden können.
  2. String.valueOftransformiert ein bestimmtes Objekt, das sich nullin den String befindet "null", während .toString()a NullPointerException.
  3. Der Compiler wird String.valueOfstandardmäßig verwendet, wenn so etwas String s = "" + (...);verwendet wird. Aus diesem Grund Object t = null; String s = "" + t;wird der String "null"und nicht ein NPE angezeigt. EDIT: Eigentlich wird es das verwenden StringBuilder.append, nicht String.valueOf. Ignorieren Sie also, was ich hier gesagt habe.

Zusätzlich zu diesen ist hier tatsächlich ein Anwendungsfall, wo String.valueOfund.toString() unterschiedliche Ergebnisse haben:

Nehmen wir an, wir haben eine generische Methode wie diese:

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

Und wir nennen es mit einem IntegerTyp wie diesem:Main.<Integer>test() .

Wenn wir damit einen String erstellen String.valueOf, funktioniert das einwandfrei:

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

Dies wird ausgegeben test an STDOUT ausgegeben.

Mit einem .toString()wird es jedoch nicht funktionieren:

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

Dies führt zu folgendem Fehler:

java.lang.ClassCastException: Klasse java.lang.Stringkann nicht in Klasse umgewandelt werdenjava.lang.Integer

Probieren Sie es online aus.

Was den Grund betrifft, kann ich auf diese getrennte Frage und ihre Antworten verweisen . Kurz jedoch:

  • Bei der Verwendung .toString()wird es zuerst kompilieren und zu bewerten das Objekt, in dem die Besetzung auf T(die eine ist Stringzu IntegerBesetzung in diesem Fall) in dem Ergebnis ClassCastException.
  • Bei der Verwendung String.valueOfwird das Generikum Twie Objectbeim Kompilieren angezeigt und es ist nicht einmal wichtig, dass es ein Integer. Es wird also ein Objectto umgewandelt Object(was der Compiler einfach ignoriert). Dann wird es verwendet String.valueOf(Object), was zu einem Stringwie erwartet führt. Obwohl der String.valueOf(Object)Wille .toString()intern einen Parameter ausführt, haben wir die Besetzung bereits übersprungen und sie wird wie eine behandelt Object, sodass wir das vermieden haben ClassCastException, was bei der Verwendung von auftritt .toString().

Ich dachte nur, es wäre erwähnenswert, diesen zusätzlichen Unterschied zwischen String.valueOfund auch .toString()hier zu erwähnen .

Kevin Cruijssen
quelle
Das letzte Mal habe ich mich darum gekümmert, was ungefähr JDK 1.2 gewesen wäre, ("" + x)kompiliert String.valueOf(x), aber alles, was komplizierter ist, hat a verwendet StringBuffer(wir hatten es StringBuilderdamals nicht).
Neil
4

String.valueOf(Object)und Object.toString()sind buchstäblich das gleiche.

Wenn Sie sich die Implementierung von String.valueOf (Object) ansehen , werden Sie feststellen , dass dies String.valueOf(Object)im Grunde nur ein null-sicherer Aufruf des toString()entsprechenden Objekts ist:

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();
}
Azurblau
quelle
Nicht wahr, verwenden Sie sowohl valueOf als auch toString für ein Char-Array und genießen Sie Ihre Augen.
Artanis
3

Der wichtigste Unterschied ist die Art und Weise, wie sie mit Null-String-Referenzen umgehen.

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
Abdullah Khan
quelle
1

Wenn Argument ist null, String.valueOfkehrt das zurück "null", Object.toStringwirft aber NullPointerException, das ist der einzige Unterschied.

Everv0id
quelle
0

Es gibt einen weiteren großen Unterschied zwischen den beiden Methoden, wenn das Objekt, das wir konvertieren, ein Array ist.

Wenn Sie ein Array mit Object.toString () konvertieren, erhalten Sie eine Art Müllwert (@ gefolgt vom Hashcode des Arrays).

Um ein für Menschen lesbares toString () zu erhalten, müssen Sie String.valueOf (char []) verwenden. Bitte beachten Sie, dass diese Methode nur für Arrays vom Typ char funktioniert. Ich würde empfehlen, Arrays.toString (Object []) zum Konvertieren von Arrays in String zu verwenden.

Der zweite Unterschied besteht darin, dass ValueOf (), wenn das Objekt null ist, einen String "null" zurückgibt, während toString () eine Nullzeigerausnahme zurückgibt.

Chintan Thakker
quelle
Hallo @ Tom, dies gilt für ein Array eines beliebigen Typs. Wenn Sie jedoch Arrays.toString (Object []) verwenden, können Sie ein Array eines beliebigen Typs in einen String konvertieren.
Chintan Thakker
Hi @Tom Object.toString (), das einen Garbage-Wert zurückgibt, gilt für ein Array eines beliebigen Typs. Sie haben Recht, dass String.valueOf (Array) nur für ein Array vom Typ char einen korrekten String angibt. Ich hätte erwähnen sollen, dass ich es danke bearbeiten werde.
Chintan Thakker
1
Das ist kein Müllwert, sondern der Klassenname und der Hashcode ( JavaDoc ).
Tom
-1

Ich kann nicht genau sagen, was der Unterschied ist, aber es scheint einen Unterschied zu geben, wenn auf Byte-Ebene gearbeitet wird. Im folgenden Verschlüsselungsszenario hat Object.toString () einen Wert erzeugt, der nicht entschlüsselt werden konnte, während String.valueOf () wie beabsichtigt funktionierte ...

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()
Chris Walters
quelle
Warum gescheitert? was ist das Problem?
Yousha Aleayoub
Die Erklärung ist, dass Sie tatsächlich valueOf(char[])eher anrufen als valueOf(Object). Das Verhalten von unterscheidet valueOf(char[])sich erheblich von char[].toString(). In beiden Fällen ist diese Antwort nicht zutreffend, da Sie eine andere Überlastung als die in der Frage gestellte nennen.
Stephen C
-2

Das Folgende zeigt die Implementierung für java.lang.String.valueOf, wie in der Quelle für jdk8u25 beschrieben. Nach meinem Kommentar gibt es also keinen Unterschied. Es ruft "Object.toString" auf. Bei primitiven Typen wird es in seine Objektform eingeschlossen und "toString" darauf aufgerufen.

Siehe unten:

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