Java中的String数据类型,String字符串类详解(进阶二)

Java中的String数据类型,String字符串类详解(进阶二)

目录

第一章、String概述1)String是什么2)String长什么样3)String的构造方法(声明方式)

第二章、String类的详解1)String底层是什么2)字符串存储的内存原理/字符串常量池(String Constant Pool)3)字符串之间的比较问题①字符串之间的直接比较②字符串拼接完毕后做==比较的问题

4)字符串与其他类型的转换①String字符串与基本数据类型的转换②String字符串与包装类型的转换

5)String类常用方法

第三章、字符串缓冲区StringBuffer和StringBuilder1)字符串缓冲区概述2)StringBuffer和StringBuilder声明方式3)StringBuffer/StringBuilder和String类型之间的转换4)二者的常用方法

第一章、String概述

1)String是什么

①String表示字符串类型,是引用数据类型不是基本数据类型,String是类且是最终类,不能有子类。 ②字符串虽然是引用类型属于对象,但是它不是存储在堆空间中,而是存储在方法区中的字符串常量池中。只要我们书写了双引号,数据都会立刻在字符串常量池中保存。

2)String长什么样

使用双引号包裹起来的都是String。 ①一个字母被双引号包裹起来的:

“A”

②多个字母被双引号包裹起来的:

“hello daShaGua!”

③中文被双引号包裹起来的:

“你好小可爱”

3)String的构造方法(声明方式)

字符串常用的构造方法:6种

构造方法作用String()初始化一个新创建的 String 对象,使其表示一个空字符序列。String(String original)初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。String(byte[] bytes)通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。String(byte[] bytes, int offset, int length)通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。String(char[] value)分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。String(char[] value, int offset, int count)分配一个新的 String,它包含取自字符数组参数一个子数组的字符。

Column 1Column 2centered 文本居中right-aligned 文本居右

public static void test1(){

//String()| 初始化一个新创建的 String 对象,使其表示一个空字符序列。

String s1 = ""; //空字符串

String s2 = new String(); //空字符串

//String(String original)| 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;

String s3 = new String(""); //空字符串

String s4 = new String("qwer");

//String(byte[] bytes) |通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

byte[] bs = {65,66,97,98};

//类型转换:byte[] --> String

String str = new String(bs);

System.out.println(str); //"ABab"

//String(byte[] bytes, int offset, int length)

//通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。

byte[] bs3 = {65,66,67,68,97,98,99,100};

//类型转换:byte[] --> String

String str3 = new String(bs3, 2, 5);

System.out.println(str3); //"CDab"

//String(char[] value) | 初始化一个新创建的 String 对象,使其表示字符数组参数中当前包含的字符序列。

char[] cs = {'j','a','v','a'};

//类型转换:char[] --> String

String str = new String(cs);

System.out.println(str); //"java"

//String(char[] value, int offset, int count) | 包含取自字符数组参数一个子数组的字符。

String str1 = new String(cs,0,2);

System.out.println(str1); //"ja"

}

第二章、String类的详解

1)String底层是什么

查看源码可以发现,String的底层是数组。 jdk1.8及以前String使用的是char数组

jdk1.9及以后使用的是byte数组 因为字符串底层是数组,所以可以遍历字符串

//第一种方式

//char charAt(int index):返回指定索引处的 char 值。

String str = "java";

for(int i = 0;i <= str.length() - 1;i++){

char c = str.charAt(i);

System.out.print(c);

}

//---------------------------分割------------------------------------------

//第二种方式

// char[] toCharArray():将此字符串转换为一个新的字符数组。

char[] cs = str.toCharArray();

for(int i = 0;i <= cs.length - 1;i++){

System.out.print(cs[i]);

}

2)字符串存储的内存原理/字符串常量池(String Constant Pool)

①字符串被保存在字符串常量池中,在JDK1.8 字符串常量池在堆中, 运行时常量池在方法区。 ②在java中String类型的值是不可改变的,指的是想要改变字符串值时会复用字符串常量池中的地址值。 例如:我们有一个字符串变量s = “a”,然后我们再对s赋值为”b”,我们并没有改变字符串s的值,只是在常量池中新建了一个字符串”b”,然后让s的地址值从指向”a”变成了指向”b”。

String s = "a";

s = "b";//并没有改变S的值,只是在常量池中新建了一个字符串”b”,然后让s从指向”a”变成了指向”b”

③直接赋值会复用字符串常量池中的地址值,new出来的不会复用,而是开辟一个新的空间

//直接赋值会复用字符串常量池中的地址

//它们的地址是一样的,这个就是 String 的复用性。"abc"在常量池中的,并且 s1 和 s2 都指向同一个地方。

String s1 = "abc";

String s2 = "abc";

System.out.println(s1 == s2); //true 比较的是地址值,s1和s2在常量池理指向了同一个地址值

System.out.println(s1.equals(s2)); //true 底层重写了toString所以调用equals方法时比较的是内容

//new出来的不会复用,而是开辟一个新的空间

String s3 = new String("abc");

System.out.println(s1 == s3); //false new出来的不会复用,而是开辟一个新的空间

System.out.println(s1.equals(s3)); //true 底层重写了toString所以调用equals方法时比较的是内容

ps:这里放一个老师的考题

//【问题】:执行完毕下列5行代码,内存中一共有几个对象?

//答:4个对象

String s1 = "hello"; //1个对象 在常量池中

String s2 = "hello"; //不会产生对象

String s3 = new String("hello"); //1个对象 在堆中

String s4 = new String("helloworld"); //2个对象 一个在堆中,另一个在常量池中

String s5 = "helloworld"; //不会产生对象

//所以一共是四个对象

3)字符串之间的比较问题

①字符串之间的直接比较

1、==比较的是地址值 2、equals比较的是字符串内容

//直接赋值会复用字符串常量池中的地址

//它们的地址是一样的,这个就是 String 的复用性。"abc"在常量池中的,并且 s1 和 s2 都指向同一个地方。

String s1 = "abc";

String s2 = "abc";

System.out.println(s1 == s2); //true 比较的是地址值,s1和s2在常量池理指向了同一个地址值

System.out.println(s1.equals(s2)); //true 底层重写了toString所以调用equals方法时比较的是内容

//new出来的不会复用,而是开辟一个新的空间

String s3 = new String("abc");

System.out.println(s1 == s3); //false new出来的不会复用,而是开辟一个新的空间

System.out.println(s1.equals(s3)); //true 底层重写了toString所以调用equals方法时比较的是内容

②字符串拼接完毕后做==比较的问题

1、字符串内容做==比较,比较的是地址值, 2、常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量,只要其中有一个是变量,结果就在堆中 3、只有常量池中数据内容进行,比较结果才会为true,有堆参与结果一定为false 4、如果拼接的结果调用intern()方法,返回值就在常量池中

String s1 = "hello"; //s1变量记录的是"hello"常量数据在常量池中的地址

String s2 = "world"; //s2变量记录的是"world"常量数据在常量池中的地址

String s3 = "helloworld"; //s3变量记录的是"helloworld"常量数据在常量池中的地址

System.out.println("hello" + s2 == s3); //常量 + 变量 结果在堆中 堆 == 常量池 false

System.out.println(s1 + "world" == s3); //变量 + 常量 结果在堆中 堆 == 常量池 false

System.out.println(s1 + s2 == s3); //变量 + 变量 结果在堆中 堆 == 常量池 false

System.out.println("hello" + "world" == s3); //常量 + 常量 结果在常量池中 常量池 == 常量池 true

System.out.println("================================");

System.out.println("hello" + s2 == "hello" + s2); //堆 == 堆 false

System.out.println(s1 + "world" == s1 + "world"); //堆 == 堆 false

System.out.println(s1 + s2 == s1 + s2); //堆 == 堆 false

System.out.println("hello" + "world" == "hello" + "world"); //常量池 == 常量池 true

System.out.println("*********************************");

/*

* String intern():返回字符串对象的规范化表示形式。

* 分析:

* jvm会去常量池中查找是否存在该字符串常量对象:

* 如果存在,则直接返回该常量对象在常量池中的地址信息

* 如果不存在,则先在常量池中创建该常量对象,再返回其在常量池中的地址信息

*/

System.out.println(("hello" + s2).intern() == ("hello" + s2).intern()); //常量池 == 常量池 true

System.out.println((s1 + "world").intern() == (s1 + "world").intern()); //常量池 == 常量池 true

System.out.println((s1 + s2).intern() == (s1 + s2).intern()); //常量池 == 常量池 true

System.out.println(("hello" + "world").intern() == ("hello" + "world").intern()); //常量池 == 常量池 true

4)字符串与其他类型的转换

①String字符串与基本数据类型的转换

1、字符串转为基本类型

String s1 = "123";

int i = Integer.parseInt(s1);

//类型转换:字符串转为基本类型

String s2 = "3.14";

double d = Double.parseDouble(s2);

2、基本类型转为字符串

int num = 123;

//类型转换:基本类型 -> String

String s1 = num + "";

String s2 = Integer.toString(num);

String s3 = String.valueOf(num);

②String字符串与包装类型的转换

1、包装类型转为字符串

Integer iObj = Integer.valueOf(123);

//类型转换:包装类型 -> 字符串类型

String str = iObj.toString();

System.out.println(str); //"123"

System.out.println(str instanceof String); //true

2、字符串转为包装类型

//类型转换:String -> 包装类型

Integer iObj1 = new Integer("123");

Double dObj = Double.valueOf("3.14");

5)String类常用方法

String类常用方法:将字符串内容转换为全大写/小写

public static void test5(){

/*

* 将字符串内容转换为全大写/小写

* String toLowerCase():使用默认语言环境的规则将此 String 中的所有字符都转换为小写。

* String toUpperCase():使用默认语言环境的规则将此 String 中的所有字符都转换为大写。

*/

String content = "Today is Friday pm";

String newContent = content.toLowerCase();

System.out.println(newContent);// 打印结果 today is friday pm

newContent = content.toUpperCase();

System.out.println(newContent);// 打印结果 TODAY IS FRIDAY PM

System.out.println(content);// 打印结果 Today is Friday pm

}

String类常用方法:查找字符在字符串中的位置

public static void test4(){

/*

* 得到传入的字符串在原串中首次/最后一次出现的位置:

* int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。

int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。

int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引。

int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。

注意:

从头到尾都比对不上,就返回-1

*/

String content = "山不在在高,有仙则名。水不在在深,有龙则灵。斯是陋室,惟吾德馨。";

int index = content.indexOf("在");//从第0个索引开始找,在第2个索引找到 第一个在

System.out.println(index); //2

index = content.indexOf("在", 5); //从第5个索引开始找,在第13个索引找到 第一个在

System.out.println(index); //13

index = content.lastIndexOf("则");//从第0个索引开始找,在第19个索引找到 最后一个则

System.out.println(index); //19

index = content.lastIndexOf("则",18);//从第18个索引开始向前找,在第8个索引找到 最后一个则

System.out.println(index); //8

index = content.indexOf("在在");//从第0个索引开始找,在第2个索引找到 第一个 在在

System.out.println(index); //2

index = content.indexOf("在再");//从第0个索引开始找,没找到 在再 返回-1

System.out.println(index); //-1

}

String类常用方法:根据参数截取字符串,获得新字符串

/* 截取字符串:

String substring(int beginIndex):

String substring(int beginIndex, int endIndex):

方法的参数存在起始索引和结束索引,绝大多数情况下,都满足含头不含尾的特点

*/

String content = "唧唧复唧唧,木兰当户织。不闻机杼声,惟闻女叹息。";

String newContent = content.substring(4);

System.out.println(content);//打印结果 唧唧复唧唧,木兰当户织。不闻机杼声,惟闻女叹息。

System.out.println(newContent);//打印结果 唧,木兰当户织。不闻机杼声,惟闻女叹息。

newContent = content.substring(3, 5);

System.out.println(newContent);//打印结果 唧唧

String类常用方法:切割字符串,返回数组

//根据正则规则切割字符串:String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。

//如果匹配不上,则不做任何的切割行为,将原串作为一个整体存入到数组容器中

String content = "java is a good lang,java is a nice lang";

String regex = ",";

String[] strs = content.split(regex);

System.out.println(Arrays.toString(strs) + "-->" + strs.length);

//打印结果[java is a good lang , java is a nice lang]-->2

String[] strs2 = content.split("@");

System.out.println(Arrays.toString(strs2) + "-->" + strs2.length);

//打印结果[java is a good lang , java is a nice lang]-->1

String类常用方法:拼接字符串的两种方式

//第一种

//拼接字符串:String concat(String str):将指定字符串连接到此字符串的结尾。

String s1 = "遥想公瑾当年,";

String s2 = "小乔初嫁了。";

String result = s1.concat(s2);

System.out.println(result);

//第二种

System.out.println("谈笑间," + "樯橹灰飞烟灭");

第三章、字符串缓冲区StringBuffer和StringBuilder

1)字符串缓冲区概述

①String是不能更改的,而StringBuffer与StringBuilder则是可变的字符序列。可以看成是高级的String。二者的内部方法是一致的。 ②缓冲区就是一个临时空间,它里面可以临时存储数据。缓冲区本身就是一个容器,把需要修改的字符串先存储到字符串缓冲区容器中,在容器中修改完成后存储在字符串常量池中。 ③任意类型都可以存储到字符串缓冲区。注意:是将任意数据都转成字符串进行存储;容器对象提供很多对容器中的数据操作的功能,比如添加,删除,修改,查询; ④StringBuffer它的线程安全是通过把各种修改数据的方法都加上 synchronized 关键字实现的,StringBuilder 是 Java 1.5 中新增的,它是在单线程环境下使用的所以去 掉了线程安全的部分所有方法都没有被 synchronized 修饰,相较于 StringBuffer 有速度优势。

2)StringBuffer和StringBuilder声明方式

// 默认含有16个字符的容量

StringBuffer sb1 = new StringBuffer();

//含12个字符容量的字符串缓冲区

StringBuffer sb2 = new StringBuffer(12);

// 含16+4的字符串缓冲区,"b cd"为4个字符容量

StringBuffer sb3 = new StringBuffer("b cd");

//StringBuilder 同理,就不一一举例了

StringBuilder sb = new StringBuilder("");

3)StringBuffer/StringBuilder和String类型之间的转换

//String类型--》StringBuilder

StringBuilder builder = new StringBuilder("abc");

StringBuilder builder2 = new StringBuilder("abcde");

////StringBuilder类型--》String

String str = builder.toString();

String str2= new String(builder2);

4)二者的常用方法

①添加

//空参构造

StringBuilder sb = new StringBuilder();

// 增操作:append和insert

//尾部追加数据append

sb.append("abc").append(123).append(3.14).append(true);

System.out.println(sb); //缓冲区对象内部数据为 ==> "abc1233.14true"

//带参构造

StringBuilder sb2 = new StringBuilder("helloworld");

System.out.println(sb2);//打印结果 helloworld

//在中间某位置插入数据 insert

sb2.insert(5, "java");

System.out.println(sb2); //打印结果 hellojavaworld

②删除

StringBuilder sb = new StringBuilder("helloabc0world");

// 删操作:delete deleteCharAt

//删除中间的"abc"数据

sb.delete(5, 8);

System.out.println(sb);//打印结果 hello0world

//删除中间的'0'数据

sb.deleteCharAt(5);

System.out.println(sb);//打印结果 helloworld

③修改

/*

改操作:reverse

setCharAt

setLength */

String content = "上海自来水来自海上1";

//类型转换:String -> StringBuilder

StringBuilder sb = new StringBuilder(content);

//将sb中的字符串内容进行反转

sb.reverse();

//-------------------------------分割--------------------------------

StringBuilder sb2 = new StringBuilder("helloworldjavascript");

//将sb2对象的容量设置为10个长度==》setLength方法

sb2.setLength(10);

System.out.println(sb2); //打印结果 "helloworld"

//将字符串内容w 改为W==》setCharAt方法

sb2.setCharAt(5, 'W');

System.out.println(sb2);//打印结果 helloWorld

🎎 相关推荐

给教练200红包少吗?给教练发红包多少合适
🎯 365bat提现

给教练200红包少吗?给教练发红包多少合适

📅 06-27 👀 7429
辽国灭亡后,蒙古为什么能迅速崛起?金国到底哪方面做得不如辽?
梅西参加了多少次世界杯?解读梅西世界杯传奇!