Domanda

Sto cercando del codice GXT per GWT e mi sono imbattuto in questo uso di Generics di cui non trovo un altro esempio nei tutorial Java. Il nome della classe è com.extjs.gxt.ui.client.data.BaseModelData se vuoi guardare tutto il codice. Ecco le parti importanti:

private RpcMap map;

public <X> X get(String property) {
  if (allowNestedValues && NestedModelUtil.isNestedProperty(property)) {
    return (X)NestedModelUtil.getNestedValue(this, property);
  }
  return map == null ? null : (X) map.get(property);
}

X non è definito da nessun'altra parte nella classe o in nessun punto della gerarchia e quando premo " vai alla dichiarazione " in eclipse va solo a <X> nella firma del metodo pubblico.

Ho provato a chiamare questo metodo con i seguenti due esempi per vedere cosa succede:

public Date getExpiredate() {
    return  get("expiredate");
}

public String getSubject() {
    return  get("subject");
}

Compilano e non mostrano errori o avvisi. Penserei almeno che dovrei fare un cast per farlo funzionare.

Significa che i generici consentono un valore di ritorno magico che può essere qualsiasi cosa e che esploderà in fase di esecuzione? Questo sembra contrario a ciò che i generici dovrebbero fare. Qualcuno può spiegarmelo e forse darmi un link ad alcuni documenti che lo spiegano un po 'meglio? Ho esaminato il pdf di 23 pagine di Sun sulla generica e ogni esempio di valore di ritorno è definito a livello di classe o è in uno dei parametri passati.

È stato utile?

Soluzione

Il metodo restituisce un tipo di qualunque cosa ti aspetti (<X> è definito nel metodo ed è assolutamente illimitato).

Questo è molto, molto pericoloso in quanto non è previsto che il tipo restituito corrisponda effettivamente al valore restituito.

L'unico vantaggio che ha è che non è necessario eseguire il cast del valore restituito di tali metodi di ricerca generici che possono restituire qualsiasi tipo.

Direi: usa questi costrutti con cura, perché perdi praticamente tutta la sicurezza del tipo e guadagni solo che non devi scrivere un cast esplicito ad ogni chiamata su get().

E sì: questa è praticamente una magia nera che esplode in fase di esecuzione e rompe l'intera idea di ciò che i generici dovrebbero raggiungere.

Altri suggerimenti

Il tipo è dichiarato sul metodo. Questo è quel & Quot; <X> & Quot; si intende. Il tipo viene quindi limitato al solo metodo ed è rilevante per una determinata chiamata. Il motivo per cui viene compilato il codice di test è che il compilatore tenta di determinare il tipo e si lamenterà solo se non è possibile. Ci sono casi in cui devi essere esplicito.

Ad esempio, la dichiarazione per Collections.emptySet() è

public static final <T> Set<T> emptySet()

In questo caso, il compilatore può indovinare:

Set<String> s = Collections.emptySet();

Ma se non è possibile, è necessario digitare:

Collections.<String>emptySet();

Stavo solo cercando di capire la stessa cosa con una classe GXT. In particolare stavo cercando di chiamare un metodo con la firma di:

class Model {
    public <X> X get(String property) { ... }
}

Per chiamare il metodo sopra dal tuo codice e farlo lanciare X su una stringa, faccio quanto segue:

public String myMethod(Data data) {
    Model model = new Model(data);
    return model.<String>get("status");
}

Il codice sopra richiamerà il metodo get e gli dirà che il tipo restituito da X dovrebbe essere restituito come stringa.

Nel caso in cui il metodo sia nella tua stessa classe, ho scoperto che devo chiamarlo con un " questo. " ;. Ad esempio:

this.<String>get("status");

Come altri hanno già detto, questo è piuttosto sciatto e pericoloso dal team GXT.

BaseModelData genera avvisi non controllati durante la compilazione, perché non è sicuro. Usato in questo modo, il tuo codice genererà ClassCastException in fase di esecuzione, anche se non ha alcun avviso stesso.

public String getExpireDate() {
  return  get("expiredate");
}

Nota interessante, da RpcMap (GXT API 1.2)

intestazione di get:

public java.lang.Object get(java.lang.Object key)

Avere un parametro generico di <X> lì che non è supportato ha lo stesso effetto, tranne per il fatto che non devi dire " Oggetto " dappertutto. Sono d'accordo con l'altro poster, questo è sciatto e un po 'pericoloso.

Sì, questo è pericoloso. Normalmente, dovresti proteggere questo codice in questo modo:

<X> getProperty(String name, Class<X> clazz) {
   X foo = (X) whatever(name);
   assert clazz.isAssignableFrom(foo);
   return foo;
}

String getString(String name) {
  return getProperty(name, String.class);
}

int getInt(String name) {
  return getProperty(name, Integer.class);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top