Como transformar um campo particular da classe abstrata em Java?
-
10-07-2019 - |
Pergunta
Não há uma classe abstrata:
public abstract class AbstractAny {
private long period;
public void doSomething() {
// blah blah blah
period = someHardcodedValue;
// blah blah blah
}
}
Eu não quero mudar a fonte da classe abstrata, mas necessidade de adicionar alguma flexibilidade sobre como o período de campo está sendo definido. É possível alterar o valor do período de campo de um método anulado? Como por exemplo:
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 tento executar este super.getClass().getDeclaredField("period")
código lança java.lang.NoSuchFieldException: period
Solução
Você precisa getClass().getSuperclass()
para obter a superclasse, não super.getClass()
.
No entanto, eu realmente não recomendo fazer isso. Você está destruindo basicamente o encapsulamento da classe abstrata. Se a classe abstrata não está fornecendo flexibilidade suficiente para os seus descendentes, deve ser fixado - indo em torno dele é apenas a pedir sarilhos. E se algum outro membro das necessidades classe abstrata para ser alterado sempre que isso se faz? Toda a ponto de ter estado privado é para que a classe é capaz de proteger seus próprios dados. Usando reflexão como este é um hack realmente feio que deve ser um absoluto última resort.
Outras dicas
Eu estou com Jon Skeet. É mais fácil a longo prazo para mudar o código fonte do superclasse que quer fazer neste campo protegido ou delegar mutação para um método substituível. Usando reflexão para alterar o valor funciona ok agora, mas não escala muito bem, tanto quanto a manutenção ao longo do tempo vai.
ConcreteSome não está estendendo a classe abstrata AbstractAny.
Tente este
public class ConcreteSome {
@Override
public void doSomething() {
Class<?> clazz = getClass().getSuperclass();
System.out.println(clazz);
Field p = clazz.getDeclaredField("period");
...
deve retornar java.lang.Object