public class TestDemo1 {public static void main(String[] args) {String s1 = "Hello";String s2 = new String("Hello");char[] array = {'H','e','l','l','o'};String s3 = new String(array);System.out.println(s1);System.out.println(s2);System.out.println(s3);}
}
对于第三种方法,传入的是字符数组,转变成字符串,对应源码:
public String(char value[]) {this.value = Arrays.copyOf(value, value.length);}

那么上述s1和s2是如何存储的呢?

public static void main(String[] args) {String s1 = "Hello";System.out.println(s1.length());System.out.println("Hello".length());String s2 = "";System.out.println(s2.isEmpty());String s3 = null;System.out.println(s3.isEmpty());}
运行结果:

分析:①字符串长度的比较调用的是length()方法,而获取数组的长度是 int[] array = {1,2,3}; System.out.println(array.length);,一个有小括号,一个没有小括号,并且在Java中没有所谓的’\0’。

②在Java中双引号“”引起来的也是String类型对象,也是字符串对象,因此可以直接使用"Hello".length(),可以看到点号.前面是个常量,因此不一定非得是变量调用字符串方法。
③s2字符串的长度为0,因此调用isEmpty()得到的返回值为true
④s3赋值为null,表示不指向任何对象,因此会抛出空指针异常
注意:长度为0和指向null,这两种空是不一样的。
public static void main(String[] args) {String s1 = "abc";String s2 = "abc";String s3 = s1;String s4 = new String("abc");System.out.println(s1 == s2);System.out.println(s1 == s3);System.out.println(s1 == s4);}
运行结果:

分析:双引号引起来的值就存在字符串常量池当中,如果常量池中有abc就再重新存一份,直接返回字符串常量池中的对象即可。

对于基本类型变量,= =比较两个变量中存储的值是否相同;对于引用类型变量, = =比较两个引用变量引用的是否为同一个对象。
②boolean equals(Object anObject)方法比较对象内容是否相同:按字符比较
String类重写了父类Object中equals方法,Object中的quals默认按照==比较,String重写equals方法后,则可以比较不同对象的内容是否相同,如果相同也可以返回true。
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("abc");System.out.println(s1 == s2);System.out.println(s1.equals(s2));}
String类重写equals代码:
public boolean equals(Object anObject) {
//1、先检测this和anObject是否为同一个对象比较,如果是返回trueif (this == anObject) {return true;}
//2、检测anObject是否为String类型的对象,如果是继续比较,否则返回falseif (anObject instanceof String) {//将anObject向下转型为String类型对象String anotherString = (String)anObject;int n = value.length;//3、this和anObject两个字符串的长度是否相同,如果是则继续比较,否则返回falseif (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;//4、从前往后逐个字符进行比较while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}
运行结果:

如果要忽略大小写进行比较,使用equalsIgnoreCase()方法:
public static void main(String[] args) {String s1 = new String("abc");String s2 = new String("Abc");System.out.println(s1.equalsIgnoreCase(s2));}
运行结果:

③int compareTo(String s)方法比较字符串对象内容的大小:按照字典序进行比较
注意:equals返回的是boolean类型,而compareTo返回的是int类型。
比较方法:先按照字典次序大小比较,如果出现不相等的字符,则返回两个字符的ASCII大小差值;如果两个字符串的前K个字符都相等(K是两个字符串长度中的最小值),那么返回两个字符串长度的差值。
public static void main(String[] args) {String s1 = new String("abcd");String s2 = new String("abcd");String s3 = new String("abc");System.out.println(s1.compareTo(s2));System.out.println(s1.compareTo(s3));}
运行结果:

s1和s2字符串内容相同,所以返回0,s1和s3前3个字符相同,s1比s3长度多1,所以返回1.
忽略大小写比较:s1.compareToIgnoreCase(s2)
public static void main(String[] args) {String s1 = new String("abcd");String s2 = new String("Abcd");System.out.println(s1.compareTo(s2));System.out.println(s1.compareToIgnoreCase(s2));}
运行结果:

public static void main(String[] args) {String s = "abcdf";System.out.println(s.charAt(2));}
运行结果:

分析:s.charAt(2)返回下标为2的那个字符
②int indexOf(int ch) 返回ch第一次出现的位置,没有ch则返回-1
public static void main(String[] args) {String s = "abcdf";System.out.println(s.indexOf('b'));System.out.println(s.indexOf('h'));}
运行结果:

分析:
字符b在字符串中的下标是1,而字符串中没有h字符,所有第二条输出语句打印-1。
③int indexOf(int ch, int fromIndex) 从fromIndex位置开始找ch第一次出现的位置,没有则返回-1
public static void main(String[] args) {String s = "abcdfasdfghsfdadbf";System.out.println(s.indexOf('b',6));}
运行结果:

分析:indexOf传入2个参数,则是从第6个位置开始找b字符
④int indexOf(String str) 【不仅可以找字符,还可以找字符串】返回str第一次出现的位置,没有返回-1
public static void main(String[] args) {String s = "abcdfasdfghsfdadbf";System.out.println(s.indexOf("dfg"));}
运行结果:

分析:在字符串s中第一次出现子串dfg的下标位置是7
⑤int indexOf(String str, int fromIndex) 从fromIndex位置开始找str第一次出现的位置,没有返回-1
public static void main(String[] args) {String s = "abcdfasdfghsfdadfgbf";System.out.println(s.indexOf("dfg",9));}
运行结果:

分析:从下标为9的位置开始找dfg
上述是从前往后找也可以从后往前找
⑥int lastIndexOf(int ch) 从后往前找,返回ch第一次出现的位置
public static void main(String[] args) {String s = "abcdfasdfghsfdadfgbf";System.out.println(s.lastIndexOf('b'));}
运行结果:

⑦int lastIndexOf(int ch, int fromIndex)从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
public static void main(String[] args) {String s = "abcdfasdfghsfdadfgbf";System.out.println(s.lastIndexOf('b',6));}
运行结果:

分析:从下标为6的位置开始,从后往前找
⑧int lastIndexOf(String str)从后往前找,返回str子串第一次出现的位置,没有返回-1
public static void main(String[] args) {String s = "abcdfasdfghsfdadfgbf";System.out.println(s.lastIndexOf("dad"));}
运行结果:

⑨int lastIndexOf(String str, int fromIndex)从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1
public static void main(String[] args) {String s = "abcdfasdfghsfdadfgbf";System.out.println(s.lastIndexOf("dad",10));}
运行结果:

class Student{}
public class TestDemo2 {public static void main(String[] args) {int a = 10;double b = 12.3;String s1 = String.valueOf(a);String s2 = String.valueOf(b);String s3 = String.valueOf(new Student());System.out.println(s1);System.out.println(s2);System.out.println(s3);}
}
运行结果:

②字符串转为基本数据类型数值——利用基本数据类型对应的包装类中的方法
public static void main(String[] args) {String s1 = "123";String s2 = "12.34";int a = Integer.parseInt(s1);double b = Double.parseDouble(s2);System.out.println(s1);System.out.println(s2);}
运行结果:

分析:parseInt和parseDouble两个方法都由static修饰,所以可以直接通过包装类名调用,而不用实例化对象。


public static void main(String[] args) {String s1 = "ABDFGSSDFsdfdgh";String s2 = s1.toLowerCase();String s3 = s1.toUpperCase();System.out.println(s1);System.out.println(s2);System.out.println(s3);}
}
运行结果:

分析:s1.toLowerCase()将字符串中的大写字母全部转换成小写字母,s1.toUpperCase()将字符串中的小写字母全部转换成大写字母,并且可以发现s1中字符串的内容是不变的(String类的不可变性)。
public static void main(String[] args) {char[] chars = {'a','b','c'};String s = new String(chars);System.out.println(s);}
②将字符串转换成数组,用到了String类中的toCharArray()方法
public static void main(String[] args) {String s = "hello";char[] chars = s.toCharArray();for (char i:chars) {System.out.println(i);}}
运行结果:

public static void main(String[] args) {String s = String.format("%d-%d-%d",2022,11,21);System.out.println(s);}
运行结果:


public static void main(String[] args) {String s = "abcdabd";String s1 = s.replace('a','x');String s2 = s.replace("abc","ooo");String s3 = s.replaceFirst("ab","00");String s4 = s.replaceAll("ab","00");System.out.println(s1);System.out.println(s2);System.out.println(s3);System.out.println(s4);}
运行结果:

注意:由于字符串是不可变对象,所以替换不修改当前字符串,而是产生一个新的字符串。
public static void main(String[] args) {String str = "Hello World Shuai Wang";String[] strings = str.split(" ");for (String x: strings) {System.out.println(x);}}
运行结果:

在上述例子中,可以给split方法再添加一个参数,指定拆分成几组。
public static void main(String[] args) {String str = "Hello World Shuai Wang";String[] strings = str.split(" ",2);for (String x: strings) {System.out.println(x);}}
运行结果:分成2组

例子:拆分IP地址,有些特殊字符作为分隔符可能无法正确拆分,需要加上转义。
public static void main(String[] args) {String str = "192.168.0.1";String[] strings = str.split("\\.");for (String x:strings) {System.out.println(x);}}
运行结果:

分析:此处以点号.进行分割,需要加2个反斜杠,第一个反斜杠表示:点号.需要转义;第二个反斜杠表示:刚刚那个反斜杠需要转义。(如果没有加反斜杠,则没有打印结果)
注意:
①字符“|”,“*”,“+”都需要加上转义字符,前面加上“\”【2个斜杠才能表示1个斜杠】
②如果是“\”,而需要写成“\\”【4个斜杠才能表示2个斜杠】
③如果一个字符串中有多个分隔符,可以用“|”作为连字符
例子:多次拆分
①用到连字符|
public static void main(String[] args) {String str = "name=zhangsan&age=21";String[] strings = str.split("=|&");for (String x:strings) {System.out.println(x);}}
②用到for循环多次拆分
public static void main(String[] args) {String str = "name=zhangsan&age=21";String[] strings = str.split("=");// name zhangsan&age 21for (int i = 0; i < strings.length; i++) {//对数组的每个元素再进行分割String[] ret = strings[i].split("&");//对数组每个元素分割之后进行打印for (String x: ret) {System.out.println(x);}}}
运行结果:

public static void main(String[] args) {String str = "abcdsasffsa";String s1 = str.substring(2);String s2 = str.substring(2,7);System.out.println(s1);System.out.println(s2);}
运行结果:

分析:
String substring(int beginIndex)表示从指定索引截取到结尾
String substring(int beginIndex, int endIndex)表示截取某个区间,截取部分内容,区间为左闭右开。
public static void main(String[] args) {String str = " Hello World ";String s1 = str.trim();System.out.println(str);System.out.println(s1);}
运行结果:


public static void main(String[] args) {final int[] array = {1,2,3,4};array = new int[6];array[0] = 6;}
代码中,array数组被final修饰,代表array引用所指向的对象地址不能改变,所以 array = new int[6];会报错,而其对象的内容可以修改,例如 array[0] = 6;可以编译运行成功。
即:final修饰类表示该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
public static void main(String[] args) {String str = "Hello";str += "World";System.out.println(str);}
观察其反汇编程序

可以发现其实际代码为:
public static void main(String[] args) {String str = "Hello";StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(str);stringBuilder.append("World");str = stringBuilder.toString();System.out.println(str);}
分析:这种字符串拼接的方式不推荐使用,因为其效率非常低,中间创建了很多临时对象。因此:尽量避免对String的直接修改,如果需要修改尽量使用StringBuffer和StringBuilder。
public static void main(String[] args) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("abc").append("hello");stringBuilder.append("World");stringBuilder.append(123);System.out.println(stringBuilder);}
append方法的源码:
public StringBuilder append(String str) {super.append(str);return this;}
可以看到return的是this,返回的就是当前对象,此时不会产生临时对象。
②常用方法——toString() 将所有的字符转换成String类型并返回
public static void main(String[] args) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("abc").append("hello");stringBuilder.append("World");stringBuilder.append(123);String str = stringBuilder.toString();System.out.println(str);}
toString的源码:
public String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count);}
分析:可以发现toString创建了一个新的String对象。
StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("abc").append("hello");stringBuilder.append("World");
②StringBulider变成String:通过调用StringBulider的toString()方法
StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("abc");String str = stringBuilder.toString();System.out.println(str);
String、StringBulider、StringBuffer的区别
①String的内容不可修改,StringBulider和StringBuffer的内容可以修改
②StringBulider和StringBuffer大部分的功能是相似的
③StringBuffer采用同步处理,属于线程安全操作;StringBuilder未采用同步处理,属于线程不安全操作

分析:synchronized(锁)用在多线程情况下,所以StringBuffer更安全。【但是频繁的加锁和释放锁都是需要耗费系统资源的】
以下总共创建了多少个String对象【不考虑常量池之前是否存在】
String str = new String("ab");String str = new String("a") + new String("b");
分析:第一条语句产生2个String对象,第二条语句产生5个String对象+1个StringBulider对象
①“ab”双引号引起来的是一个字符串对象,new String new了一个字符串对象,所以一个2个
②“a”和"b"2个双引号引起来,则产生了2个字符串对象,2个new则new了2个字符串对象,+字符串拼接会产生一个StringBulider对象,StringBulider对象最后调用toString方法会new一个String对象,所以会产生5个String对象,1个StringBulider对象,总共6个对象。
上一篇:用举组词,举要是全的意思
下一篇:抖音如何发布新的挑战