2013-02-25 18 views
7

Considerare l'interfaccia UnaryFunction definita nel capitolo Java efficace generici.Perché è sicuro sopprimere questo avviso non controllato?

public interface UnaryFunction<T> { 
T apply(T arg); 
} 

e il seguente codice per la restituzione UnaryFunction

// Generic singleton factory pattern 
private static UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() { 
    public Object apply(Object arg) { return arg; } 
}; 

// IDENTITY_FUNCTION is stateless and its type parameter is 
// unbounded so it's safe to share one instance across all types. 
@SuppressWarnings("unchecked") 
public static <T> UnaryFunction<T> identityFunction() { 
    return (UnaryFunction<T>) IDENTITY_FUNCTION; 
} 

Perché il cast di IDENTITY_FUNCTION a (UnaryFunction<T>) sicuro?

Il libro dice questo sulla domanda che sto chiedendo ma non posso seguire la logica qui. Dove stiamo invocando la funzione apply che esegue l'operazione di identità? Sono confuso perché è quella funzione che restituisce lo stesso oggetto passato senza modificare nulla.

Il cast di il_più_grande_comune_divisore ad (UnaryFunction<T>) genera un allarme incontrollato cast, come UnaryFunction<Object> non è un UnaryFunction<T> per ogni T. Ma la funzione di identità è speciale: è restituisce il suo argomento non modificato, quindi sappiamo che è typesa da usare come UnaryFunction<T> qualunque sia il valore di T. Pertanto, possiamo sopprimere con sicurezza l'avviso di cast non controllato generato da questo cast. Una volta fatto, il codice viene compilato senza errori o con l'avviso .

+0

Domanda laterale: che libro stai usando e dice qual è il punto di questo codice? – asteri

+0

@Jeff Efficace java è il nome del libro ed è lì nel capitolo generici, in particolare nella sezione che descrive le funzioni generiche. – Geek

risposta

3

Il cast è sicuro tanto solo come la funzione identità restituisce l'oggetto esatto che è stato passato ad essa in primo luogo. Pertanto, in fase di runtime, non esiste una specializzazione del parametro generico T che può violare il cast.

Aka, si sta lanciando un oggetto come se fosse un proprio tipo.

3

Con la cancellazione di tipo

T apply(T arg); 

in realtà è

Object apply(Object arg); 

Ora per l'identità

Abc x = ...; 
Abc y = IDENTITY.apply(x); 

si può supporre che sia sempre corretto (è equivalente a y = x;).

(molto pragmatico.)

+0

Dov'è 'apply' chiamato nel codice in questione? – Geek

+0

Ogniqualvolta viene applicata la funzione identità (.apply) il risultato viene assegnato a T IDENTITY.apply (T), che normalmente non può essere eseguito, poiché il parametro T non è presente in fase di esecuzione. –

1

identityFunction() restituisce semplicemente la funzione stessa, da utilizzare su oggetti diversi.

Di seguito è riportato un esempio di utilizzo: avviso di sicurezza

String result = identityFunction().apply("Hello"); 

Il tipo è importante. È lì perché IDENTITY_FUNCTION è implementato in modo tale che il compilatore non possa garantire che la funzione restituisca lo stesso tipo dell'input. Si consideri il seguente implementazione alternativa:

private static UnaryFunction<Object> CONST_FUNCTION = new UnaryFunction<Object>() { 
    public Object apply(Object arg) { return "Default"; } 
}; 

Questa implementazione restituisce sempre una stringa, quindi non è, ovviamente, sicuro di tornare come una funzione unaria su un tipo di dati generici.

Nel nostro caso (IDENTITY_FUNCTION), la prova che il tipo restituito è uguale al tipo di input è all'interno dell'implementazione. Restituiamo la stessa istanza, quindi è garantito che abbia lo stesso tipo. Quando si sopprimono i tipi di avvisi di sicurezza, si consiglia di giustificarli con una prova.

+0

-1 Confusione. IdentityFunction() non restituisce la "funzione stessa", restituisce lo stesso _argument_. Non vedo alcun motivo per cui questo risultato, di tipo T sia "da utilizzare su oggetti diversi". Nel tuo esempio, è una stringa che _ non può essere _utilizzata_ su oggetti diversi. – user949300

+1

@ user949300: 'identityFunction()' restituisce un riferimento all'oggetto memorizzato nella variabile 'IDENTITY_FUNCTION'. Tale riferimento consente di chiamare 'apply()', quindi 'identityFunction()' restituisce effettivamente la funzione stessa. Sarebbe stato meglio se i nomi non fossero gli stessi. Ex 'getIdentityFunction()' e 'IDENTITY_FUNCTION'. La prima riga della risposta si riferisce al metodo getter. – unholysampler

+0

grazie - capito. Questa intera domanda/sistema è molto confusa per qualcosa che non fa nulla :-). Non riesco a "annullare" il mio downvote fino a quando non modifichi la risposta a causa delle limitazioni in StackOverflow. – user949300

Problemi correlati