2011-12-27 8 views
19

Supponiamo che io ho due classi derivanti da una terza classe astratta:Esiste una forma di casting "sicuro" in Java?

public abstract class Parent{ 
    public Parent(){ 
    } 
} 

public class ChildA extends Parent { 
    public ChildA { 
    } 
} 

public class ChildB extends Parent { 
    public ChildB { 
    } 
} 

In C# ho potuto gestire la fusione in modo sicuro un po 'tipo da fare:

ChildA child = obj as ChildA; 

che renderebbe bambino == null se non era un oggetto di tipo ChildA. Se dovessi fare:

ChildA child = (ChildA)obj; 

... in C# questo genererebbe un'eccezione se il tipo non era corretto.

Quindi, in pratica, c'è un modo per fare il primo tipo di casting in Java? Grazie.

+0

duplicati : http://stackoverflow.com/questions/148828/how-to-emulate-c-sharp-as-operator-in-java –

+0

Scuse. Ho cercato "type safe casting java". Non mi è venuto in mente di cercare "come parola chiave java". – garrettendi

+3

E poi esplode con un NPE. ;) –

risposta

47

non riesco a pensare a un modo nel linguaggio stesso, ma si può facilmente emulare in questo modo:

ChildA child = (obj instanceof ChildA ? (ChildA)obj : null); 
+0

E a proposito di obj instanceof List ? (Lista ) obj: null? Non è possibile utilizzare l'istanza di un tipo generico, perché scomparirà in fase di esecuzione. – vajanko

+0

@vajanko Hai ragione, non puoi farlo con un tipo generico se devi controllare anche il tipo di articoli. Potresti ancora fare la lista? (Lista) obj: null' - ma riceverai avvertimenti in fase di compilazione. La domanda non ha detto nulla sui generici. –

5

È possibile utilizzare l'operatore instanceof.

if(obj instanceof ChildA){ 
    final ChildA child = (ChildA) obj; 
} 
2

È sempre possibile solo controllare prima:

if (child instanceof ChildA) { 
    ChildA child = (ChildA) child; 
    // Do stuff. 
} 

Oppure fai un semplice metodo:

public ChildA getInstance(Parent p) { 
    if (child instanceof ChildA) { 
     return (ChildA) p; 
    } else { 
     return null; 
    } 
} 
9

In java 8 è anche possibile utilizzare la sintassi ruscello con Optional:

Object o = new Integer(1); 

    Optional.ofNullable(o) 
      .filter(Number.class::isInstance) 
      .map(Number.class::cast) 
      .ifPresent(n -> System.out.print("o is a number")); 
1

Penso che il modo migliore per affrontare questo è di usare metodi generici. Questa è a mio parere l'opzione più riutilizzabile/sicura.

ecco quello che sono venuto a:

@SuppressWarnings("unchecked") 
public <E> E coerceTo(Object o, Class<E> target) throws IllegalArgumentException { 
    if(target.isInstance(o)) return (E)o; 
    String msg = "expected "+target.getName()+" but was "+o.getClass().getName(); 
    throw new IllegalArgumentException(msg); 
} 

Si noti che qui, il cast è sicuro ed è corretto aggiungere le SuppressWarnings annotazione.

Ecco un esempio di come chiamare il metodo:

Object o = 1; 
int a = coerceTo(o, Integer.class); 
2

È possibile utilizzare questo metodo che è compatibile con tutti i tipi Java:

public static <T> T safeCast(Object o, Class<T> clazz) { 
    return clazz != null && clazz.isInstance(o) ? clazz.cast(o) : null; 
} 

Esempio:

// A given object obj 
Integer i = safeCast(obj, Integer.class);