栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Java

Java基础汇总(二)——String(重点string.intern())

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java基础汇总(二)——String(重点string.intern())

 一、==运算符和equals之间的区别:

  • 对于基本数据类型,==比较的是值是否相同
  • 对于引用数据类型,==比较的是内存地址是否相同
  • equals仅比较引用指向的内容(值)是否相同

二、字符串的不可变性

String的对象一旦被创建,则不能修改,是不可变的。所谓的修改其实是创建了新的对象,引用指向新的对象。

例:

String s = "abc";// (1) 创建新的对象"abc" s为指向对象abc的引用
System.out.println("s = " + s);//abc
s = "123";  (2) //创建新的对象"123" 引用s指向新的对象123
System.out.println("s = " + s);//123

执行(1)处代码后,首先会在方法区的运行时常量池创建一个新的对象"abc",其次在Java栈中创建一个对象的引用s,并让s指向"abc";

执行(2)处代码后,首先会在方法区的运行时常量池创建一个新的对象"123",然后让Java栈中创建的的引用s重新指向“123”,而原来的对象"abc"还在内存中,并没有改变。

1. String为什么不可变

  • String类用final关键字修饰,不可继承
  • 但是String对象的引用本身是可以改变指向其他的对象的
  • final修饰的char[]数组保证了char数组的引用不可变,内容可变。但String内部并不提供方法来完成这一操作,所以String的不可变是基于代码封装和访问控制的。

例:java.lang.String类代码前三行

public final class String implements java.io.Serializable, Comparable, CharSequence {   
       
private final char value[];
 } 

String不可变是为了线程的安全!!!

2. String, StringBuffer and StringBuilder的区别:

可变性:

  • String 不可变
  • StringBuffer 和 StringBuilder 可变

线程安全:

  • String 不可变,因此是线程安全的
  • StringBuffer 是线程安全的,内部使用 synchronized 进行同步
  • StringBuilder 不是线程安全的

适用场景:

  • 少量的字符串数据,可以考虑String
  • 单线程场景下操作大量字符串数据,考虑使用StringBuilder
  • 多线程场景下操作大量字符串数据,考虑使用StringBuffer 

3. StringBuffer

StringBuffer提供append和add方法,可以将字符串添加到已有序列的末尾或指定位置

  • append方法
String s = "abc";
String s1 = s + s;
System.out.println("s1 = " + s1);

String类型在使用 “+” 运算符时,首先把“abc”封装成stringbuilder,其次调用append方法,最后再用tostring返回。所以当大量使用字符串加法时,会大量地生成stringbuilder实例,这是十分浪费的,这种时候应该用stringbuilder来代替string。

三、String.intern()

例1:

String s = new String("1"); 

/* JDK1.6及以下:首先在字符串常量池和堆中创建相应对象"1",s为指向堆中的引用
   JDK1.7及以上:首先在字符串常量池和堆中创建相应对象"1",s为指向堆中的引用
/*

s.intern();

/* JVM判断字符串常量池中是否存在对象"1",若存在,引用s依旧指向堆中;
   若不存在
   JDK1.6及以下:将堆中相应对象复制到字符串常量池中,引用s.intern()指向常量池
   JDK1.7及以上:将堆相应对象的地址放到字符串常量池中,引用s.intern()指向常量池
/*

String s2 = "1";

/* JVM判断字符串常量池是否存在对象"1",
   若存在,引用s2直接指向常量池(JDK1.6及以下:引用s2指向常量池中的对象"1";
                               JDK1.7及以上:引用s2指向常量池中对象"1"在堆中的地址,相当于引用s2指向堆);
若不存在,在常量池中创建相应对象"1",引用s指向相应常量池
/*

System.out.println(s == s2); // 无论JDK1.6及以下还是JDK1.7及以上输出结果为false


例2:

String s3 = new String("1") + new String("1");

/* JDK1.6及以下:首先在字符串常量池中创建对象"1",其次在堆中分别创建两个String对象"1",最后在堆中通过.append方法创建对象"11",引用s3指向对象"11"
   JDK1.7及以上:首先在字符串常量池中创建对象"1",其次在堆中分别创建两个String对象"1",最后在堆中通过.append方法创建对象"11",引用s3指向对象"11"
/*

s3.intern();

/* JVM判断字符串常量池中是否存在对象"11",若存在,引用s3依旧指向堆中;
   若不存在
   JDK1.6及以下:将堆中相应对象复制到字符串常量池中,引用s3.intern()指向常量池
   JDK1.7及以上:将堆相应对象的地址放到字符串常量池中,引用s3.intern()指向常量池(这时的引用s3相当于指向堆)
/*

String s4 = "11";

/* JVM判断字符串常量池是否存在对象"11",
   若存在,引用s2直接指向常量池(JDK1.6及以下:引用s4指向常量池中的对象"11";
                               JDK1.7及以上:引用s4指向常量池中对象"11"在堆中的地址,相当于引用s4指向堆);
若不存在,在常量池中创建相应对象"11",引用s4指向相应常量池
/*

System.out.println(s3 == s4);

/* JDK1.6及以下 false
   JDK1.7及以上 true
/* 

图1:JDK1.6和1.7的例1都为图1所示

 图2:JDK1.6为黑色线条 所示;JDK1.7为红色线条所示

 搞懂String.intern()的关键就是对于new String(),其会分别在常量池和堆中分别建立新的对象引用,然后将引用指向堆中;然后s.intern()会将堆中的内容或者地址放置在常量池中(若常量池中不存在该对象),反之引用不变;而常量字符串的赋值如String s2 = "1"直接放入常量池中;

对于如new String(“1”)+new String(“1”)的字符串,其首先在常量池中创建对象“1”,其次在堆中创建两个new String(“1”),最后通过.append方法在堆中创建“11”(此时常量池中无对象“11”)。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1036451.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号