2009-08-03 12 views
2

Il y a une classe abstraite:Comment faire pour muter un champ privé de la classe abstraite en Java?

public abstract class AbstractAny { 
    private long period; 

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

Je ne veux pas changer la source de la classe abstraite, mais besoin d'ajouter une certaine flexibilité sur la façon dont la période de terrain est en cours. Est-il possible de changer la valeur de la période de champ d'une méthode redéfinie? Comme par exemple:

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); 
    } 
    } 
} 

Quand j'essaie de lancer ce code super.getClass().getDeclaredField("period") lancers francs java.lang.NoSuchFieldException: period

Répondre

20

Vous devez getClass().getSuperclass() pour obtenir le superclasse, non super.getClass().

Cependant, je vraiment ne recommande pas cela. Vous êtes en train de détruire l'encapsulation de la classe abstraite. Si la classe abstraite n'offre pas assez de flexibilité à ses descendants, elle devrait être corrigée - il ne sert qu'à demander des problèmes. Que se passe-t-il si un autre membre de la classe abstraite doit être changé chaque fois que celui-ci le fait? Le point d'avoir un état privé est que la classe est capable de garder ses propres données. En utilisant la réflexion comme ceci est un hack vraiment moche qui devrait être un dernier recours .

0

ConcreteSome n'étend pas la classe abstraite AbstractAny.
Essayez cette

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

devrait retourner java.lang.Object

+0

Correction, merci –

2

Je suis avec Jon Skeet. Il est plus facile à long terme de changer le code source de la superclasse pour protéger ce champ ou pour déléguer la mutation à une méthode redéfinissable. L'utilisation de la réflexion pour changer la valeur fonctionne bien maintenant, mais elle n'évolue pas très bien en ce qui concerne la maintenance au fil du temps.