简体   繁体   English

访问Java中的私有成员

[英]Access private member in Java

I am attempting to access a private member from another class in Java. 我试图从Java中的另一个类访问私有成员。 Is this a possible task? 这可能是一项任务吗? Currently there is no getter method for this member. 目前该成员没有getter方法。

Below is an image of what I would like to obtain; 下面是我想要获得的图像;

在此输入图像描述

It is possible using reflection, see this link for a good explanation of how. 可以使用反射,请参阅此链接以获得有关如何的良好解释。 How do I read a private field in Java? 如何在Java中读取私有字段?

That said, you really really need to have an extremely good reason for doing so, because if you don't control the code chances are that sometime down the road the owner of that code makes a change and everything breaks at runtime. 也就是说,你真的需要有一个非常好的理由这样做,因为如果你不控制代码的话,那么在不久的将来,代码的所有者会做出改变而且一切都会在运行时中断。 And if you own the code there is no reason to do it in the first place. 如果您拥有代码,那么首先没有理由这样做。

If you control the code or have access to the owner, do the right thing and implement proper access methods to get the data you need. 如果您控制代码或有权访问所有者,请执行正确的操作并实施适当的访问方法以获取所需的数据。

You can't, unless you use reflection (more about that below). 你不能,除非你使用反射(更多关于下面的内容)。

If the member is declared private , then other classes aren't allowed to read it. 如果该成员被声明为private ,则不允许其他类读取它。 That's what private scope is about. 这就是私人范围的意义所在。

If you can modify the class that owns the ArrayList, you can add a getter. 如果您可以修改拥有ArrayList的类,则可以添加getter。 It is better not to get the ArrayList in it's entirety (it's a reference and you might inadvertently change it). 最好不要完整地获取ArrayList(它是一个引用,你可能会无意中更改它)。 Add a getter that gets one element, instead. 添加一个获取一个元素的getter。

There is also the option to use reflection, but as is mentioned several times on this page, this is strongly discouraged. 还有使用反射的选项,但正如本页上多次提到的那样,强烈建议不要这样做。 Reflection is a technology that allows code to inspect other code in the same system. 反射是一种允许代码检查同一系统中的其他代码的技术。 Should you really want to use it, the tutorial is here . 如果您真的想要使用它,那么教程就在这里

This is how it is done using reflection: 这是使用反射完成的方式:

  1. navigate to the java.lang.reflect.* instance reflecting your member of interest, starting from obj.getClass() ; 导航到反映您感兴趣的成员的java.lang.reflect.*实例,从obj.getClass() ;
  2. call member.setAccessible(true) ; call member.setAccessible(true) ;
  3. access the member reflectively. 反过来访问该成员。

The usual warning is that this must not be a part of your overall design, but if there is a good reason why you need it, there it is. 通常的警告是,这不应该是整体设计的一部分,但如果有充分理由为什么需要它,那就是它。

If one member is private, it's for a good reason: data encapsulation . 如果一个成员是私有的,这是有充分理由的: 数据封装 This is basic object-oriented philosophy: that member is not meant to be accessed, which means this information is only relevant to this class and should not be relevant to any other class. 这是基本的面向对象的哲学:该成员不应被访问,这意味着该信息仅与该类相关,并且不应与任何其他类相关。

  • If you can modify this class, you can add a getter for this field, but make sure this is really what you want. 如果您可以修改此类,则可以为此字段添加getter,但请确保这正是您想要的。 As I said above, if it's private and has no getters, it's for a reason. 正如我上面所说,如果它是私人的并且没有吸气剂,那是有原因的。

  • If this class is from an external library or framework, then you're most likely using it wrong. 如果这个类来自外部库或框架,那么你很可能错误地使用它。 If you still want to access this private field, you can use reflection to access it (you can do this in several different ways, but I think what you're looking for is Topolnik's answer). 如果您仍想访问此私有字段,可以使用反射来访问它(您可以通过几种不同的方式执行此操作,但我认为您正在寻找的是Topolnik的答案)。

You can't do it direct. 你不能直接做到这一点。 The Java Language Specification is quite clear about this (see chapter Controlling Access to Members of a Class ). Java语言规范非常清楚(参见控制对类成员的访问 )。 A "private" member is only accessible from class it is defined, and neither from classes in the same package nor from subclasses (but from a nested class, see Java Language Specification, chapter Determining Accessibility ). “私有”成员只能从定义的类访问,既不能从同一个包中的类也不能从子类中访问(而是从嵌套类中查看,请参阅Java语言规范, 确定可访问性一章)。

You can circumvent this using reflection. 你可以用反射来规避这个。 For this you have to get the class, then find the description of the filed. 为此你必须得到课程,然后找到提交的描述。 With the description of the filed, you can then set the value for this field. 通过对字段的描述,您可以设置此字段的值。

Example (from the Java tutorial ): 示例(来自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);

If you only want to read, you are done (the Java securoty manager might still prevent you from reading the field). 如果您只想阅读,那么您就完成了(Java securoty经理可能仍会阻止您阅读该字段)。 If you also want to write the field, things become more complicated. 如果你也想写字​​段,事情会变得更复杂。 And this might even bring you to read a wrong value (in a very theoretical corner case, but still). 这甚至可能会让你读到一个错误的值(在一个非常理论的角落里,但仍然如此)。 See below for more details. 请参阅下面的更多细节。

This will not work under all conditions. 这在所有条件下都不起作用。 For final fields you have to make them accessible, and for private final fields, you have to additionally change the modifier, before you can set the value (an example can be found here ): 对于最终字段,您必须使它们可访问,对于私有最终字段,您必须另外更改修饰符,然后才能设置值(可以在此处找到示例):

  field.setAccessible(true);

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

Additionally the Java security manager might prevent you from doing this. 此外,Java安全管理器可能会阻止您执行此操作。

When the compiler has already inlined the filed, this technique will have no effect. 当编译器已经内联该文件时,该技术将不起作用。 Then the compiler has changed your program during compile time: it exchanged each reference to the filed with the value. 然后编译器在编译期间更改了程序:它使用值将每个引用交换到字段。 Datails can be found in the Java Language Specification (chapter Subsequent Modification of Final Field ): 可以在Java语言规范( 最终字段的后续修改章节)中找到Datails:

In some cases, such as deserialization, the system will need to change the final fields of an object after construction. 在某些情况下,例如反序列化,系统将需要在构造之后更改对象的最终字段。 final fields can be changed via reflection and other implementation dependent means. 最终字段可以通过反射和其他依赖于实现的方式来改变。 The only pattern in which this has reasonable semantics is one in which an object is constructed and then the final fields of the object are updated. 它具有合理语义的唯一模式是构造对象然后更新对象的最终字段的模式。 The object should not be made visible to other threads, nor should the final fields be read, until all updates to the final fields of the object are complete. 对象不应该对其他线程可见,也不应该读取最终字段,直到完成对象的最终字段的所有更新。 Freezes of a final field occur both at the end of the constructor in which the final field is set, and immediately after each modification of a final field via reflection or other special mechanism. 最终字段的冻结既发生在设置了最终字段的构造函数的末尾,也发生在通过反射或其他特殊机制对每个最终字段进行修改之后。

Even then, there are a number of complications. 即使这样,也有许多并发症。 If a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the compile-time constant. 如果在字段声明中将final字段初始化为编译时常量,则可能无法观察到对final字段的更改,因为在编译时将该final字段的使用替换为编译时常量。

Another problem is that the specification allows aggressive optimization of final fields. 另一个问题是规范允许对最终字段进行积极优化。 Within a thread, it is permissible to reorder reads of a final field with those modifications of a final field that do not take place in the constructor. 在一个线程中,允许使用构造函数中不发生的最终字段的那些修改来重新排序最终字段的读取。

Because of this, you might read a wrong value with the code above. 因此,您可能会使用上面的代码读取错误的值。 If someone changed a field using reflection, and you read the value back later, you will not read the value the actual code is using. 如果有人使用反射更改了字段,并且您稍后再读取该值,则不会读取实际代码使用的值。 So you will read a wrong value in this case: 因此,在这种情况下,您将读取错误的值:

  1. It is a private final static field 这是一个private final static字段
  2. The compiler used the optimisation technique described above 编译器使用上述优化技术
  3. Someone changed the value with the reflection method described above. 有人用上述反射方法改变了这个值。

You can do it with Reflection but do it on your own risk as it's not recommended. 您可以使用Reflection执行此操作但由于不建议您自行承担风险。

Below is an Example for your given situation: 以下是您给定情况的示例:

        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.

Is it for testing ? 是测试吗? If yes I think you can use reflection, otherwise it is not recommanded. 如果是,我认为你可以使用反射,否则不推荐。

You can extend classes that are with in .jar and even without sources using AspectJ (Java version of Aspect Oriented Programming) http://www.eclipse.org/aspectj/ 您可以使用AspectJ (面向方面​​编程的Java版本)扩展.jar中甚至没有源的类http://www.eclipse.org/aspectj/

For your example you can modify standard ArrayList behavior, eg copy information aside when addition is called. 对于您的示例,您可以修改标准ArrayList行为,例如,在调用add时不要复制信息。

This is however not Java language and requires some learning , eg what is advice. 然而,这不是Java语言, 需要一些学习 ,例如什么是建议。

Note: AspectJ is heavily used internally in Spring framework. 注意:AspectJ在Spring框架内部大量使用。

private

This keyword in itself says that the variable or a method or a function associated with it, is no longer available to the class's object. 此关键字本身表示变量或与其关联的方法或函数不再可用于类的对象。 To access it, you need to make a public method in which you will use it. 要访问它,您需要创建一个公共方法来使用它。

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

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

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