当前位置: 首页 > 面试题库 >

反射API不会破坏数据封装的目的吗?

龙昊焱
2023-03-14
问题内容

最近我遇到了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不会改变数据封装的目的吗?为什么我们必须使用反射API?我在一些站点上读到它可以用于测试目的,但是据我说,模块已经过测试,可以使用JUnit测试用例轻松完成。那么谁能解释为什么我们会有这样的hack?


问题答案:

反射API不会改变数据封装的目的吗?

是的,没有。

  • 是的,反射API的某些用法 可能会 破坏数据封装。
  • 不,并非所有对反射API的使用 都会 破坏数据封装。确实,明智的程序员只有在有充分理由时才通过反射API破坏封装。
  • 不可以,反射API不会改变数据封装的 目的 。数据封装的 目的 保持不变……即使有人故意破坏它。

为什么我们必须使用反射API?

反射有 很多 用途, 不会
破坏封装。例如,使用反射来找出类具有的超类型,其具有的注释,其具有的成员,调用可访问的方法和构造函数,读取和更新可访问的字段等。

在某些情况下(在不同程度上)可以使用打破封装的反射形式:

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

  • 某种形式的依赖注入(aka IoC),序列化和持久性要求访问和/或更新私有字段。

  • 有时,您需要破坏封装以解决某些无法修复的错误。

我在一些站点上读到它可以用于测试目的,但是据我说,模块已经过测试,可以使用JUnit测试用例轻松完成。那么谁能解释为什么我们会有这样的hack?

这取决于您的班级设计。设计为可测试的类将可以在无需访问“私有”状态的情况下进行测试,或者将暴露该状态(例如,protected吸气剂)以进行测试。如果该类不这样做,那么JUnit测试可能需要使用反射来查看抽象内部。

这是不理想的(IMO),但是如果您正在为某人编写的类编写单元测试,并且不能“调整”
API以提高可测试性,那么您可能必须在使用反射还是完全不测试之间进行选择。 。

最重要的是,数据封装是我们努力实现的理想选择(在Java中),但是在某些情况下,务实正确的做法是破坏它或忽略它。

请注意,并非所有的OO语言都像Java一样支持强大的数据封装。例如,Python和Javascript都是无可争议的OO语言,但是它们都使一个类可以轻松访问和修改另一类对象的状态,甚至改变其他类的行为。强大的数据抽象并不是每个人都了解面向对象的含义的中心。



 类似资料:
  • 问题内容: 无论如何,Java中是否有删除数据(例如,变量值,对象)并确保不能从内存中恢复数据的方法?在Java中分配变量是否会从内存中删除值?有任何想法吗?适用于其他语言的答案也是可以接受的。 问题答案: 由于虚拟内存的奇妙,几乎不可能以完全无法检索的方式从内存中删除某些内容。最好的选择是将值字段清零。然而: 这并不意味着该对象的旧(未清零)副本不会保留在未使用的交换页面上,该页面可能会在重新启

  • 对于Oracle池连接,我使用,但这些连接似乎在数据库中保持活动状态。今天我在连接到Oracle数据库时遇到了一个错误: ORA-12516:TNS:侦听器找不到具有匹配协议栈的可用处理程序 另外,我在dao级别使用jdk7 try-with-resources语法进行连接: 弄不清真正的问题在哪里。我应该使用c3p0而不是OracleDataSource吗?ojdbc7中是否有bug或我的代码中

  • 注意:我在Chrome应用程序中使用来自webview的YouTubeIframe。 这是YouTube的API声明: videoSyndicated参数允许您将搜索限制为只能在youtube.com以外播放的视频。如果为此参数指定值,还必须将type参数的值设置为video。 videoLicense参数过滤搜索结果,以仅包括具有特定许可证的视频。YouTube允许视频上传者选择将知识共享许可或

  • 我试图将Spring Security性添加到我的项目中,但是在将它添加到gradle文件并导入更改时,突然Spring数据JPA依赖项不再起作用了。 这是什么原因造成的?

  • 问题内容: 我听过关于此主题的不同回答,那么销毁PHP会话的肯定方法是什么? 在最简单的情况下,这是否足以真正终止用户与服务器之间的会话? 问题答案: 要销毁会话,您应该采取以下步骤: 删除会话数据 使会话ID无效 为此,我将使用以下代码: 为了确保会话ID无效,您应该只允许脚本启动的会话ID。因此,设置一个标志并检查它是否被设置: 此外,您可以使用此时间戳定期交换会话ID,以缩短其寿命:

  • 所有的 C++ 程序都有以下两个基本要素: 程序语句(代码):这是程序中执行动作的部分,它们被称为函数。 程序数据:数据是程序的信息,会受到程序函数的影响。 封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受到外界的干扰和误用,从而确保了安全。数据封装引申出了另一个重要的 OOP 概念,即数据隐藏。 数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅