繁体   English   中英

访问Java中的私有成员

[英]Access private member in Java

我试图从Java中的另一个类访问私有成员。 这可能是一项任务吗? 目前该成员没有getter方法。

下面是我想要获得的图像;

在此输入图像描述

可以使用反射,请参阅此链接以获得有关如何的良好解释。 如何在Java中读取私有字段?

也就是说,你真的需要有一个非常好的理由这样做,因为如果你不控制代码的话,那么在不久的将来,代码的所有者会做出改变而且一切都会在运行时中断。 如果您拥有代码,那么首先没有理由这样做。

如果您控制代码或有权访问所有者,请执行正确的操作并实施适当的访问方法以获取所需的数据。

你不能,除非你使用反射(更多关于下面的内容)。

如果该成员被声明为private ,则不允许其他类读取它。 这就是私人范围的意义所在。

如果您可以修改拥有ArrayList的类,则可以添加getter。 最好不要完整地获取ArrayList(它是一个引用,你可能会无意中更改它)。 添加一个获取一个元素的getter。

还有使用反射的选项,但正如本页上多次提到的那样,强烈建议不要这样做。 反射是一种允许代码检查同一系统中的其他代码的技术。 如果您真的想要使用它,那么教程就在这里

这是使用反射完成的方式:

  1. 导航到反映您感兴趣的成员的java.lang.reflect.*实例,从obj.getClass() ;
  2. call member.setAccessible(true) ;
  3. 反过来访问该成员。

通常的警告是,这不应该是整体设计的一部分,但如果有充分理由为什么需要它,那就是它。

如果一个成员是私有的,这是有充分理由的: 数据封装 这是基本的面向对象的哲学:该成员不应被访问,这意味着该信息仅与该类相关,并且不应与任何其他类相关。

  • 如果您可以修改此类,则可以为此字段添加getter,但请确保这正是您想要的。 正如我上面所说,如果它是私人的并且没有吸气剂,那是有原因的。

  • 如果这个类来自外部库或框架,那么你很可能错误地使用它。 如果您仍想访问此私有字段,可以使用反射来访问它(您可以通过几种不同的方式执行此操作,但我认为您正在寻找的是Topolnik的答案)。

你不能直接做到这一点。 Java语言规范非常清楚(参见控制对类成员的访问 )。 “私有”成员只能从定义的类访问,既不能从同一个包中的类也不能从子类中访问(而是从嵌套类中查看,请参阅Java语言规范, 确定可访问性一章)。

你可以用反射来规避这个。 为此你必须得到课程,然后找到提交的描述。 通过对字段的描述,您可以设置此字段的值。

示例(来自Java教程 ):

Class<?> c = book.getClass();
Field chap = c.getDeclaredField("chapters");
// Reading the value
Object value = chap.getLong(book);
// Writing the value
// Here you might have to insert the code below
chap.setLong(book, 12);

如果您只想阅读,那么您就完成了(Java securoty经理可能仍会阻止您阅读该字段)。 如果你也想写字​​段,事情会变得更复杂。 这甚至可能会让你读到一个错误的值(在一个非常理论的角落里,但仍然如此)。 请参阅下面的更多细节。

这在所有条件下都不起作用。 对于最终字段,您必须使它们可访问,对于私有最终字段,您必须另外更改修饰符,然后才能设置值(可以在此处找到示例):

  field.setAccessible(true);

  Field modifiersField = Field.class.getDeclaredField("modifiers");
  modifiersField.setAccessible(true);
  modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

此外,Java安全管理器可能会阻止您执行此操作。

当编译器已经内联该文件时,该技术将不起作用。 然后编译器在编译期间更改了程序:它使用值将每个引用交换到字段。 可以在Java语言规范( 最终字段的后续修改章节)中找到Datails:

在某些情况下,例如反序列化,系统将需要在构造之后更改对象的最终字段。 最终字段可以通过反射和其他依赖于实现的方式来改变。 它具有合理语义的唯一模式是构造对象然后更新对象的最终字段的模式。 对象不应该对其他线程可见,也不应该读取最终字段,直到完成对象的最终字段的所有更新。 最终字段的冻结既发生在设置了最终字段的构造函数的末尾,也发生在通过反射或其他特殊机制对每个最终字段进行修改之后。

即使这样,也有许多并发症。 如果在字段声明中将final字段初始化为编译时常量,则可能无法观察到对final字段的更改,因为在编译时将该final字段的使用替换为编译时常量。

另一个问题是规范允许对最终字段进行积极优化。 在一个线程中,允许使用构造函数中不发生的最终字段的那些修改来重新排序最终字段的读取。

因此,您可能会使用上面的代码读取错误的值。 如果有人使用反射更改了字段,并且您稍后再读取该值,则不会读取实际代码使用的值。 因此,在这种情况下,您将读取错误的值:

  1. 这是一个private final static字段
  2. 编译器使用上述优化技术
  3. 有人用上述反射方法改变了这个值。

您可以使用Reflection执行此操作但由于不建议您自行承担风险。

以下是您给定情况的示例:

        YOURCLASS f = new YOURCLASS(); //Make an object of your class
        Field a = f.getClass().getDeclaredField("privateListObject");    //get private declared object from class
        a.setAccessible(true);  //Make it accessible so you can access it
        ArrayList al = (ArrayList) a.get(f);    // At last it's yours.

是测试吗? 如果是,我认为你可以使用反射,否则不推荐。

您可以使用AspectJ (面向方面​​编程的Java版本)扩展.jar中甚至没有源的类http://www.eclipse.org/aspectj/

对于您的示例,您可以修改标准ArrayList行为,例如,在调用add时不要复制信息。

然而,这不是Java语言, 需要一些学习 ,例如什么是建议。

注意:AspectJ在Spring框架内部大量使用。

private

此关键字本身表示变量或与其关联的方法或函数不再可用于类的对象。 要访问它,您需要创建一个公共方法来使用它。

您只能从同一个类的方法访问私有变量。因此,您必须创建一个getter方法来返回该数组

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM