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 ...
随机推荐
- 20175317 《Java程序设计》第八周学习总结
20175317 <Java程序设计>第八周学习总结 教材学习内容总结 第八周我学习了教材第十五章的内容,认识了什么是泛型与集合框架,具体内容如下: 泛型 1. 如何声明泛型类 2. 如何 ...
- Lab 11-3
Analyze the malware found in Lab11-03.exe and Lab11-03.dll. Make sure that both files are in the sam ...
- 浅谈企业IT技术运营中台
关注嘉为科技,获取运维新知 如果你是IT圈内的人,在2月份,你的朋友圈里面最火的词应该就是“中台”了,我们在此不讨论企业的技术中台.数据中台.AI中台.业务中台,想和大家讨论一下IT技术运营中台. “ ...
- git同时存在两个账号(在同一台电脑上)——三步完成
目录 1.首先是常规设置 2.同时添加两个账号 3.最后一步,配置~/.ssh/config文件 4.补充:有时因为设置了全局账号,因此需要清除 由于本人有连个git账号,个人github账号和公司g ...
- mui底部选项卡切换实现
MUI提供了两种webview和div模式,来实现底部选项卡切换 效果相同,div是在同一个页面实现所有切换块的页面,根据id导航,而webview是由多个页面组成,形成页面之间的来回跳转
- [cf contest 893(edu round 33)] F - Subtree Minimum Query
[cf contest 893(edu round 33)] F - Subtree Minimum Query time limit per test 6 seconds memory limit ...
- 德邦总管 修改oracle数据库用户密码的方法
WIN+R打开运行窗口,输入cmd进入命令行: 输入sqlplus ,输入用户名,输入口令(如果是超级管理员SYS的话需在口令之后加上as sysdba)进入sql命令行: 连接成功后,输入“s ...
- Could not autowire. No beans of 'xxxx' type found的错误
在Idea的spring工程里,经常会遇到Could not autowire. No beans of 'xxxx' type found的错误提示.但程序的编译和运行都是没有问题的,这个错误提示并 ...
- python中os模块在windows下的使用
今天学习了一下Python的os模块,主要是针对文件夹和文件路径的一系列操作. 与Python内置函数相比这里这里的函数功能更多样化,功能也更强大.但是学习过程中我发现很多函数都是只适用于unix系统 ...
- Linux c使用gumbo库解析页面表单信息(二)
一.如何在程序当中使用gumbo? 要想在代码中使用gumbo,仅仅包含gumbo头文件是不够的,必须在编译程序的时候加上-lgumbo选项,编译程序才会链接到gumbo库上面. 这是我编译gumbo ...