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类型是二 ...
随机推荐
- Quartz 定时器任务调度配置(以及如何配置quartz启动执行一次)
1. 添加maven依赖.pom.xml 中添加jar文件 <!-- 作业任务调度机制 --> <dependency> <groupId>org.quartz-s ...
- ES6项目构建(babel+gulp+webpack)
(一)基础架构 (二)任务自动化(gulp) (三)编译工具(babel,webpack) (四)代码实现 一.基础构架 1.app : 放置前端代码 css : css文件 js : js文件 cl ...
- JSAP102
JSAP102 1.API //案例:禁用文本框 <body> <input type="button" value="禁用" id=&quo ...
- [CentOS7]redis设置开机启动,设置密码
简介 上篇文章介绍了如何安装redis,但每次重启服务器之后redis不会自启,这里将介绍如何进行自启设置,以及如何设置redis的密码,进行密码验证登陆. 上篇文章: Centos7安装Redis ...
- Win7或Win8上安装VS2015报“安装包丢失或损坏”问题的解决办法
原因:microsoft root certificate authority 2010.microsoft root certificate authority 2011证书未安装,导致文件校验未通 ...
- 遇到一个git branch很奇怪的问题
最近,同事做了一个自动化的打包平台,但我发现里面的分支竟然有重复的,还有一些已经删除的branch. 比如,我已经删除了一个 test分支,在工程 game 目录下(已输入 git pull),输入: ...
- 第二天学习笔记:(MDN HTML学习、web安全策略与常见攻击、语义化)
一:Web入门 1:web文件命名 在文件名中应使用连字符(-).搜索引擎把连字符当作一个词的分隔符, 但不会以这种方式处理下划线. 养成在文件夹和文件名中使用小写,并且使用短横线而不是空格来分隔的习 ...
- Linux 修改时区
CentOS 7修改方式如下: # lsb_release -a --查看系统版本-CentOS Linux release 7.6 # timedatectl --查看当前系统时区# ls ...
- 一个会学习(观察->活学->求变)的人,在任何领域都能变得强大无比
开始今天的话题之前,我说个小故事. 很早以前有一部美剧,叫<Hero>. 大概讲的是正反两派都是一群有超能力的人,彼此为了某个巨大的阴谋互相撕逼了十多集.虽然剧情很老套,但是让 ...
- Nop--NopCommerce源码架构详解专题目录
最近在研究外国优秀的ASP.NET mvc电子商务网站系统NopCommerce源码架构.这个系统无论是代码组织结构.思想及分层都值得我们学习.对于没有一定开发经验的人要完全搞懂这个源码还是有一定的难 ...