【问题标题】:accessing child fields in abstract class throught reflection in java通过java中的反射访问抽象类中的子字段
【发布时间】:2012-06-08 15:49:54
【问题描述】:

我有 2 节课:

public abstract class AbstractTestClass {
    private String abstractString = "abstract";
    public void showFields() throws IllegalAccessException{
        for (Field field : this.getClass().getDeclaredFields()) {
            System.out.println(field.get(this));
        }
    }
}

public class TestClass extends AbstractTestClass {
    private String concreteString = "concreteString";
}

并测试:

public class MainTest {
    public static void main(String[] args) throws IllegalAccessException{
        TestClass test = new TestClass();
        test.showFields();
    }
}

运行此测试会导致下一个异常:

java.lang.IllegalAccessException: Class AbstractTestClass can not access a member of class TestClass with modifiers "private"

当我调试代码时,它包含 TestClass 的实例。

问题:

  1. 为什么会这样?
  2. 如何使这段代码工作,而不是使用 Field.setAccessible() 或更改文件的可见性?

【问题讨论】:

    标签: java inheritance reflection field


    【解决方案1】:

    我相信你犯了我刚开始时犯的同样的错误:抽象类和扩展类是两部分焊接在一起形成一个单一的类,可以访问彼此的所有字段和方法等。

    遗憾的是,这不是真的:继承是在普通父子对象中更紧密的关系,但仍必须遵守访问规则,例如如果方法在抽象类中声明为protected,而扩展类在不同的包中,则无法访问(反之亦然)。

    因为showFields() 方法定义在AbstractTestClass 中,所以它只能访问该类中的字段。 TestClass 中的字段基本上被隔离了。

    我能想到的唯一解决方法是在TestClass 中覆盖showFields(),吞下任何关于无法访问私有字段的异常,然后调用super.showFields() 并再次吞下任何异常。不漂亮。

    public abstract class AbstractTest {
      private String abstractString = "abstract";
      public void showFields() throws IllegalAccessException {
        for (Field field : this.getClass().getSuperclass().getDeclaredFields()) {
          try {
            System.out.println(field.get(this));
          }
          catch (IllegalAccessException e) { 
            // swallow 
          }
        }
      }
    }
    
    public class MyTest extends AbstractTest
    {
      private String concreteString = "concreteString";
      @Override public void showFields() throws IllegalAccessException {
        for (Field field : this.getClass().getDeclaredFields()) {
          try {
            System.out.println(field.get(this));
          }
          catch (IllegalAccessException e) {  
            // swallow
          }
        }
        super.showFields();
      }
    }
    

    我怀疑这就是你的想法......

    【讨论】:

    • 免责声明:多年来,我已经设法避免使用反射,我对此感到更高兴。我什至发现自己越来越少地使用扩展类,而是更喜欢使用接口和委托方法 - 所以请不要认为我的回答是权威的。
    • A 同意应该避免反射,但尝试使用自己编写的注释进行试验。所以我必须使用它们。感谢您的回答。我解决了这个问题,将字段的可见性更改为包。这个包只包含抽象类和他的孩子,所以我认为这不会是糟糕的风格。
    • 是的,一个好的包结构和对访问级别的周到使用总是比诉诸hackery更好的主意。
    【解决方案2】:

    如何使这段代码工作,而不是使用 Field.setAccessible() 或改变文件的可见性?

    你不能,你必须使该字段可访问才能使用它

    【讨论】:

    • 你能解释一下为什么吗?我是这么想的:当我扩展抽象类时,他所有的非抽象方法都变成了具体类的方法,当我调用它们时,它们将从具体类中调用。而调试中的 this 包含具体的类让我感到尴尬。
    猜你喜欢
    • 2011-04-03
    • 1970-01-01
    • 2015-07-08
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 2010-12-06
    相关资源
    最近更新 更多