一、String
string类是四大引用数据类型之一
API当中说:“Java程序中的所有字符串字面值(如"abc")都作为此类的实例实现。” 就是说:程序内所有的双引号字符串,都是String类的对象。(就算没有new,也照样是。)
- String类:代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
- String是一个final类,代表不可变的字符序列。
- 当字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值
- 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值
- 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
- String对象的字符内容是存储在一个char型数组value[]中的。
- 因为字符串不可改变,所有字符串是可以共享使用的。
- 字符串效果上相当于是char[]字符串数组,但是底层原理是byte字节数组
- String实现了Serializable接口:表示字符串是可序列化的
- 实现了Comparable接口:表示String可以比较大小
1.1 创建字符串的常见3+1种方式:
三种构造方法:
- public String();创建一个空白字符串,不含有任何内容。
- public String(char[] array);根据字符数组的内容,来创建对应的字符串。
- public String(byte[] array);根据字节数组的内容,来创建对应的字符串。
一种直接创建:
- String str = “Hello”;
//使用空参构造
String str1 = new String();//小括号留空,说明字符串什么内容都没有。
System.out.println("第一个字符串:" + str);//""
//根据字符数组创建字符串
char[] = charArray = {'A','B','C'};
String str2 = new String(charArray);
System.out.println("第二个字符串:" + str2);//ABC
//根据字符数组创建字符串
byte[] byteArray = {97,98,99};
String str3 = new String(byteArray);
System.out.println("第三个字符串:" + str3);//abc
//直接创建
String = str4 = "Hello";
System.out.println("第四个字符串:" + str4);//Hello
1.2字符串常量池
- 程序当中直接写上的双引号字符串,就在字符串常量池当中。new的不在池当中,是数据再堆空间中开辟空间以后对应的地址值
- 对于基本类型来说,==是进行数值的比较
- 但是对于引用类型来说,==是进行地址值的比较。(Java如果是""创建则比较值)
1.3 String的比较方法
==是进行对象的地址值比较,如果确定需要字符串的内容比较,可以使用俩个方法:
- public boolean equals(Object obj):参数可以是任何对象,只有参数是一个并且内容相同才会给true,否则返回false
- 注意事项:
- equals具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
- 如果比较双方一个常量一个变量,推荐把常量字符串写在前面。推荐:“abc”.equals(str) 不推荐str.equals(“abc”);因为如果在调用方法是变量是个null,那么就会空指针报错NullPointException
- 注意事项:
- public boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较。
// == 比较
String s1 = "Java";
String s2 = "Java";
String s3 = new String("java");
String s4 = new String("java");
System.out.println(s1 == s2);//false
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
//equals比较
String strA = "Hello";
String strB = "Hello";
char[] charArray = {'H','e','l','l','o'};
String strC = new String(charArray);
System.out.println(strA.equals(strB));//true
System.out.println(strA.equals(strC));//true
System.out.println(strA.equals("Hello"));//true
System.out.println("Hello".equals(strA));//true
1.4 字符串的拼接
public class StringDeam {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "World";
String s3 = "HelloWorld";
String s4 = "Hello" + "World";
String s5 = s1 + "World";
String s6 = "Hello" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4); // true
System.out.println(s3 == s5); // false
System.out.println(s3 == s6); // false
System.out.println(s5 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s5 == s7); // false
System.out.println(s5 == s7); // false
String s8 = s5.intern();
System.out.println(s3 == s8); // true
}
}
- 只要再拼接的时候是变量名参与拼接,相当于new,此时已经不再常量池而是再堆空间
- 常量与常量的拼接结果再常量池中,因常量池中不会存在相同的变量,所以会指向同一个地方。
- 如果拼接的结果调用intern()方法,返回值就在常量池中
1.5 常用方法
1.5.1 String当中与获取相关的常用方法有
- public int length():获取字符串当中含有字符个数,拿到字符串长度。
- public String concat(String str):讲当前字符串和参数字符串拼接成为返回值新的字符串。
- public char charAt(int index):获取指定索引位置的单个字符。
- public int indexof(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。
- int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
- int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
- int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
- 注:indexOf和lastIndexOf方法如果未找到都是返回-1
1.5.2 String当中的截取方法
- public String substring(int index):从参数的位置一直到字符串末尾,返回新字符串。
- public String substring(int begin,int end):截取从begin开始,一直到end结束,中间的字符串。[begin,end
1.5.3 String当中与转换和替换相关的常用方法有
- public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值
- public byte[] getBytes();获取当前字符串底层的字节数组。
- String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
- public String replace(CharSequence oldString,CharSequence newString):讲所有出现的老字符串替换成新的字符串。
备注:charSequence意思就是说可以接受字符串类型 - String replaceAll(String regex, String replacement): 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
- String replaceFirst(String regex, String replacement): 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
- boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
1.5.4 String字符串的分割方法
- public String split(String regex):按照参数的规则,将字符串切分成若干部分;
regex是一个正则表达式。
如果是英文句点得写". 、
1.5.5 其余常用方法
- public String trim():返回字符串的副本,忽略前面和尾部的空格
- public boolean startsWith(String suffix):判断用于判断当前字符串对象的前缀是否位参数指定的字符串
- public boolean endsWith(String suffix):判断用于判断当前字符串对象的后缀是否位参数指定的字符串
- boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
- public String toLowerCase():把所有字符从大写字母改为小写字母
- public String toUpperCase():把所有字符从小写字母改为大写字母
- int compareTo(String anotherString):比较俩个字符串的的大小 负数代表减去的小,0表示相等
- boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
public class StringDemo{
public static void main(Stringp[] args){
//获取字符串长度
int length = "asdasfgasdqwaedasfawfqawdasqfaw".length();
System.out.println("字符串的长度是:" + length);
//拼接字符串
String str10 = "Hello";
String str20 = "World";
String str30 = str10.concat(str2);
String str40 = str10 + str20
System.out.println(str10);//Hello,原封不动
System.out.println(str20);//World,原封不动
System.out.println(str30);//HelloWorld,新的字符串
System.out.println(str40);//HelloWorld,新的字符串
//获取指定索引位置的单个字符
char ch = “Hello”.charAt(1);
System.out.println("ch");//e
//查找参数字符串在本来字符串当中出现的第一次索引位置
//如果根本没有,返回-1值
String original = "HelloWorld";
int index = original.indexOf("llo");//2
System.out.println(index);
System.out.println("HelloWorld".indexOf("abc"));//-1
//截取字符串
String strA1 = "HelloWorld";
String strA2 = str1.substring(5);
System.out.println(strA1);//HelloWorld
System.out.println(strA2);//World,新字符串
String strA3 = strA1.substring(4,7);
System.out.println(strA3); //oWo
//转char数组
char[] chars = "Hello".toCharArray();
System.out.println(Chars[0])//H
System.out.println(Chars.length)// 5
//转byte数组
byte[] bytes = "abc".getBytes();
for(int i=0;i<bytes.length;i++){
System.out.println(bytes[i]);
}
//替换字符
String l = "How do you do?";
String l1 = l.replace("o","*");
System.out.println(l1);//H*w d* y*u d*?
//分割字符串
String a1 = "aaa,bbb,ccc";
String[] array1 = a1.split(",");
for(int i=0;i<array1.length;i++){
System.out.println(array1[i]) ;
}
//去空格
String aa1 = " 11 "
String aa1 = aa1.trim();
System.out.println(aa1); //11
// 判断字符串的开始和结尾
String num1 = "1110044";
String num2 = "123124124521";
boolean b = num1.startsWith("11");// 判断字符串num1,是否以"11"开头
boolean b2 = num2.startsWith("22");// 判断字符串num2,是否以"22"结尾
// 转大小写
String as= "aaa";
String at= "BBB";
System.out.println(aaa.toUpperCase()) ; //AAA
System.out.println(aaa.toLowerCase()) ; //bbb
String s1 ="abc";
String s2 = new String("abe");
System.out.println(s1.compareTo(s2)) ; //-2
String src = "helloworld";
String s3 = "hol";
System.out.println(src.contains(s3)) ; //-2
}
}
1.6 String与基本数据类型转换
1.6.1 字符串转换基本数据类型、包装类
- Integer包装类的public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。
- 类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
1.6.2 基本数据类型、包装类转换字符串
- 调用String类的public String **valueOf(int n)**可将int型转换为字符串
- 相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可由参数的相应类型到字符串的转换
- 也可以用字符串拼接 + “” 即可转化为字符串
1.6.2 字符串转字符数组
- public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。
- public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
1.6.3 字符串转字节数组
- public byte[] getBytes() **:**使用平台的默认字符集将此 String 编码为byte 序列,并将结果存储到一个新的 byte 数组中。
- public byte[] getBytes(String charsetName) **:**使用指定的字符集将 此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
二、StringBuilder和StringBuffer
方法都一致,俩者的主要区别在于StringBuilder是线程安全的,StringBuffer是线程不安全的
概述
- Java.lang.StringBuilder
- 在调用空参构造的时候底层会创建一个长度为16的char型数组,如果是传入字符串则在字符串的长度上加上16的char型数组。(注:length()返回的长度是实际数据的长度)
- 如果长度超过了char型数组的长度,会创建一个新数组长度为原数组的二倍在加二。如果还不够则拿新的长度替换(长度加上传入字符串的长度),直到长度足够。再把数据复制进去
- StringBuilder是一个可变的字符串类,可以看做是字符串缓冲区,可以提高字符串的操作效率(看成一个长度可以变换的字符串),底层也是一个数组,但是没有被final修饰,可以改变长度
- StringBuilder在内存中始终是一个数组,占用空间少,效率高,如果超出了StringBuilder的容量,会自动扩容。
- 建议在使用的时候直接指定长度,避免扩容
与String的性能对比
public class testStringBuilder {
public static void main(String[] args) {
testString();
testStringBuilder();
}
public static void testString(){
String s = "";
long start = System.currentTimeMillis(); // 获取1970年1月1日0时0分0秒 到当前时间经历过的的毫秒值
for (int i=1;i<=50000;i++){
s +=i;
}
long end = System.currentTimeMillis();
System.out.println("String=>" + " " + (end-start));
}
public static void testStringBuilder(){
StringBuilder stringBuilder = new StringBuilder();
long start = System.currentTimeMillis(); // 获取1970年1月1日0时0分0秒 到当前时间经历过的的毫秒值
for (int i=1;i<=50000;i++){
stringBuilder.append(i);
}
long end = System.currentTimeMillis();
System.out.println("StringBuilder=>" + " " + (end-start));
}
}
打印结果:
String=> 3780
StringBuilder=> 2
注:
- +号运算符 对字符串拼接时候会产生垃圾字符串 导致内存变大,再Java底层中会new StringBuilder调用append()完成字符串拼接,再调用toString()方法返回字符串,一个加号,堆内存中俩个对象。
构造方法
- StringBuilder():构造一个不带任何字符的字符串生成器,其初始容量为16个字符。
- StringBuilder(int len):构造一个不带任何字符的字符串生成器,指定其长度
- StringBuilder(String str):构造一个字符串生成器,并初始化为指定的字符串内容
public class CreateStringBuilder {
public static void main(String[] args) {
// StringBuilder():构造一个不带任何字符的字符串生成器,其初始容量为16个字符。
StringBuilder stringBuilder = new StringBuilder();
System.out.println(stringBuilder);
// StringBuilder(String str):构造一个字符串生成器,并初始化为指定的字符串内容
StringBuilder stringBuilder1 = new StringBuilder("abc");
System.out.println(stringBuilder1);
}
}
常用方法
- public StringBuilder append(…):添加任意类型数据的字符串形式,并返回当前对象自身;
注:
append方法返回的是this。
append的方法无序返回值。 - public String toString():将当前StringBuilder对象转换为String对象
注:
String和StringBuilder可以互相转换:
String->StringBuilder:可以使用StringBuilder的构造方法
StringBuilder->String:可以使用StringBuilder中的toString方法 - public StringBuilder reverse() 返回相反的字符序列
- public int length() 返回长度(字符出现的个数)
- StringBuffer delete(int start,int end):删除指定位置的内容
- StringBuffer insert(int offset, xxx):在指定位置插入xxx
- StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
- public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。
- public String substring(int start,int end):获取指定位置的字符串
- public int length():获取长度
- public char charAt(int n):获取指定位置的字符
- public void setCharAt(int n ,char ch):设置指定位置的字符
public class StringBuilderMethod {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
// public StringBuilder append(...):添加任意类型数据的字符串形式,并返回当前对象自身;
stringBuilder.append(123);
stringBuilder.append("abc");
stringBuilder.append(true);
StringBuilder stringBuilder1 = stringBuilder.append('s');
StringBuilder stringBuilder2 = stringBuilder.append(12314.123);
System.out.println(stringBuilder);
System.out.println(stringBuilder1 == stringBuilder2); // 返回当前对象自身
// 链式编程:如果一个方法返回得是一个对象,对象就可以继续向下调用方法
stringBuilder2.append("连").append("式").append("编").append("程");
System.out.println(stringBuilder);
// result=> 123abctrues12314.123
// result=> true
// 123abctrues12314.123连式编程
// public StringBuilder reverse() 返回相反的字符序列
stringBuilder.reverse();
System.out.println(stringBuilder);
// 程编式连321.41321seurtcba321
//public int length() 返回长度(字符出现的个数)
System.out.println(stringBuilder.length());
// public String toString():将当前StringBuilder对象转换为String对象
System.out.println(stringBuilder.toString());
}
}
面试题
- 面试题:
String s = new String("abc");
这种方式再内存中创建了几个对象- 俩个:一个是堆空间的new结构,另一个是char[]对应的常量池中的数据:“abc”
- String、StringBuffer、StringBuilder三者有什么异同点?
- String:不可变的字符序列;底层使用char型数组进行存储
- StringBuffer:可变的字符序列,是线程安全的,但是效率低;底层使用char型数组进行存储
- StringBuilder:可变的字符序列,是线程不安全的,效率高;底层使用char型数组进行存储