2

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

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

在此处输入图像描述

4

10 回答 10

6

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

也就是说,你真的需要有一个非常好的理由这样做,因为如果你不控制代码,那么代码的所有者可能会在某个时候进行更改,并且在运行时一切都会中断。如果你拥有代码,那么一开始就没有理由这样做。

如果您控制代码或有权访问所有者,请做正确的事情并实施适当的访问方法来获取您需要的数据。

于 2013-08-09T14:33:00.583 回答
5

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

如果声明了成员private,则不允许其他类读取它。这就是私有作用域的意义所在。

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

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

于 2013-08-09T14:22:48.570 回答
3

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

  1. 导航到java.lang.reflect.*反映您感兴趣的成员的实例,从obj.getClass();开始
  2. 打电话member.setAccessible(true)
  3. 反射性地访问成员。

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

于 2013-08-09T14:27:40.933 回答
2

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

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

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

于 2013-08-09T14:28:09.827 回答
1

你不能直接做。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 安全管理器可能仍会阻止您阅读该字段)。如果你也想写字​​段,事情就变得更复杂了。这甚至可能会让您读取错误的值(在非常理论上的极端情况下,但仍然如此)。请参阅下面的更多细节。

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

  field.setAccessible(true);

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

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

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

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

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

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

因此,您可能会使用上面的代码读取错误的值。如果有人使用反射更改了字段,而您稍后读回该值,您将不会读取实际代码正在使用的值。所以在这种情况下你会读到一个错误的值:

  1. 这是一个private final static领域
  2. 编译器使用了上述优化技术
  3. 有人用上面描述的反射方法改变了值。
于 2013-08-09T14:42:53.987 回答
1

你可以这样做,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.
于 2013-08-09T14:47:16.833 回答
0

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

于 2013-08-09T14:27:15.370 回答
0

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

对于您的示例,您可以修改标准 ArrayList 行为,例如在调用添加时将信息复制到一边。

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

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

于 2013-08-09T14:54:23.050 回答
-1
private

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

于 2013-08-09T14:48:07.527 回答
-3

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

于 2013-08-09T14:22:05.047 回答