Java基础-复习02-String

一. 概述(java.lang.String类)

  • public final class String,String类被声明为final,因此不可变不可被继承
  • Java 8中,String内部使用char[]数组存储数据
public final char[] value;
  • Java 9之后,使用byte[]数组存储数据,并用coder标识编码方式
public final byte[] value;
public final coder;

问题1:String为什么定义为final,有什么好处?
1、如果一个String对象已经被创建过了,那么就会从字符串常量池(String Pool在heap内)中取得引用
2、当String用做HashMap的key,不可变特性可以使hash值也不可变,因此只需要计算一次
3、String不可变性天生具备线程安全,可以在多个线程中安全地使用。

二. String实例化

方法一:字面量方式赋值

String s = "abc"; 
/*JVM首先会去字符串池中查找是否存在"abc"这个对象
1、不存在,则在字符串池中创建"abc"这个对象,然后将引用地址返回给字符串常量s,s指向"abc"
2、存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给字符串常量s

方法二:new构造器

String s = new String("abc"); 
/*JVM首先在字符串池中查找有没有"abc"这个字符串对象
1、不存在,则先在字符串池中创建"abc"字符串对象,再在堆中创建一个"abc"字符串对象,
然后将堆中的"abc"对象地址返回给s引用,s指向堆中的"abc"
2、存在,则不在字符串池中再去创建"abc"这个对象,直接在堆中创建一个"abc"字符串对象,
然后将堆中的"abc"对象地址返回给s引用,s指向堆中的"abc"

问题2:判断下列代码

String s1 = "abcd";
String s2 = "abcd";
System.out.println(s1 == s2); //true

String s3 = new String("abcd");
String s4 = new String("abcd");
System.out.println(s3 == s4); //false

String s5 = s4.intern();
String s6 = s4.intern();
System.out.println(s5 == s6); //true
/*字符串调用intern()方法
如果字符串池中已经存在一个字符串和该字符串值相等(equals()方法),则返回字符串池中对象的引用
否则,就会在字符串池中添加一个新的字符串,并返回这个新字符串对象的引用

三. String与其他类型转换

1. String与基本类型、包装类转换

String -> 基本类型、包装类:调用包装类静态方法parseXxx()

String s = "123";
Int i = Integer.parseInt(s);

基本类型、包装类 -> String:调用String的valueOf()

int i = "123";
String s = String.valueOf(i);

2. String与字符数组转换

String -> char[]:调用String的toCharArray()

String s = "abc";
char[] c = String.toCharArray(s);

char[] -> String:调用String构造器

char[] c = new char[]{'a', 'b', 'c'};
String s = new String(c);

3. String与字节数组转换

String -> byte[]:编码,调用String的getBytes()

String s = "abc123一二三";
byte[] b1 = s.getBytes(); //使用默认方式编码
byte[] b2 = s.getBytes("gbk"); //使用gbk编码

byte[] -> String:解码,调用String构造器

String s1 = new String(b1); //使用默认方式解码
String s2 = new String(b2, "gbk"); //使用gbk解码

四. StringBuffer和StringBuilder

1. 可变性

  • String不可变
  • StringBuffer和StringBuilder可变

2. 线程安全性

  • String线程安全,效率最低
  • StringBuffer线程安全,内部使用synchronized同步,但效率较低
  • StringBuilder线程不安全,未加线程锁,但效率较高
  • 运行速度:StringBuilder > StringBuffer > String
/*以StringBuffer为例,StringBuilder同理*/
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建长16字符数组
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length()+16];

3. 结论:

少量操作字符串使用:String
多线程大量操作字符串使用 :StringBuffer(int capacity)
单线程大量操作字符串使用:StringBuilder(int capacity)

常用方法:

  • 增:.append(xxx)
  • 删:.delete(int start,int end)
  • 改:setCharAt(int n ,char ch) / replace(int start, int end, String str)
  • 查:charAt(int n)
  • 插:insert(int offset, xxx)
  • 长度:length()
  • 遍历:for() + charAt() / toString()

五. 字符串拼接

  • 字符串间或字符串常量间拼接,相当于拼接后的字符串,直接存入字符串常量池
String s = "a" + "b" + "c"; //等同于 String s = "abc",也就是说在字符串常量池存入了"abc"

final String s1 = "a";
final String s2 = "b";
String s3 = s1 + s2; //等同于 String s3 = "ab"
  • 拼接元素如果存在字符串的引用(变量),结果则存入堆中新创建的对象中
String s = "Hello";
String s1 = "Hello" + "World"; //结果在字符串常量池,s1指向常量池中的"HelloWorld"
String s2 = s + "World"; //结果在堆中的对象里,s2指向对象里的"HelloWorld"
System.out.println(s1 == s2); //false,地址不同

String s2 = s + “World”; 内部过程如下

  1. 创建StringBuilder,从局部变量表加载变量s,调用append方法
  2. 根据s变量地址找到常量池里的"Hello"进行append,再对"World",append
  3. appendStringBuilder调用toString方法,类似于new出新的字符串(和new的区别在于,如果常量池不存在拼接完成的字符串,也不会自动在常量池里创建,但是new会)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值