前言
字符串就是一连串的字符序列, Java 提供 String,StringBuffer,StringBuilder 3个类来封装字符串,并提供了一系列方法来操作字符串对象。
Java9改进了字符串(包括String. StringBuffer. StringBuilder) 的实现。在Java9以前字符串底层采用char[]数组来保存字符,因此字符串的每个字符占2字节;而Java 9的字符串采用byte[]数组再加一个encoding-flag(编码标识)字段来保存字符,因此字符串的每个字符只占1字节。所以Java9的字符串更加节省空间,但字符串的功能方法没有受到任何影响。.源码截图如下:
String,StringBuilder,StringBuffer区别
- String是不可变的
- StringBuilder,StringBuffer是可变的字符串
- StringBuilder是线程不安全的
- StringBuffer是线程安全的
String类
1.final修饰,不可以有子类。源码截图:
2.“hello” 直接量和 newString(“hello”) 有什么区别呢?
当 Java 程序直接使用形如"hello" 的字符串直接量( 包括可以在编译时就计算出来的字符串值)时,JVM 将会使用常量池来管理这些字符串;当使用 new String(“hello”) 时,JVM 会先使用常量池来管理"hello" 直接量 ,再调用String 类的构造器来创建一个新的 String 对象,新创建的 String 对象被保存在堆内存中。换句话说,new String(“hello”) 共产生了两个字符串对象。
3.字符串不可变
底层代码:final char[] value;
String 类是不可变的, String 的实例一旦生成就不会再改变了,例如如下代码。
//字符串不可变
String str5 = new String("hello");
str5 = str5.concat("!!!");//字符串连接
System.out.println(str5);//结果为 hello!!!
这里的不可变是指String对象不可变。区分对象和对象的引用:从上述的打印结果看,str5的值确实变了,那怎么还说String对象是不可变的呢?其实这存在一个误区:str5只是一个String对象的引用,并不是对象本身。对象在内存中是一块内存区,成员变量越多,这块内存占的空间就越大。引用只是存放了地址。
也就是说,str5只是一个引用,它指向一个具体的对象,当str5 = str5.concat("!!!");这句代码执行后,又创建了一个新的对象hello!!! ,而str5重新指向了这个对象,原来的对象“hello”还在内存中,并没有改变。内存结构如下图所示:
4.StringBuilder StringBuffer
char[] value;
5.方法:
构造方法
//构造方法
public static void test1(){
String str1 = new String();
byte[] b = {97,98,99};
//将每个数转成对应的字符,再连接成字符串
String str2 = new String(b);
System.out.println(str2); //abc
char[] c = {'a','b','c'};
//字符串底层使用的是char类型数组实现的字符串
//打印时,自动转成字符串
System.out.println(new String(c)); //abc
System.out.println(b); //[B@15db9742
System.out.println(c); //abc
}
常用方法
//返回字符串的长度
//数组使用的是属性,字符串使用的是length()方法
System.out.println("hello".length());
//去掉字符串的前后空格
//trim()方法可用于用户名,密码校验
System.out.println(" hel lo ".trim());
//int compareTo(String anotherString):比较两个字符串的大小。如果两个字符串的字符序列相等,则返回0;不相等时,从两个字符串第0个字符开始比较,返回第一一个不相等的字符差。另一种情况,较长字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。
String s1 = new String( "abcdefghijklmn");
String s2 = new String( "abcdefghij ");
String s3 = new String( "abcdefghijalmn ");
System .out .println( "sl. compareTo(s2) : " + sl.compareTo(s2) ) // 返回长度差
System .out .println( "sl. compareTo(s3): " + sl.compareTo(s3) ) // 返回'k'-'a'的差
//boolean equalsIgnoreCase(String str):比较字符序列,只是忽略字符的大小写
System.out.println("abc".equalsIgnoreCase("Abc"));
// char charAt(int index): 获取字符串中指定位置的字符。
System.out.println("hello".charAt(2));
//int indexOf(int ch): 找出 ch 字符在该字符串中第一次出现的位置
System.out.println("hello".indexOf('e'));
System.out.println("hello".indexOf("elle")); //-1
System.out.println("hello".indexOf("ello")); //1
System.out.println("hello".indexOf("l"));
// int indexOf(String str, int fromIndex): 找出str子字符串在该字符串中从 fromIndex 开始后第一次出现的位置
System.out.println("helelo".indexOf("l",3));
//int lastIndexOf(int ch): 找出 ch 字符在该字符串中最后一次出现的位置。
System.out.println("hello".lastIndexOf("l"));
//int lastIndexOf(String str, int fromIndex): 找找出 str 子字符串在该字符串中从 fromlndex 开始后最后一次出现的位置
System.out.println("he3llo".lastIndexOf("l",2));
//> String substring(int beginlndex): 获取从 beginlndex 位置开始到结束的子字符串。
System.out.println("hello123".substring(2));
//[2,4)
System.out.println("hello123".substring(2,4));
//判断前缀和后缀
System.out.println("1234566".startsWith("123"));
System.out.println("afbsdf".endsWith("X"));
//大小写字符
System.out.println("aBc".toUpperCase());
System.out.println("SDad".toLowerCase());
System.out.println("abcde".contains("cd"));
//valueOf:用于将基本类型值转换为 String 对象的方法
System.out.println(String.valueOf(123));
//char[] toCharArrayO: 将该 String 对象转换成 char 数组。
char[] c = "abc".toCharArray();
String str2 = new String(" ");
System.out.println(str2.isEmpty());
String类重写了equals,hashCode,toString,以下是String类的源码截图。
可见,重写的equals比较的是相同的字符序列
练习题:
//11.判断回文(回文,从中间开始两边对称)
String s3="上海自来水来自海上";
if(isHuiWen(s3)) {
System.out.println("是回文");
}else {
System.out.println("不是回文");
}
static boolean isHuiWen(String s) {
int j=s.length()-1;
for(int i=0;i<j;i++,j--)
{
if(s.charAt(i)!=s.charAt(j))
return false;
}
return true;
}
//12. 输入一个字符串,统计字符串中字母、数字和其他符号的个数
public static void test1(){
int a=0,b=0,d=0;
Scanner sc = new Scanner(System.in);
System.out.println("input:");
String str = sc.next();
for(int i = 0;i<str.length();i++){
char c = str.charAt(i);
if(c>='a'&&c<='z'||c>='A'&c<='Z'){
a++;
}else if(c>='0'&&c<='9'){
b++;
}else{
d++;
}
}
System.out.println("字符:"+a+",数字:"+b+",其他 :"+d);
}
//13. 输入一个字符串,将其中的数字提取出来并求和
//adfd1234dfdf56ae2==1,2,3,4,5,6,2
//'1'+'2'
//'1'49-'0' =1
//'2'50-'0'48=2
public static void test2(){
String str = "adfd1234dfdf56ae2";
int sum = 0;
for(int i = 0;i<str.length();i++){
char c = str.charAt(i);
if(c>='0'&c<='9'){
sum += c-'0';
}
}
System.out.println(sum);
}
//14. 输入一个字符串,将其中的数字提取出来并进行升序排序
//dsho353sdhiha89dnso4 -> 353894 -> 334589
public static void test3(){
String str = "dsho353sdhiha89dnso4";
int index = 0;//表示array数组的索引
char array[] = new char[str.length()];
for(int i = 0;i<str.length();i++){
char c = str.charAt(i);
if(c>='0'&&c<='9'){
array[index++] = c;
}
}
array = Arrays.copyOf(array, index);//数组缩容
Arrays.sort(array);//数组排序
System.out.println(Arrays.toString(array));
}
//15. 输入一个字符串,统计其中每一个字符出现的次数
// sdhaofnaadsg -> s:2 d:2 h:1 a:3 o:1 f:1 n:1 g:1
// a a b c d d
//boolean{true,true,false,true,true,true}
public static void test4(){
String str = "sdhaofnaadsg";
boolean[] b = new boolean[str.length()];
for(int i = 0;i<b.length;i++){
if(b[i]){
continue;//如果记过数的字符,不重复计数
}
char c = str.charAt(i);
int count = 0;
for(int j = i;j<str.length();j++){
if(str.charAt(j)==c){
b[j]=true;//标识元素已经记过数
count++;//字符的计数器
}
}
System.out.println(c+":"+count);
}
}
//16.输入2个字符串,打印第二个字符串在第一个字符串中出现的所有的位置
//vagaophgao a -> 1 3 8
//index = indexOf("",index)
//index++
public static void test5(){
String str1 = "vagaophgao";
String str2 = "a";
int index = 0;//索引
while(index<str1.length()){
index = str1.indexOf(str2,index);
if(index!=-1){
System.out.println(index);
index++;
}else{
break;
}
}
}
StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer 被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString0方法将其转换为一个String对象。
StringBuilder builder = new StringBuilder("hello");
String str = builder.insert(1, "a")
.append("123")
.delete(1, 3)
.reverse()
.toString();
StringBuilder类(可变字符串类):字符串内容改变频率高,建议使用此对象
//不同对象的代码执行效率
String str = "a";
long start = System.currentTimeMillis();
for(int i = 1;i<=10000;i++){
str+="b";
}
long end = System.currentTimeMillis();
System.out.println(end-start);
start = System.currentTimeMillis();
StringBuilder str2 = new StringBuilder("a");
for(int i = 1;i<=10000;i++){
str2.append("b");
}
end = System.currentTimeMillis();
System.out.println(end-start);
结果:
43
2