java中字符串“不可变性”的破坏,使用反射破坏final属性。以及涉及到字符串常量池的问题。
大家都清楚java中String类是不可变的,它的定义中包含final关键字。一旦被创建,值就不能被改变(引用是可以改变的)。
但这种“不可变性”不是完全可靠的,可以通过反射机制破坏。参考一下代码:
String str = "abc";
System.out.println(str); Field field = String.class.getDeclaredField("value");
field.setAccessible(true); char[] value = (char[])field.get(str);
value[0] = '1';
value[1] = '2';
value[2] = '3'; System.out.println(str);
这段程序会输出:
abc
123
此处没有给str赋上新的引用值,说明字符串对象确实被改变了。但如果创建新的String对象,用来进行比对的话,会发现一个有趣的现象。先看代码及注释中的运行结果:
String str = "abc";
System.out.println(str); //打印abc Field field = String.class.getDeclaredField("value");
field.setAccessible(true); char[] value = (char[])field.get(str);
value[0] = '1';
value[1] = '2';
value[2] = '3';
System.out.println(str); //打印123 String str1 = "123";
String str2 = "abc"; System.out.println(str1 == str); //打印false
System.out.println(str2 == str); //打印true System.out.println(str1.equals(str)); //打印true
System.out.println(str2.equals(str)); //打印true
System.out.println(str2.equals(str1)); //打印true System.out.println(str); //打印123
System.out.println(str1); //打印123
System.out.println(str2); //打印123
前两个打印仍然是原先的值就不说,后面几个输出信息就很有意思了。仔细想想其出现的原因,应该是因为有字符串常量池的存在。常量池相关的知识网上和各种java基础的书上有很多介绍,这里只简单说下:
jvm在用户创建字符串的时候,会检查字符串常量池中该字符串(字面量,而不是引用)是否存在,若不存在,则将字符串放入常量池中,如果存在则直接返回该字符串的内存地址给String对象。
现在问题就清楚了,str1和str2创建的时候,JVM没有在常量池中找到123这个字面量,找到了abc这个字面量(之前创建过),所以给str1分配了新的内存,而直接将abc的内存地址(虽然现在已经不是存储的abc这个字面量了),即str指向的地址直接返回给了str2。
所以当用==比较的时候,str和str1指向不同的内存地址,返回了false,而str和str2则会返回true。
后面的equals比较,只要清楚一点就能搞清楚原因了:为什么str2的值会是123呢?因为如上所诉,JVM在创建str2的时候,直接将abc这个内存的地址给到了str2,而这个内存块中现在存储的值已经被我们通过反射强行改成了123。
java中字符串“不可变性”的破坏,使用反射破坏final属性。以及涉及到字符串常量池的问题。的更多相关文章
- Java中对不变的 data和object reference 使用 final
Java中对不变的 data和object reference 使用 final 许多语言都提供常量数据的概念,用来表示那些既不会改变也不能改变的数据,java关键词final用来表示常量数据.例如: ...
- Java循环一个对象的所有属性,并通过反射给这些属性赋值/取值
Java循环一个对象的所有属性,并通过反射给这些属性赋值/取值 说到循环遍历,最常见的遍历数组/列表.Map等.但是,在开发过程中,有时需要循环遍历一个对象的所有属性.遍历对象的属性该如何遍历呢?查了 ...
- JAVA中内部类(匿名内部类)访问的局部变量为什么要用final修饰?
本文主要记录:在JAVA中,(局部)内部类访问某个局部变量,为什么这个局部变量一定需要用final 关键字修饰? 首先,什么是局部变量?这里的局部是:在方法里面定义的变量. 因此,内部类能够访问某局部 ...
- java中的成员变量、类变量,成员方法、类方法 属性和方法区别
成员变量:包括实例变量和类变量,用static修饰的是类变量,不用static修饰的是实例变量,所有类的成员变量可以通过this来引用. 类变量:静态域,静态字段,或叫静态变量,它属于该类所有实例共有 ...
- 一、图解Java中String不可变性
这里有一堆例子来说明Java的String的不可变性. 1.声明一个String String s = "abcd"; s 变量保存string对象的引用,下面的箭头解释成保存了哪 ...
- 认识Java中的字符串
Java 中 String 类的常用方法 Ⅰ String 类提供了许多用来处理字符串的方法,例如,获取字符串长度.对字符串进行截取.将字符串转换为大写或小写.字符串分割等,下面我们就来领略它的强大之 ...
- java中字符串的存储
在java中,不同的字符串赋值方法,其所在的地址可能不同也就导致,两个字符串的值看似相等可是在s1==s2操作时,其结果返回的却是false 例: String s1 = "Programm ...
- 详解Java中的字符串
字符串常量池详解 在深入学习字符串类之前, 我们先搞懂JVM是怎样处理新生字符串的. 当你知道字符串的初始化细节后, 再去写String s = "hello"或String s ...
- Java中的字符串操作(比较String,StringBuiler和StringBuffer)
一.前言 刚开始学习Java时,作为只会C语言的小白,就为其中的字符串操作而感到震撼.相比之下,C语言在字节数组中保存一个结尾的\0去表示字符串,想实现字符串拼接,还需要调用strcpy库函数或者自己 ...
- 深入理解Java中的String
一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码: public final class String implements java.io.Ser ...
随机推荐
- vue admin mock数据
搭建脚手架axios访问不到接口:mock数据的问题mock下的index.js设置了默认指向
- Python Django Web开发的5个优秀好习惯
https://blog.csdn.net/weixin_42134789/article/details/82381854
- XV Open Cup named after E.V. Pankratiev. GP of Central Europe (AMPPZ-2014)--B.Petrol
多源最短路+并查集 #include <bits/stdc++.h> using namespace std; #define rep(i, j, k) for (int i = int( ...
- Weblogic WLS-WebServices组件反序列化漏洞复现
漏洞分析: 当weblogic使用WLS-WebServices组件时,该组件会调用XMLDecoder解析XML数据,由此就产生了该漏洞 影响版本: weblogic<10.3.6版本 复现过 ...
- java protected修饰符说明
1. 简介 对protected修饰符进行阐述,结合Object类的clone方法进行说明.其中clone方法如下:protected Object Object.clone(): 关于protect ...
- var that = this 小坑记
在js编码过程中,经常会使用如上的语句来规避拿不到变量的问题. 比如: queryData:function () { var that=this; var param={}; for(var key ...
- maven到Gradle,一些对比和分享
Gradle作为一款基于Groovy语言的构建工具,已经吸引众多的ant,maven使用者转投gradle的怀抱,和Gradle相比,ant显得冗余复杂,maven显得有些死板落后,而gradle基于 ...
- Tsinghua 2018 DSA PA2简要题解
反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...
- nginx 实现所有的子域名301跳转到另外一个域名的对应子域名
server { listen ; server_name *.olddomain.com; if ( $http_host ~* "^(.*?)\.olddomain\.com$" ...
- Android 音视频深入 十八 FFmpeg播放视频,有声音(附源码下载)
项目地址https://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpegv%E6%92%AD%E6%94%BE%E8%A7% ...