本文转载自微信公众号「学习Java的小姐姐」,作者学习Java的小姐姐0618。转载本文请联系学习Java的小姐姐公众号。
创新互联主营遂溪网站建设的网络公司,主营网站建设方案,app软件定制开发,遂溪h5重庆小程序开发公司搭建,遂溪网站营销推广欢迎遂溪等地区企业咨询
1.1不变性
我们常常听人说,HashMap 的 key 建议使用不可变类,比如说 String 这种不可变类。这里说不可变指的是类值一旦被初始化,就不能再被改变了,如果被修改,将会是新的类,我们写个demo 来演示一下。
- public class test {
- public static void main(String[] args){
- String str="hello";
- str=str+"world";
- }
- }
从代码上来看,s 的值好像被修改了,但从 debug 的日志来看,其实是 s 的内存地址已经被修了,也就说 s =“world” 这个看似简单的赋值,其实已经把 s 的引用指向了新的 String,debug 截图显示内存地址已经被修改,两张截图如下,我们可以看到标红的地址值已经修改了。
用示意图来表示堆内存,即见下图。
我们可以看下str的地址已经改了,说了生成了两个字符串,String类的官方注释为Strings are constant; their values cannot be changed after they are created. 简单翻译下为字符串是常量;它们的值在创建后不能更改。
下面为String的相关代码,如下代码,我们可以看到:
1. String 被 final 修饰,说明 String 类绝不可能被继承了,也就是说任何对 String 的操作方法,都不会被继承覆写,即可保证双亲委派机制,保证基类的安全性。
2. String 中保存数据的是一个 char 的数组 value。我们发现 value 也是被 final 修饰的,也就是说 value 一旦被赋值,内存地址是绝对无法修改的,而且 value 的权限是 private 的,外部绝对访问不到,String没有开放出可以对 value 进行赋值的方法,所以说 value 一旦产生,内存地址就根本无法被修改。
- //char类型的final数组
- private final char value[];
- //hash值
- private int hash;
- private static final long serialVersionUID = -6849794470754667710L;
1.2相等判断
相等判断逻辑写的很清楚明了,如果有人问如何判断两者是否相等时,我们可以从两者的底层结构出发,这样可以迅速想到一种贴合实际的思路和方法,就像 String 底层的数据结构是 char 的数组一样,判断相等时,就挨个比较 char 数组中的字符是否相等即可。(这里先挖个坑,携程问过类似题目)
- public boolean equals(Object anObject) {
- //如果地址相等,则直接返回true
- if (this == anObject) {
- return true;
- }
- //如果为String字符串,则进行下面的逻辑判断
- if (anObject instanceof String) {
- //将对象转化为String
- String anotherString = (String)anObject;
- //获取当前值的长度
- int n = value.length;
- //先比较长度是否相等,如果长度不相等,这两个肯定不相等
- if (n == anotherString.value.length) {
- char v1[] = value;
- char v2[] = anotherString.value; int i = 0; //while循环挨个比较每个char
- while (n-- != 0) {
- if (v1[i] != v2[i])
- return false;
- i++;
- }
- return true;
- }
- }
- return false;
- }
相等逻辑的流程图如下,我们可以看到整个流程还是很清楚的。
1.3替换操作
替换在平时工作中也经常使用,主要有 replace 替换所有字符、replaceAll 批量替换字符串、replaceFirst这三种场景。
下面写了一个 demo 演示一下三种场景:
- public static void main(String[] args) {
- String str = "hello word !!";
- System.out.println("替换之前 :" + str);
- str = str.replace('l', 'd');
- System.out.println("替换所有字符 :" + str);
- str = str.replaceAll("d", "l");
- System.out.println("替换全部 :" + str);
- str = str.replaceFirst("l", "");
- System.out.println("替换第一个 l :" + str);
- }
输出的结果是:
这边要注意一点是replace和replaceAll的区别,不是替换和替换所有的区别哦。
而是replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\\d", "*"),而replace则不会,replace("\\d","*")就是替换"\\d"的字符串,而不会解析为正则。
1.4 intern方法
String.intern() 是一个 Native 方法,即是c和c++与底层交互的代码,它的作用(在JDK1.6和1.7操作不同)是:
如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则直接返回常量池中该字符串的引用;
如果没有, 那么在jdk1.6中,将此String对象添加到常量池中,然后返回这个String对象的引用(此时引用的串在常量池)。
在jdk1.7中,放入一个引用,指向堆中的String对象的地址,返回这个引用地址(此时引用的串在堆)。
- public native String intern();
如果看上面看不懂,我们来看下一下具体的例子,并来分析下。
- public static void main(String[] args) {
- String s1 = new String("学习Java的小姐姐");
- s1.intern();
- String s2 = "学习Java的小姐姐";
- System.out.println(s1 == s2);
- String s3 = new String("学习Java的小姐姐") + new String("test");
- s3.intern();
- String s4 = "学习Java的小姐姐test";
- System.out.println(s3 == s4);
- }
我们来看下结果,实际的打印信息如下。
为什么显示这样的结果,我们来看下。所以在 jdk7 的版本中,字符串常量池已经从方法区移到正常的堆 区域了。
我们再看下,如果把上面的两行代码调整下位置,打印结果是不是不同。
- public static void main(String[] args) {
- String s1 = new String("学习Java的小姐姐");
- String s2 = "学习Java的小姐姐";
- s1.intern();
- System.out.println(s1 == s2);
- String s3 = new String("学习Java的小姐姐") + new String("test");
- String s4 = "学习Java的小姐姐test";
- s3.intern();
- System.out.println(s3 == s4);
- }
2.1 继承结构
2.2 主要区别
1)String是不可变字符序列,StringBuilder和StringBuffer是可变字符序列。
2)执行速度StringBuilder > StringBuffer > String。
3)StringBuilder是非线程安全的,StringBuffer是线程安全的。
新闻名称:真的懂Java的String吗?
网页路径:http://www.shufengxianlan.com/qtweb/news42/518292.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联