2014-12-25 14 views
13

Non sono sicuro di aver compreso il codice nella riga 1 di seguito?Trasmissione a complementi di interfaccia non implementati

interface Talkable{ } 
class Device{} 
class Phone extends Device implements Talkable{} 


Talkable d = (Talkable) new Device(); //line 1 
Talkable p = new Phone(); //line 2 

Capisco line2 dal telefono implementa talkable, ma periferica e talkable sono indipendenti, come può essere legale linea 1?

risposta

9

In realtà, in Java è perfettamente valido per lanciare un tipo correlato ad un altro (anche se il casting ha poco senso). Si verificherà un errore durante il runtime se i tipi non sono compatibili .

Ad esempio:

public static void main(String[] args) { 
     String s = (String) new Object(); 
     System.out.println(s.intern()); 

    } 

compila bene, ma dà Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String at Sample.main(Sample.java:5) durante il runtime

+0

Hmm, non lo sapevo. Quindi, stai dicendo che anche se il telefono non ha esteso il dispositivo, la prima riga sarebbe comunque passata dal compilatore? – user1529412

+0

@ user1529412 - Sì. Esatto .. Controlla la mia modifica :) – TheLostMind

+1

Perché '(Number)" "' fallisce? – August

5

Linea 1 sarà un'eccezione di runtime. Il compilatore non controlla in fase di compilazione se il cast può essere eseguito correttamente. Questo è il motivo per cui talvolta è consigliabile controllarlo prima con l'operatore instanceof.

In generale, si può sempre gettato una variabile x di tipo A a qualsiasi interfaccia C, perché non può esistere una classe B extends A implements C, o di una classe B implements A, C

Lo stesso non è vero per lanciare una variabile x di classe A a qualsiasi classe D, perché non esiste una sottoclasse E extends A, D, poiché una classe potrebbe non estendere più classi.

18

La ragione il compilatore accetta questo è spiegato nella (parte pertinente in grassetto) JLS section 5.5.1:

Dato un tempo di compilazione tipo di riferimento S (sorgente) e un tipo di riferimento in fase di compilazione T (target) , una conversione di casting esiste da S a T se non si verificano errori di compilazione a causa delle seguenti regole.

Se S è un tipo di classe:

  • Se T è un tipo di classe, allora o | S | <: | T |, o | T | <: | S |. In caso contrario, si verifica un errore in fase di compilazione.

Inoltre, se esiste un supertipo X di T, e un supertipo Y di S, in modo tale che sia X e Y sono tipi parametrici dimostrabilmente distinti (§4.5), e che le cancellature di X e Y sono i lo stesso, si verifica un errore in fase di compilazione.

  • Se T è un tipo di interfaccia:

    • Se S non è una classe finale (§8.1.1), allora, se esiste un supertipo X di T, e un supertipo Y di S, tale che sia X che Y sono tipi parametrici distinti e che le cancellazioni di X e Y sono le stesse, si verifica un errore in fase di compilazione.

      Altrimenti, il cast è sempre legale al momento della compilazione (perché anche se S non implementa T, potrebbe essere una sottoclasse di S).

Nel tuo caso, un java.lang.ClassCastException saranno gettati in fase di esecuzione in quanto Device non possono essere convertiti in Talkable. Ma fino all'esecuzione del programma, il compilatore consente il cast perché potrebbe esistere una sottoclasse di Device che implementa Talkable.

3

In pratica, sulla riga uno il codice "dice" espressamente al compilatore che l'oggetto sul lato destro è un oggetto di tipo sul lato sinistro (questo è chiamato type casting). Questo è valido contro qualsiasi due tipi in Java in fase di compilazione, ma se i tipi non sono correlati, ci sarà un errore di runtime (verrà generato un Exception).

sulla linea due, ciò che viene fatto è valido sia nel tempo che runtime compilazione, perché Phone è di qualsiasi tipo si estende e/o strumenti, quindi in pratica, Phone è un Talkable (e un Device).