Dosen't Reflection API打破了数据封装的目的吗?

Ani*_*kur 8 java reflection encapsulation private

最近我遇到了Reflection API,令我惊讶的是我们可以访问甚至更改私有变量.我尝试了以下代码

import java.lang.reflect.Field;

public class SomeClass{
    private String name = "John";
}

public class Test{
    public static void main(String args[]) throws Exception {
        SomeClass myClass = new SomeClass();

        Field fs = myClass.getClass().getDeclaredField("name");
        fs.setAccessible(true);

        System.out.println("Variable is " + fs.getName() + " and value is "
                + fs.get(myClass));

        fs.set(myClass, "Sam");
        System.out.println("Variable is " + fs.getName() + " and value is "
                + fs.get(myClass));
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到了以下输出.

Variable is name and value is John
Variable is name and value is Sam
Run Code Online (Sandbox Code Playgroud)

我们说Java是一种面向对象的语言,它的主要特性是数据封装,继承,多态......等不是反射API改变了数据封装的目的吗?为什么我们必须使用Reflection API?我在一些网站上读到它可以用于测试目的,但据我说,模块已经过测试,可以使用JUnit测试用例轻松完成.所以任何人都可以解释为什么我们有这样的黑客攻击?

Ste*_*n C 11

反射API是不是改变了数据封装的目的?

是的,不是.

  • 是的,反射API的某些用法可能会破坏数据封装.
  • 不,并非所有反射API的使用都会破坏数据封装.实际上,一个明智的程序员只有在有充分理由这样做时才会通过反射API打破封装.
  • 不,反射API不会改变数据封装的目的.数据封装的目的保持不变......即使有人故意破坏它.

为什么我们必须使用Reflection API?

许多反映出的使用不要破坏封装; 例如,使用反射来找出类具有的超类型,它具有哪些注释,它具有哪些成员,调用可访问的方法和构造函数,读取和更新可访问的字段等等.

并且有些情况可以接受(在不同程度上)使用封装破坏各种反射:

  • 您可能需要查看封装类型(例如,访问/修改私有字段)作为实现某些单元测试的最简单方法(或唯一方式).

  • 某些形式的依赖注入(也称为IoC),序列化和持久性需要访问和/或更新私有字段.

  • 偶尔,您需要打破封装以解决某些类中无法修复的错误.

我在一些网站上读到它可以用于测试目的,但据我说,模块已经过测试,可以使用JUnit测试用例轻松完成.所以任何人都可以解释为什么我们有这样的黑客攻击?

这取决于你班级的设计.设计为可测试的类将是可测试的而无需访问"私有"状态,或者将暴露该状态(例如,protectedgetter)以允许测试.如果类没有这样做,那么JUnit测试可能需要使用反射来查看抽象内部.

这是不可取的(IMO),但如果您正在为某人编写的类编写单元测试,并且您无法"调整"API以提高可测试性,那么您可能必须在使用反射或根本不进行测试之间进行选择.


最重要的是数据封装是我们努力实现的理想(在Java中),但有些情况下,实际上正确的做法是打破它或忽略它.

请注意,并非所有OO语言都支持像Java那样强大的数据封装.例如,Python和Javascript都是无可争议的OO语言,但它们都使一个类可以轻松访问和修改另一个类的对象状态......甚至可以更改其他类的行为.强大的数据抽象并不是每个人对面向对象意味着什么的看法的核心.