最近我遇到了 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));
}
}
我得到以下输出。
Variable is name and value is John
Variable is name and value is Sam
我们说Java是一种面向对象的语言,它的主要特点是数据封装、继承、多态性……等等。反射API不是改变了数据封装的目的吗?为什么我们必须使用Reflection API?我在一些网站上读到它可以用于测试目的,但根据我的说法,模块已经过测试,并且可以使用 JUnit 测试用例轻松完成。那么谁能解释一下为什么我们会有这样的黑客行为呢?
反射 API 不是改变了数据封装的目的吗?
是和不是。
- 是的,反射 API 的一些用途can破坏数据封装。
- 不,并非反射 API 的所有用途do破坏数据封装。事实上,明智的程序员只会在有充分理由时才通过反射 API 来打破封装。
- 不,反射 API 不会改变purpose的数据封装。这purpose数据封装的原理保持不变……即使有人故意破坏它。
为什么我们必须使用Reflection API?
有many反射的用途DO NOT破坏封装;例如使用反射来找出类有哪些超类型、有哪些注释、有哪些成员、调用可访问的方法和构造函数、读取和更新可访问的字段等。
在某些情况下,使用破坏封装的反射类型是可以接受的(在不同程度上):
您可能需要查看封装类型的内部(例如访问/修改私有字段)作为实现某些单元测试的最简单方法(或唯一方法)。
某些形式的依赖注入(又名 IoC)、序列化和持久化需要访问和/或更新私有字段。
偶尔,您需要打破封装来解决某些类中无法修复的错误。
我在一些网站上读到它可以用于测试目的,但根据我的说法,模块已经过测试,并且可以使用 JUnit 测试用例轻松完成。那么谁能解释一下为什么我们会有这样的黑客行为呢?
这取决于您的班级设计。设计为可测试的类要么可以在不需要访问“私有”状态的情况下进行测试,要么将公开该状态(例如protected
getter)以允许测试。如果类不这样做,那么 JUnit 测试可能需要使用反射来查看抽象内部。
这是不可取的(IMO),但是如果您正在为某人编写的类编写单元测试,并且您无法“调整”API 来提高可测试性,那么您可能必须在使用反射或根本不测试之间做出选择。
最重要的是,数据封装是我们努力实现的理想(在 Java 中),但在某些情况下,实际正确的做法是破坏它或忽略它。
请注意,并非所有 OO 语言都像 Java 一样支持强数据封装。例如,Python 和 Javascript 无疑都是面向对象的语言,但两者都使一个类可以轻松访问和修改另一个类的对象状态……甚至更改其他类的行为。强数据抽象并不是每个人对面向对象含义的看法的核心。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)