Java反射获取私有(private)对象属性,方法(子类,父类,祖先....)(如何改变string的值)

2023-11-02

Java反射,获取对象私有属性,方法(String是否可变)

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

大家都应该知道,或者听过,String类是不可变的,为什么呢?因为String其实使用一个
private final char [] value;来保存字符的;final,private,明显就不让你改了啊。但是,大家请看:

String a="abc";
// 这段可以先不看
Field valueFieldString=String.class.getDeclaredField("value");
valueFieldString.setAccessible(true);
char[]value=(char[])valueFieldString.get(a);
value[2]='@';
// 从这里开始看
String b="abc";
//a.intern();
        
System.out.println(a);
System.out.println(b);
System.out.println(a==b);
System.out.println("abc"==b);
System.out.println("ab@"==a);
System.out.println(a.equals("ab@"));
System.out.println(a.equals("abc"));
System.out.println("abc".equals("ab@"));

输出(猜猜看,和你想的一不一样呢?):

ab@
ab@
true
true
false//(如果把intern那个注释去掉的话,就是true)
true
true
true

如果,你都答对了,恭喜你,那请直接跳到 反射用法.

否则:请看下面分析

先摘一段官方intern()的注释:

* Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned.
3个点:
*** 1.常量池(JVM中就是方法区)是由 String 这个class来私有的管理的。***
*** 2.调用intern()时,会查看常量池是否存在这个String对象,这是通过equals()方法来判断的。***
*** 3.如果存在,则返回常量池中那个String对象,否则,加入到常量池,并返回当前对象。***

ps : equals()方法,首先是看obj1==obj2,也就是引用地址是否相等,如果等则返回true,然后是逐个字符比较。

ok,有了以上知识。其实到这里你自己也可以分析出来了。

我们来分析一下
首先,String a="abc"; 这句话在内存(常量池)中放入了一个String对象:“abc”(内存地址假设为0x123,由char [] value = [‘a’,‘b’,‘c’]保存),
然后第2~5行,我们先不管语法,只要知道是把“abc”这个字符串的第三个字符’c’替换为’@’,
此时char [] value = [‘a’,‘b’,‘c’] 变为了char [] value = [‘a’,‘b’,’@’],String这个class对象管理的还是“abc”这个对象。
接下来 String b="abc",这句话会从常量池中寻找“abc”,此时会发现常量池中“abc”是存在的,于是,b就指向了“abc”,b其实就是“abc”的位置的一个引用,a也是一个“abc”位置的引用。
那么接下来就是顺理成章了:

        System.out.println(a);//a指向"abc"这个对象,而这个对象,内部存储却是{'a','b','@'}
		System.out.println(b);//同上
        System.out.println(a==b);//都指向0x123
        System.out.println("abc"==b);//都是0x123
        System.out.println("ab@"==a);//"ab@"这个对象在常量池中没有,会先在常量中生成,地址显然不是0x123,所以输出false,但是,当调用了a.intern()后,会调用String的equals()去常量池中新建一个对象"ab@',并返回这个位置。
        System.out.println(a.equals("ab@"));
        System.out.println(a.equals("abc"));
        System.out.println("abc".equals("ab@"));

如果仔细想想,其实还是有疑问,在这里就不展开了,不然偏题了,因为我对底层也不懂,intern是c++实现的,具体看这篇:

http://www.wtoutiao.com/a/1023451.html

反射

反射,RTTI,Class对象,这些就不说了,看一段代码:

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

这段代码输入是一个Class的对象,递归输出这个类的父类,祖父类直到Object类的所有方法和域。

再看一段:

	static void getObjField(Object obj) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
	
		Class cur_class = obj.getClass();
		getClassFieldAndMethod(cur_class);
        Field vfield=cur_class.getDeclaredField("value");
        vfield.setAccessible(true);
        char[]value=(char[])vfield.get(obj);
        System.out.println(Arrays.toString(value));
	}

ok,这段代码输入任意一个对象,调用上面那段代码的方法getClassFieldAndMethod(),这样你就知道这个对象都有些什么域,什么方法了,再通过域的名称,就可以获取当前这个对象的域的值,进而可以修改了!!

是不是很简单,从此以后谁都不能限制你在Java程序里面为所欲为了!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java反射获取私有(private)对象属性,方法(子类,父类,祖先....)(如何改变string的值) 的相关文章

  • Java 中的 <-- 是什么? [复制]

    这个问题在这里已经有答案了 我遇到了下面的片段 它输出到4 3 2 1 我从来没有遇到过 lt 在爪哇 Is lt 使 var1 的值变为 var2 的运算符 public class Test public static void mai
  • 有人用过 ServiceLoader 和 Guice 一起使用吗?

    我一直想通过我们的应用程序 构建系统进行更大规模的尝试 但更高的优先级不断将其推到次要地位 这似乎是加载 Guice 模块的好方法 并且避免了关于 硬编码配置 的常见抱怨 单个配置属性很少会自行更改 但您几乎总是会有一组配置文件 通常用于不
  • 无法使用 datastax java 驱动程序通过 UDT 密钥从 cassandra 检索

    我正在尝试使用用户定义的类型作为分区键将对象存储在 cassandra 中 我正在使用 datastax java 驱动程序进行对象映射 虽然我能够插入到数据库中 但无法检索该对象 如果我更改分区键以使用非 udt 例如文本 我就能够保存和
  • JOOQ 忽略具有默认值的数据库列

    看来JOOQ完全忽略了数据库列的默认值 既不会更新 ActiveRecord 对象 也不会在 INSERT 时跳过此列 相反 它尝试将其设置为 NULL 这在 NOT NULL 列上失败 Example CREATE TABLE bug f
  • 如何使用 Java Apache POI 隐藏 Excel 工作表中以下未使用的行?

    我正在使用数据库中的数据填充模板 Excel 工作表 for Map
  • 为什么 jar 执行的通配符在 docker CMD 中不起作用?

    我有一个Dockerfile与以下CMD启动我的 Spring Boot 应用程序 FROM java 8 jre CMD java jar app file jar 当我尝试从创建的图像启动容器时 我得到 Error Unable to
  • Mockito 和 Hamcrest:如何验证 Collection 参数的调用?

    我遇到了 Mockito 和 Hamcrest 的泛型问题 请假设以下界面 public interface Service void perform Collection
  • 如何使用双重调度来分析图形基元的交集?

    我正在分析图形基元 矩形 直线 圆形等 的交互并计算重叠 相对方向 合并等 这被引用为双重调度的一个主要示例 例如维基百科 http en wikipedia org wiki Double dispatch 自适应碰撞算法通常要求 不同的
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • 如何自定义舍入形式

    我的问题可能看起来很简单 但仍然无法得到有效的东西 我需要自定义 Math round 舍入格式或其他格式以使其工作如下 如果数字是 1 6 他应该四舍五入到 1 如果大于或等于 1 7 他应该四舍五入到 2 0 对于所有其他带有 6 的小
  • IntelliJ Idea:将简单的 Java servlet(无 JSP)部署到 Tomcat 7

    我尝试按照教程进行操作here http wiki jetbrains net intellij Creating a simple Web application and deploying it to Tomcat部署 servlet
  • UseCompressedOops JVM 标志有什么作用以及何时应该使用它?

    HotSpot JVM 标志是什么 XX UseCompressedOops我应该做什么以及什么时候使用它 在 64 位 Java 实例上使用它 与不使用它 时 我会看到什么样的性能和内存使用差异 去年大多数 HotSpot JVM 都默认
  • 使用 Proguard 通过 Dropbox.com 库混淆 Android 应用程序

    我刚刚创建了一个需要 Dropbox com API 库的 Android 应用程序 我现在尝试在 发布 模式下构建应用程序 并希望在代码上运行混淆器以对其进行混淆 但是 每当我尝试运行 Proguard 时 都会收到以下错误 Progua
  • Joshua Bloch 的构建器设计模式有何改进?

    早在 2007 年 我就读过一篇关于 Joshua Blochs 所采用的 构建器模式 的文章 以及如何修改它以改善构造函数和 setter 的过度使用 特别是当对象具有大量属性 其中大部分属性是可选的 时 本文对此设计模式进行了简要总结
  • Tomcat 6 未从 WEB-INF/lib 加载 jar

    我正在尝试找出我的 tomcat 环境中的配置问题 我们的生产服务器正在运行 tomcat 安装并从共享 NFS 挂载读取战争 然而 当我尝试使用独立的盒子 及其配置 进行同样的战争时 我收到下面发布的错误 有趣的是 如果我将 WEB IN
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • 检测到 JVM 正在关闭

    我有一个使用 addShutdownHook 处理 Ctrl C 的 Swing 应用程序 它工作正常 直到我的关闭任务之一调用一个在正常情况下更改 JLabel 文本的函数 此时它挂起 我认为问题是 Swing EDT 已终止或正在等待某
  • 使用 DBCP 配置 Tomcat

    在闲置一段时间 几个小时 后 我们收到了 CommunicationsException 来自 DBCP 错误消息 在异常中 位于这个问题的末尾 但我没有看到任何配置文件中定义的 wait timeout 我们应该看哪里 在 tomcat
  • Spring 作为 JNDI 提供者?

    我想使用 Spring 作为 JNDI 提供程序 这意味着我想在 Spring 上下文中配置一个 bean 可以通过 JNDI 访问该 bean 这看起来像这样
  • 在会话即将到期之前调用方法

    我的网络应用程序有登录的用户 有一个超时 在会话过期之前 我想执行一个方法来清理一些锁 我已经实现了sessionListener但一旦我到达public void sessionDestroyed HttpSessionEvent eve

随机推荐