2015-06-05 7 views
13

Conosco i tre seguenti metodi che possono essere utilizzati per il cast degli oggetti.Metodi diversi per trasmettere un oggetto in Java

Object o = "str"; 

String str1 = (String) o;    // Method 1 

String str2 = o.toString();    // Method 2 

String str3 = String.class.cast(o);  // Method 3 
  1. Quale approccio è migliore, e quali sono i vantaggi/svantaggi di un metodo rispetto agli altri?
  2. Cosa succede all'oggetto durante il periodo di casting interno?
+7

In realtà,' o.toString() 'non è un cast, si ottiene semplicemente la rappresentazione di stringa di un oggetto;) – NiziL

+0

Manca: 'String str4 = String.valueOf (o);', che è IMHO la soluzione preferita, in quanto non esegue il cast e copre bene il caso che 'o' è' null'. – Marco13

+0

@ Marco13: i ho chiesto questo in una risposta menzionata da "Rahul Tripathi". Questo era nella mia mente, ma ho pensato che fosse piuttosto semplice chiamare il metodo e non si collega al casting –

risposta

11

Il secondo metodo che si mostra non è il casting; è semplicemente chiamando il metodo toString() su un oggetto, che non è diverso da qualsiasi altro metodo di chiamata:

String str2 = o.toString(); 

L'effetto del primo e del terzo metodo è essenzialmente uguale. Preferirei usare il primo metodo.

Cosa è successo con l'oggetto al momento del casting internamente?

Non succede nulla all'oggetto. La trasmissione è non un modo per convertire in qualche modo automaticamente gli oggetti da un tipo a un altro tipo. L'unica cosa che fa un cast è dire al compilatore di accettare la dichiarazione di assegnazione e non controllare i tipi per questa affermazione. Stai dicendo al compilatore "So meglio di te che tipo di oggetto è, quindi lasciami fare questo incarico e non lamentarmi del tipo".

Nell'esempio, il tipo di variabile o è Object. Quando assegni o a una variabile di tipo String, il compilatore non lo consentirà poiché controlla i tipi e non può essere sicuro che o si riferisca effettivamente a un oggetto String. Quindi usi un cast per dire al compilatore "So che questo è un oggetto String, quindi lasciami fare questo incarico".

Il tipo verrà comunque controllato, ma in fase di esecuzione, non in fase di compilazione. Se, durante il runtime, il tipo di oggetto non è String, riceverai uno ClassCastException.

2

qui va:

Object o = "str"; 

String str1 = (String) o; 

questo funziona solo quando l'oggetto in realtà è una stringa.

String str2 = o.toString(); 

Quando si utilizza toString() su un oggetto String, si ottiene la stringa stessa. Genera un'eccezione quando l'oggetto o è nullo.

String str3 = String.class.cast(o); 

Utilizzato principalmente quando si utilizza la riflessione, vale a dire quando si vuole recuperare il token di classe attraverso la riflessione.

+0

cosa dire: String.valueOf (o);? –

+1

Se il tuo oggetto è null quindi 'String.valueOf (o);' restituirà 'null' mentre' o.toString(); 'restituirà' NullPointerException'. Notare che 'String.valueOf()' cerca di vert qualsiasi cosa tu passi in una String. Può gestire sia primitive che oggetti –

+1

'String.valueOf()' restituirà '" null "', non nullo. C'è una differenza. 'o.toString()' farà * gettare * 'NullPointerException'. Non seppellire la risposta nel codice. – EJP

4

Il primo lancia il riferimento o, il cui tipo dichiarato è Oggetto e il cui tipo concreto concreto è String, a String. Questo è il modo canonico di lanciare. Funzionerà solo se l'oggetto a cui fa riferimento o è effettivamente di tipo String. Se non lo è, avrai una ClassCastException.

Il secondo non esegue il cast. Chiama lo toString() sull'oggetto a cui fa riferimento o.Funzionerà sempre, ma è davvero molto diverso da un cast.

Il terzo utilizza la riflessione per eseguire un cast. Ciò avrà lo stesso effetto del primo e funzionerà nelle stesse circostanze. Ma questo sarà generalmente utilizzato solo quando il codice in realtà non conosce il tipo della classe a cast:

Class<?> someClassToCastTo = ...; // could be String.class or anything else, you don't know) 

String str3 = someClassToCastTo.cast(o); 

Non succede nulla all'oggetto quando è fuso. Il cast controlla che l'oggetto sia effettivamente di classe String, e fallisce altrimenti, tutto qui. Ma una volta eseguito il cast su una variabile di tipo String, è possibile accedere ai metodi esistenti in String e che non è possibile chiamare quando si dispone di una variabile di tipo Object.

1

Java è un linguaggio fortemente tipizzato e consente solo la trasmissione di un oggetto a una delle sue classi o interfacce padre. Cioè, se avete la seguente:

class A {} 

interface I {} 

class B extends A implements I {} 

class C {} 

si può lanciare un oggetto di tipo B in questo modo:

B b = new B(); 
A a = b; // no need for explicit casting 
I i = b; 
Object o = b; // Object is implicit parent of A 
C c = b; // ERROR C isn't a parent class of b 

Questo si chiama upcasting. È inoltre possibile bassi:

A a = new B(); 
B b = (B) b; 

è necessario utilizzare cast esplicito qui e JVM controllerà in runtime se il cast è davvero consentita.

Il casting String.class.cast(o) è utile, quando non si conosce il tipo specifico a cui si sta eseguendo il casting in fase di compilazione.

Il .toString() non sta trasmettendo. È solo un metodo, che dovrebbe restituire una rappresentazione String del tuo oggetto. Ma la rappresentazione non è l'oggetto, è solo una rappresentazione. Questo metodo è definito nella classe Object, quindi è presente in tutte le classi e viene leggermente modificato nella lingua. Cioè, se si scrive

String s = "Hell " + o; 

JVM chiamerà o.toString() metodo per voi per ottenere che la rappresentazione.

1

Si può effettivamente ragionare da soli.

$ cat Cast.java 
public class Cast { 
    private Cast() {} 
    public static void main(String[] args) { 
     Object o = "str"; 
     String str1 = (String) o;    // Method 1 
     String str2 = o.toString();    // Method 2 
     String str3 = String.class.cast(o);  // Method 3 
    } 
} 
$ javac Cast.java 
$ javap -c Cast 
Compiled from "Cast.java" 
public class Cast { 
    public static void main(java.lang.String[]); 
    Code: 
     0: ldc   #2     // String str 
     2: astore_1 
     3: aload_1 
     4: checkcast  #3     // class java/lang/String 
     7: astore_2 
     8: aload_1 
     9: invokevirtual #4     // Method java/lang/Object.toString:()Ljava/lang/String; 
     12: astore_3 
     13: ldc   #3     // class java/lang/String 
     15: aload_1 
     16: invokevirtual #5     // Method java/lang/Class.cast:(Ljava/lang/Object;)Ljava/lang/Object; 
     19: checkcast  #3     // class java/lang/String 
     22: astore  4 
     24: return 
} 

Come si può vedere,

  1. Metodo 1 è solo un codice operativo checkcast.
  2. Il metodo 2 è un codice operativo invokevirtual.
  3. Il metodo 3 è un ldc (classe di carico), seguito da invokevirtual e checkcast.

Ovviamente, il Metodo 3 è inferiore in termini di verbosità, leggibilità e prestazioni.

Di 1 e 2, che è meglio?

checkcast significa "guarda questo oggetto: è davvero un String?" - in tal caso, procedere con l'assegnazione; in caso contrario, lanciare un ClassCastException.

invokevirtual significa "guardare in alto, che toString() metodo per chiamata in base alla classe di o" - in questo caso, è String.toString(). L'ovvio attuazione di tale metodo è

public String toString() { 
    return this; 
} 

data la scelta tra chiedere "E 'un String? E" Che tipo è? quale metodo chiamiamo come risultato? Eseguiamo str2 con il parametro implicito. "- Il metodo 1 dovrebbe essere un po 'più semplice