String 类型的值能够被反射改变从而引发的意外事件
- 今天刷技术文章,遇到了一个问题,用 Java 反射机制去修改 String 变量的值,出于深入研究,就发现了一个问题,即,用初始值比较修改后的值,用 == or .equals() 方法,出现了相等的情况
文字描述看起来比较难受,我们直接看代码
//创建字符串"Hello World", 并赋给引用 s
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
//改变value属性的访问权限
valueFieldOfString.setAccessible(true);
//获取s对象上的value属性的值
byte[] value = (byte[]) valueFieldOfString.get(s);
//改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
System.out.println("Hello World".toString());
System.out.println(s == "Hello World"); // true
System.out.println(s.equals("Hello World")); // true
如上方代码所示,我们定义了一个 String 变量 s ,并且赋值给它 "Hello World",然后通过 Java 的反射机制去修改第五个字符的值,在输出结果的时候,理所当然的结果是 "Hello_World",但是我在这个情况之上多了一手,把被修改后的值与初始值比较看看,会发生什么情况,结果一试就出现了问题,竟然与初始值相等且返回了 true .
于是,打算好好深究一下,我们知道 String 的变量是存放在 JVM 的常量池中的,同时指向 "Hello World" 的引用 s1 是 String 对象,存放在堆区,我们通过反射区修改的值并不是常量池中的 "Hello World" ,而是 堆区中的对象 s1 的值,所以我们输出 s1 的时候就是 "Hello_World" ,那么为什么初始值比较修改后的值的时候会出现 true 呢?
我们看看 System.out.println("Hello World".toString()); 这行代码,输出结果是 Hello_World,这是因为 "Hello World".toString() 的时候,会去常量池中去找 "Hello World"的引用,它的引用就是 s1 ,所以输出的是 s1 的值,即 "Hello_World",所以,到这里,我们就知道了,为什么 s == "Hello World" 和 s.equals("Hello World") 返回 true 了 .
[reference]
String类型的值能够被反射改变和常量池的理解
String字符串被创建的原理过程
Java内存图以及堆、栈、常量区、静态区、方法区的区别

Java中 类的加载概述和加载时机

String 类型的值能够被反射改变从而引发的意外事件的更多相关文章
- C#中string类型是值类型还是引用类型?
.Net框架程序设计(修订版)中有这样一段描述:String类型直接继承自Object,这使得它成为一个引用类型,也就是说线程上的堆栈上不会驻留有任何字符串. string类型(引用类型) 名称 CT ...
- C#中string类型是值类型还是引用类型?(转)
出处:https://www.cnblogs.com/dxxzst/p/8488567.html .Net框架程序设计(修订版)中有这样一段描述:String类型直接继承自Object,这使得它成为一 ...
- SpringMVC中使用@Value给非String类型注入值
String类型的@Value注入方式 String类型的直接可以使用 @Value("陈婉清") private String name; 非String类型的@Value注入方 ...
- 为什么说Java String 类型的值是不可改变的?
String对象是不可变的,它的内容是不能改变的.下列代码会改变字符串的内容吗? 1 2 String s = "Java"; s = "HTML"; 答案是不 ...
- Java - 尚学堂第八章常用类(将输入的string类型的值转为整数、浮点型、日期类型)
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...
- String 类型
一.不可变 一个 String 类型的值是不可以改变的,比如,String china = "中国",“中国”这个字符串从它创建开始直到销毁都是不可改变的. 二.字符串常量池 字面 ...
- C#中特殊的string类型
string C#有string关键字,在翻 ...
- java对象转化成String类型
在java项目的实际开发和应用中,常常需要用到将对象转为String这一基本功能.本文将对常用的转换方法进行一个总结.常用的方法有Object#toString(),(String)要转换的对象,St ...
- redis的数据类型(二)string类型
下面讲解value,value包括String.List.Set.Sorted Set.Hash 一.String类型 1.string类型 String是最基本的类型,而且Stirng类型是二 ...
随机推荐
- PAT Basic 1006
1006 换个格式输出整数 (15 分) 让我们用字母 B 来表示“百”.字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超过 3 位的正整数 ...
- static之静态初始化块
static之静态初始化块 所有的静态初始化块都优先执行,其次才是非静态的初始化块和构造函数,它们的执行顺序是: 父类的静态初始化块 子类的静态初始化块 父类的初始化块 父类的 ...
- Oracle分组小计、总计示例(grouping sets的使用)
1.首先创建一个表 create table TE ( ID VARCHAR2(2), T_CODE VARCHAR2(4), T_NAME VARCHAR2(4), T_A ...
- Docker卸载高版本重装低版本后启动提示:driver not supported
解决方法: mv /var/lib/docker /var/lib/docker.old 其实就是docker镜像文件夹目录作怪,新版本的目录无法与旧版本目录相兼容. 不过建议降级的用户这样操作: y ...
- Oracle中连接与加号(+)的使用
1.左外连接(Left outer join/ left join) left join是以左表的记录为基础的,左表的记录将会全部表示出来,而右表只会显示符合搜索条件的记录.右表记录不足的地方均为NU ...
- Unity Inspector面板常用的属性
在扩展Unity的时候,往往会用到一些属性,这里将常用的列一下. 1.属性只读: #if UNITY_EDITOR using UnityEditor; #endif using UnityEngin ...
- mysql select into 不支持
不支持的 select * into order_new from orders 改为 Create table order_new(select * from orders)
- 系统架构-设计模式(适配器、观察者、代理、抽象工厂等)及架构模式(C/S、B/S、分布式、SOA、SaaS)(干货)
博客园首页是需要分享干货的地方,今天早上写的<HRMS(人力资源管理系统)-从单机应用到SaaS应用-系统介绍>内容下架了,所以我就按照相关规定,只分享干货,我把之前写完的内容整理发布上来 ...
- tp5.1的安装与运行流程
今天安装tp5.1的时候出现问题,我这里使用的是将tp直接解压缩后放在项目里面,结果提示下面的错误:Warning: require(D:\workspace\zhiyuedu\vendor/topt ...
- 【Spring】Springboot监听器,启动之后初始化工作
package com.laplace.laplace.common.starter.config; import java.io.IOException; import org.slf4j.Logg ...