引用类型String
-
Java提供了String、StringBuffer、StringBuilder类来创建和操作字符串。Java中字符串被当作是对象来处理,是引用类型数据
-
String类的内部:
-
String是一个被final修饰的类
-
String对象的字符串内容存储在被private和final修饰后的字符数组中、即value[]。
-
private意味着外面无法直接获取字符数组,而且String没有提供value的get和set方法。
-
final意味着字符数组的引用不可改变,即不可通过让value指向新的数组对象来实现修改
-
String 对象;而且String也没有提供方法来修改value数组某个元素值,因此字符串的字符数组内容也不可改变
-
所以,字符串的拼接、字符串的截取、字符串的替换等操作每次都需要创建一个新的char数组表示修改后的结果
-
字符串是不可被更改的对象,如果更改字符串的值,意味着创建一个新的字符串。
字符串内存分析
字面量
- 字符串的每个字面量都是一个String对象,例:String str1=“diajw”
新建对象
- 使用new创建字符串对象。例:String str1=new String(“diajw”);
字符串存储分析
-
字面量保存在常量池中
-
在编译代码时,编译程序会将所有字面量都保存在方法区中的常量池里。因此,相同字面量的所有对象,实际上就是存储于常量池中的同一个对象。例:
String str1="fmYweifi";
String str2="fmYweifi";
System.out.println(str1==str2);
//true s1和s2指向了常量池中的同一个对象,所以他们引用的是同一个地址,即s1和s2都指向了"fmYweifi"
String str3=new String("fmYweifi");
System.out.println(str1==str3);
//false 一个是指向的是常量池中的地址str1,另一个是指向堆中的地址str3,他们的引用地址不同,所以返回值是false
- 存储分析图:
- 总结:字符串常量存储在字符串常量池。常量池中的相同的字符串可共享
字符串常量存储在堆中
字符串的拼接:
//字符串的拼接
String str4="Pro";
String str5="cessOn";
String str6="Pro"+"cessOn";
System.out.println(str6);
String str7=str4+"cessOn";
System.out.println(str7);
String str8=str4+str5;
System.out.println(str8);
String str9=(str4+str5).intern();
System.out.println(str9);
- 字符串在内存中的分析:
-
总结:常量与常量的拼接结果在常量池
-
拼接的两者中只要其中一个是变量,结果就在堆中
-
拼接的结果调用intern()方法,就在常量池中
-
intern函数用来返回常量池中的某个字符串。如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用,否则,在常量池中加入该对象,然后返回引用
比较字符串对象
String str1="fmYweifi";
String str2="fmYweifi";
System.out.println(str1==str2);
//true s1和s2指向了常量池中的同一个对象,所以他们引用的是同一个地址,即s1和s2都指向了"fmYweifi"
String str3=new String("fmYweifi");
System.out.println(str1==str3);
//false 一个是指向的是常量池中的地址str1,另一个是指向堆中的地址str3,他们的引用地址不同,所以返回值是false
常用方法
创建字符串
- 第一种方法:通过byte字节数组的方式来创建字符串,再通过String对象来接收该byte的字节数组,这样字节码会转换为字节码(例:97=a,98=b),然后通过String类方法String(arr,offset:起始下标,length:取的长度)取出该字符串:如下代码
byte[] buf={97,98,99};
String str=new String(buf);
str=new String(buf,0,3);
System.out.println(str);
-
第二种方法:使用字符数组构建字符串,通过char字符数组把它传给字符串对象,然后通过方法String(arr,offset:起始下标,取的字符个数);:如下代码
char[] arr={'这','里','有','一','个','问','题'}; str=new String(arr); str=new String(arr,3,2); System.out.println(str);
-
第三种方法:使用int类型的数组创建字符串,把int数组传给字符串对象,然后通过方法String(arr,offset:数组起始下标,count:取的个数):如下代码:
int[] arr1={95,96,97,98,99};
String str1;
str1=new String(arr1,2,3);
System.out.println(str1);
- 第四中方法:利用字符串创建字符串
String string=new String("abcdeg");
System.out.println("该字符串的输出为:"+string);
length
- 获取字符串的长度
例:
String s="naffnjas";
System.out.println(s.length());
字符串转换为字节数组或者字符数组
- 第一种方法:把字符串转换为字符数组,用.toCharArray()方法把字符串转换为字符数组,然后用Arrays.toString(数组变量名)输出
String str="Happiness";
char[] chars=str.toCharArray();
System.out.println("字符数组:"+ Arrays.toString(chars));
-
第二种方法:把字符串转换为字节数组,用.getBytes()方法把字符串转换为字节数组,然后用Arrays.toString(数组变量名)输出
String str1="Happiness"; byte[] b=str1.getBytes(); System.out.println("字节数组:"+Arrays.toString(b));
大小写转换
-
用字符串对象调用方法.toUpperCase()时转换为大写
String str2="Happiness"; System.out.println("转换为大写:"+str2.toUpperCase());
-
用字符串对象调用方法.toLowerCase()时转换为小写
String str2="Happiness";
System.out.println("转换为小写:"+str2.toLowerCase());
+
-
实现字符串的连接。
-
字符串和任意类型之间使用“+”,所有基本类型都转换为字符串,所有引用类型都会调用toString,最后再执行字符串连接。
例:代码:
int age=15; String s="He is "+age+" years old"; String s1="He is ".concat(String.valueOf(age)).concat(" years old"); String s3="He is ".concat(""+age).concat(" years old"); System.out.println(s); System.out.println(s1); System.out.println(s3);
由上述可知,将其它类型转换为字符串有两种方法:
-
第一种:String.valueOf(变量名)
-
第二种:“”+变量名
去掉字符两端的空格
trim
例:
String s=" abc ";
System.out.println(s.trim());
String s2=s.trim();
System.out.println(s2.length());
判断相关方法
- 该类方法返回值均为boolean类型
方法声明 | 方法作用 |
---|---|
public boolean equals(Object obj) | 比较字符串内容是否相同,区分大小写 |
public boolean equalsIgnoreCase(String str) | 比较字符串内容是否相同,忽略大小写 |
public boolean contains(String str) | 判断字符串是否包含另一个字符串 |
public boolean startsWith(String str) | 判断字符串是否以指定字符串开头 |
public boolean endsWith(String str) | 判断字符传是否以制定字符结尾 |
public boolean isEmpty() | 判断字符串是否为空 |
例:
String str="Demo.java";
System.out.println("判断字符串是否为空内容:"+str.isEmpty());
System.out.println("是否以指定的字符串开始:"+str.startsWith("De"));
System.out.println("是否以指定的字符串结束:"+str.endsWith("ja"));
System.out.println("判断字符串是否包含指定的内容:"+str.contains("Demo"));
System.out.println("判断两个字符串的内容是否一致:"+"DEMO.JAVA".equals(str));
System.out.println("判断两个字符串的内容是否一致(忽略大小写):"+"DEMO.JAVA".equalsIgnoreCase(str));
定位
- 字符串中的索引值是从0开始的
方法声明 | 方法作用 |
---|---|
public char charAt(int index) | 获取指定索引值的字符 |
public int indexOf(int ch) | 返回此字符在字符串中第一次出现的索引值,如果都不匹配则返回-1 |
public int indexOf(String str) | 返回指定字符串在字符串中第一次出现的索引值,如果都不匹配则返回-1 |
public int lastIndexOf(int str) | 返回制定字符在字符串中最后一次出现的索引值,如果都不匹配则返回-1 |
public int lastIndexOf(String str) | 返回制定字符串在字符串中最后一次出现的索引值,如果都不匹配则返回-1 |
例:
String str="abc中国ab中国";
System.out.println("字符串的字符个数:"+str.length());
System.out.println("根据索引值获取对应的字符:"+str.charAt(3));
System.out.println("查找子串中第一次出现的索引值:"+str.indexOf("中国"));
System.out.println("查找子串最后一次出现的索引值:"+str.lastIndexOf("中国"));
替换
方法声明 | 方法作用 |
---|---|
public String replace(char old,char new) | 替换指定的字符 |
例:
String str1="后天要下雨";
System.out.println("指定新内容替换旧的内容:"+str1.replace("下雨","天晴"));
子串
方法声明 | 方法作用 |
---|---|
public String subString(int start) | 指定位置开始截取字符串,直到结尾。[start,length] |
public String subString(int start,int end) | 截取指定范围内的字符串。[start,end] |
String str="信息技术有限公司";
System.out.println("指定开始的索引值截取子串:"+str.substring(2));//从2的
System.out.println("指定开始的索引值截取子串:"+str.substring(2,6));//从2到6截取到子串
比较
方法声明 | 方法作用 |
---|---|
public int compareTo(String str) | 按字典顺序进行比较,区分大小写 |
public int compareToIgnore(String str) | 按字典顺序进行比较,忽略大小写 |
拆分
方法声明 | 方法作用 |
---|---|
String[] split(String regex) | 分割字符串为一个字符串数组。通常使用逗号 |
String str="张三-李四-王五";
String[] arr=str.split("-");
System.out.println("字符串数组的内容:"+Arrays.toString(arr));
将其它数据转换为字符串
修饰 | 方法声明 | 返回值类型 |
---|---|---|
static String | valueOf(boolean b) | 返回boolean参数字符串表示形式 |
static String | valueOf(char c) | 返回char参数的字符串表示形式 |
static String | valueOf(char[] data) | 返回char数组参数的字符串表示形式 |
static String | value(char[] data,int offfset,int count) | 返回char数组参数的特定子数组的字符串表示形式 |
static String | valueOf(double d) | 返回double参数的字符串表示形式 |
static String | valueOf(float f) | 返回float参数的字符串表示形式 |
static String | valueOf(int i) | 返回int参数的字符串表示形式 |
static String | valueOf(long l) | 返回long参数的字符串表示形式 |
static String | valueOf(Object obj) | 返回Object 参数的字符串表示形式 |
StringBuffer
-
为啥需要StringBuffer
-
因为String内容是不可以被修改的,在频繁操作字符串的应用中,导致String对象泛滥,不断的被创建和销毁,占用大量的内存和cpu空间。
例:
String result="";
for (int i = 0; i < 100; i++) {
result +="A";
}
-
这创建了100个对象,其中有99个对象是临时对象,是计算的中间结果。JVM需要花费大量的内存来存放,也需要花费大量cpu时间来收回对象。
-
因此,通常要使用可变字符串缓冲区类(StringBuffer)来完成类似的工作:
StringBuffer buffer=new StringBuffer(100*1024);
for(int i=0;i<1000;i++){
buffer.append("A");
}
String result=buffer.toString();
System.out.println(result);
}
- 这样,只需要创建一个StringBuffer和一个String对象就完成了
缓冲原理
-
StringBuffer对象内部有一个缓冲区,默认缓冲区的容量是16字节。
-
通过StringBuffer的append方法向缓冲区中不断追加数据,当数据的大小超过缓冲区的大小时,系统会重新创建一个原来缓冲区的一倍大的新缓冲区,并将原来的缓冲中的数据拷贝到新的缓冲区中,这种操作非常耗资源。因此,需要预估数据所占空大小,在创建缓冲区时就预分配最大值,防止重新创建新缓冲区,提高系统性能
例:将三个字符串连接起来组成一个字符串:
StringBuffer buffer;
String str2="Hello";
String str3="World";
String str4="Beijing";
- 第一种方法:
String str5=str2+str3;
String str6=str5+str4;
//这种方法是有临时对象str5
- 第二种方法:使用StringBuffer:
StringBuffer sb=new StringBuffer(1024);//设置初始缓冲区大小
sb.append(str2).append(str3).append(str4);
String str7= sb.toString();//获得结果字符串
- 只需要创建一个StringBuffer对象,不需要再额外创建对象,最后直接返回缓冲区中的值为一个字符串,这种方法的优点在于,它只需要一次性分配缓冲区,之后就不会再需要创建额外的临时对象,整个性能会非常高
常用方式
- 先使用StringBuffer创建一个字符串缓冲类,然后使用append增加数据。
StringBuffer sb=new StringBuffer(5*1024);//建立一个长度为5*1024的缓冲区
sb.append("java");
sb.append("java");
sb.append("java");
sb.append("java");
sb.append("java");
System.out.println(sb);//sb.toString()获取字符串
方法
方法声明 | 方法作用 |
---|---|
StringBuffer deleteCharAt(int index) | 删除指定位置的字符,并返回本身 |
StringBuffer delet(int start,int end) | 删除从指定位置开始指定位置结束的内容 ,并且返回本身 |
StringBuffer replace(int start,int end,String str) | 从start到end用str替换 |
StringBuffer reverse() | 字符串反转 |
String substring(int start) | 从指定位置截取到末尾 |
String substring(int start,int end) | 截取start到end的字符串,包括开始位置,不包括结尾处 |
添加
方法声明 | 方法作用 |
---|---|
StringBuffer() | 空构造 |
StringBuffer(int capacity) | 指定容量的字符串缓冲对象 |
StringBuffer(String str) | 指定字符串的内容的字符串缓冲对象 |
StringBuffer append(xxx) | 在缓冲区的尾部添加新的文本对象。它支持任意类型的参数,都自动被转换为字符串 |
StringBufffer insert(int offet,xxx) | 在指定的索引位置添加新的文本对象 |
StringBuffer sb=new StringBuffer("jack");
sb.append(true);
sb.append('a');
sb.append(97).append(34.0).append(new char[]{'o','o'});//链式编程
System.out.println(sb.toString());//输出缓冲区中的文本
sb=new StringBuffer("jack");
sb.insert(2,"java");//jajavack
System.out.println(sb.toString());
查看
方法声明 | 方法作用 |
---|---|
int capacity() | 返回当前容量 |
int length() | 返回长度(字符数) |
indexOf(String str) | 返回第一次出现的指定字符串在字符串中的索引 |
String substring(int start) | 从指定位置截取到末尾 |
String substring(int start,int end) | 截取start到end的字符串,包括开始位置,不包括结尾处 |
toString() | 返回StringBuffer中的字符串 |
例:
StringBuffer sb=new StringBuffer("jackc");
System.out.println(sb.indexOf("c"));
System.out.println(sb.length());
修改
方法声明 | 方法作用 |
---|---|
StringBuffer replace(int start , int end,String str) | 使用指定字符串替换字串。[start,end] |
setCharAt(int index,char ch) | 替换指定位置中的字符 |
例;
StringBuffer sb=new StringBuffer("hellow");
System.out.println(sb.replace(4,7,"java"));
sb.setCharAt(8,'Q');
System.out.println(sb);
删除
方法声明 | 方法作用 |
---|---|
StringBuffer deleteChartAt(int index) | 删除指定位置的字符,并返回本身 |
StringBuffer delete(int start,int end) | 删除从指定位置开始指定位置结束的内容,并返回本身 |
例:
StringBuffer sb=new StringBuffer("helloWorld");
System.out.println(sb.delete(2,5));//heworld
System.out.println(sb.deleteCharAt(2));//heorld
反序
方法声明 | 方法作用 |
---|---|
StringBuffer reverse() | 字符串反转 |
例:
String str="hellworld";
StringBuffer sb=new StringBuffer(str);
System.out.println(sb.reverse());
String、StringBuffer、StringBuilder的区别
区别 | 是否可变 | |
---|---|---|
String | String的值是不可变的,每次对String的操作都会生成新的String对象,浪费空间 | 不可变 |
StringBuffer | StringBuffer是可变的,任何对它指向的字符串都不会产生新的对象。 | 可变 |
StringBuilder | 可变 | 可变 |
uffer(str);
System.out.println(sb.reverse());
String、StringBuffer、StringBuilder的区别
| | 区别 | 是否可变 |
| ------------- | ------------------------------------------------------------ | -------- |
| String | String的值是不可变的,每次对String的操作都会生成新的String对象,浪费空间 | 不可变 |
| StringBuffer | StringBuffer是可变的,任何对它指向的字符串都不会产生新的对象。 | 可变 |
| StringBuilder | 可变 | 可变 |