博客
关于我
Java反射获取private属性和方法(子类,父类,祖先....)
阅读量:792 次
发布时间:2023-01-28

本文共 2393 字,大约阅读时间需要 7 分钟。

Java反射获取私有属性和方法(子类、父类、祖先等)

反射在Java编程中扮演着重要角色,特别是在处理私有属性和方法时,它提供了强大的灵活性。通过反射,我们可以访问一些在通常情况下无法直接访问的元素。然而,反射的使用需要谨慎,其潜在危险性可能导致代码安全性问题。

先来看一个例子:String可变还是不可变?

通常情况下,String类被认为是不可变的。这是因为字符串实际上使用一个final char数组来存储字符数据,带有private访问修饰符。这种结构使得字符串的可变性被严格限制。但是,让我们深入探讨这个问题。

首先,在运行时,字符串"abc"被存储为一个指向char数组的引用。该数组存储在String对象的"值"属性中。我们可以通过反射机制获取到这个私有属性,并绕过语言层面的常见约束。

反射用法

灭一灭百。反射提供了强大的操作类的能力。通过反射,我们可以访问运行时类信息,修改属性值,执行静态方法,创建对象等。这种能力使得程序具有了更大的灵活性。

下面是一段代码示例:

static void getClassFieldAndMethod(Class cur_class) {String class_name = cur_class.getName();Field[] obj_fields = cur_class.getDeclaredFields();for (Field field : obj_fields) {if (field.isAccessible()) {System.out.println(class_name + ": " + field.getName());}try {field.setAccessible(true);System.out.println(class_name + ": " + field.getName());} catch (SecurityException e) {e.printStackTrace();}}Method[] methods = cur_class.getDeclaredMethods();for (Method method : methods) {try {method.setAccessible(true);System.out.println(class_name + ": " + method.getName());} catch (SecurityException e) {e.printStackTrace();}}if (cur_class.getSuperclass() != null) {getClassFieldAndMethod(cur_class.getSuperclass());}}

代码解释:

  • 取得当前类的名称。
  • 遍历该类的所有非传递字段,并输出每个字段的名称。
  • 对于每个方法,调用setAccessible方法,使其变得可访问。
  • 如果类有父类直到Object类,递归处理父类。
  • 类似的逻辑也可以用于获取对象属性和方法。

    伪原

    这段代码输入一个Class对象,递归输出该类的父类、祖父类直到Object类的所有方法和域。你可以使用它来查看类的具体实现,或者绕过常见的程序设计约束。

    注:请谨慎使用反射操作,因为它可能导致一些不规范的行为,例如绕过Java安全机制,形成漏洞或隐藏的副作用。

    postscript

    关于intern()方法的实现细节,它是通过Stringthis cansThrownBy Chester名字符池来工作的。这意味着在调用intern()时,字符串会被存储在类String管理的常量池中。

    官方文档中,intern()方法的注释已详细说明了其工作原理:

  • 检查常量池中是否存在一个与当前字符串相等的对象。
  • 如果存在,返回该对象引用。
  • 如果不存在,创建一个新的字符串实例,将其存储在常量池中,并返回新的对象。
  • 通过上述分析,我们可以看出语句执行过程中发生了什么事情。如果你希望为这个Example进行更深入的分析,你可能需要参考JVM的一些内部实现细节。

    好了,回到我们的变量修改示例:

    a = "abc"valueFieldString.setAccessible(true)char[] value = (char[]) valueFieldString.get(a)value[2] = '@'

    在这种情况下,String对象的"值"属性被修改为包含字符'@'。然而,尽管字符的值被修改了,字符串对象本身仍然保持不变,仍然指向常量池中的那个对象。

    那么,问题来了:

    b = "abc""abc".equals(b) ?

    这里的关键点在于String对象的值属性与字符串整体的可变性。通过我们的修改,可以看出String对象的字符数组发生了变化,而字符串整体的行为却没有和直接修改常量池中的字符串一样。

    简单来说,即使你修改了字符串的内部存储内容,字符串本身仍然与常量池中的那个对象绑定。因此,修改后的字符串和原始的字符串在引用上是相同的,但在内容上是不同的。

    这样,当你创建一个新的字符串实例的时候,虽然在常量池中会新增一个新的字符串,但原有的字符串对象不会受到影响。

    现在,再回到反射的反向介绍。通过反射机制,你可以修改实例中的域值,甚至创建新的动态方法。这使得反射非常灵活,也非常危险。在编写代码时,确保反射操作是安全和可靠的至关重要。

    总之,反射提供了对Java对象模型的高度灵活性,使开发者能够实现复杂的功能。然而,你需要谨慎对待反射,因为它可能导致意想不到的后果。

    如果你已经理解了上述内容,请可以跳到下一个Section,探讨反射的实际用法。需要注意的是,反射是一项强大的工具,遇到不良使用可能导致严重后果。

    转载地址:http://siryk.baihongyu.com/

    你可能感兴趣的文章
    java.lang.NoSuchMethodError: org.jaxen.dom4j.DocumentNavigator.getInstance()【可能的解决办法】
    查看>>
    java农业文化旅游管理平台(ssm)
    查看>>
    java农副产品网上预订系统(ssm)
    查看>>
    java农副产品购物app的设计与开发(ssm)
    查看>>
    java农家乐客户管理系统(ssm)
    查看>>
    Java分布式
    查看>>
    JAVA分布式系统
    查看>>
    java分布式链路追踪;jvm应用监控-skywalking
    查看>>
    java分库分表
    查看>>
    Java创建elasticsearch的model时,如何配置使用ik分词器?
    查看>>
    Java创建对象的初始化顺序
    查看>>
    java加密解密
    查看>>
    Java动态代理的两种实现方法
    查看>>
    java勤工助学管理系统
    查看>>
    Java包装类、拆箱和装箱详解
    查看>>
    Java匹配文件流特定数据块方法
    查看>>
    Java原型模式(Prototype模式)
    查看>>
    Java参数传递到底是按 值传递 还是 引用传递 ?
    查看>>
    JAVA反射
    查看>>
    Java反射
    查看>>