Domanda

Esiste una classe astratta:

public abstract class AbstractAny {
  private long period;

  public void doSomething() {
    // blah blah blah
    period = someHardcodedValue;
    // blah blah blah
  }
}

Non voglio cambiare l'origine della classe astratta ma devo aggiungere una certa flessibilità su come viene impostato il periodo di campo. È possibile modificare il valore del periodo di campo da un metodo di sostituzione? Come ad esempio:

public class ConcreteSome extends AbstractAny{
  @Override
  public void doSomething() {
    try {
      Field p = super.getClass().getDeclaredField("period");
      p.setAccessible(true);
      p.setLong(this, 10L);
    } catch (SecurityException e) {
        throw new RuntimeException(e);
    } catch (NoSuchFieldException e) {
        throw new RuntimeException(e);
    } catch (IllegalArgumentException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
  }
}

Quando provo a eseguire questo codice super.getClass (). getDeclaredField (" period ") genera java.lang.NoSuchFieldException: period

È stato utile?

Soluzione

È necessario getClass (). getSuperclass () per ottenere la superclasse, non super.getClass () .

Tuttavia, davvero non consiglio di farlo. Stai praticamente distruggendo l'incapsulamento della classe astratta. Se la classe astratta non fornisce abbastanza flessibilità per i suoi discendenti, dovrebbe essere riparata - aggirarla è solo chiedere problemi. Cosa succede se qualche altro membro della classe astratta deve essere cambiato ogni volta che lo fa? Il punto fondamentale di avere uno stato privato è che la classe sia in grado di proteggere i propri dati. Usare la riflessione in questo modo è un brutto trucco che dovrebbe essere un ultimo ricorso assoluto.

Altri suggerimenti

Sono con Jon Skeet. A lungo termine è più semplice modificare il codice sorgente della superclasse per rendere questo campo protetto o delegare la mutazione a un metodo sostituibile. L'uso di reflection per modificare il valore ora funziona correttamente, ma non si adatta molto bene alla manutenzione nel tempo.

ConcreteSome non estende la classe astratta AbstractAny.
Prova questo

public class ConcreteSome {
    @Override
    public void doSomething() {
        Class<?> clazz = getClass().getSuperclass();
        System.out.println(clazz);
        Field p = clazz.getDeclaredField("period");
        ...

dovrebbe restituire java.lang.Object

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top