访问Java中的私有成员

时间:2013-08-09 14:18:44

标签: java

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

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

enter image description here

10 个答案:

答案 0 :(得分:6)

可以使用反射,请参阅此链接以获得有关如何的详细说明。 How do I read a private field in Java?

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

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

答案 1 :(得分:5)

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

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

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

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

答案 2 :(得分:3)

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

  1. java.lang.reflect.*开始,导航至反映您感兴趣成员的obj.getClass()个实例;
  2. 致电member.setAccessible(true);
  3. 反思地访问该成员。
  4. 通常的警告是,这不应该是整体设计的一部分,但如果你有充分的理由需要它,那就是它。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:1)

你不能直接做到。 Java语言规范对此非常清楚(参见章节Controlling Access to Members of a Class)。 “私有”成员只能从定义的类访问,既不能从同一个包中的类也不能从子类中访问(而是从嵌套类中查看,请参阅Java语言规范,章节Determining Accessibility)。

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

示例(来自Java tutorial):

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经理可能仍会阻止您阅读该字段)。如果你也想写字​​段,事情会变得更复杂。这甚至可能会让你读到一个错误的值(在一个非常理论的角落里,但仍然如此)。有关详细信息,请参见下文。

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

  field.setAccessible(true);

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

此外,Java安全管理器可能会阻止您这样做。

当编译器已经内联文件时,此技术将无效。然后编译器在编译期间更改了程序:它使用值将每个引用交换到字段。可以在Java语言规范(章节Subsequent Modification of Final Field)中找到Datails:

  

在某些情况下,例如反序列化,系统需要更改   施工后物体的最终区域。最后的字段可以   通过反思和其他依赖于实现的手段改变。该   只有具有合理语义的模式才是其中的一种   构造对象,然后构造对象的最终字段   更新。该对象不应该对其他线程可见,也不应该   是否应该读取最终字段,直到对最终字段的所有更新   对象是完整的。最终场的冻结都发生在   设置最终字段的构造函数的结尾,以及   每次通过反射或最终场的修改后立即   其他特殊机制。

     

即使这样,也有许多并发症。如果是最终字段   在字段声明中初始化为编译时常量,   由于使用了最终字段,因此可能无法观察到对最终字段的更改   在编译时用编译时替换final字段   恒定。

     

另一个问题是规范允许攻击性   最终字段的优化。在一个帖子中,允许   使用final的修改重新排序最终字段的读取   不在构造函数中发生的字段。

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

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

答案 5 :(得分: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.

答案 6 :(得分:0)

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

答案 7 :(得分:0)

使用AspectJ(面向方面​​编程的Java版本)http://www.eclipse.org/aspectj/

可以扩展.jar中的类甚至没有源的类

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

然而,这不是Java语言和requires some learning,例如什么是建议。

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

答案 8 :(得分:-1)

private

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

答案 9 :(得分:-3)

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