String类的重要属性
在C语言中已经涉及到字符串,但是在c语言中表示字符串只能使用字符数组或字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但这种将数据和操作数据分离开的方式不符合面向对象的思想,而字符串应用又非常广泛,因此Java专门提供了String类。
在开发和校招中,字符串也是常客,面试中也被频繁问到,比如String,StringBuffer,StringBuilder之间的区别等。
常用方法
字符串构造
String类常用的构造方式有以下三种:
public static void main(String[] args) { //使用常量串构造 String s1 = "hello word"; System.out.println(s1); //直接newString对象 String s2 = new String("hello china"); System.out.println(s2); //使用字符数组进行构造 char[] array = {'h','e','l','l','o'}; String s3 = new String(array); System.out.println(s3); }
注意:
1. String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类的实例变量如下:
//s1和s2引用的不是同一对象,s1和s3引用的是同一对象 String s1 = new String("hello"); String s2 = new String("world"); String s3 = s1; System.out.println(s1.length()); //获取字符串长度 System.out.println(s1.isEmpty()); //如果字符串长度为0返回true,否则返回false
2. 在Java中“ ”引起来的也是String类型对象
//打印“hello”字符串的长度 System.out.println("hello".length());
String对象的比较
1. == 比较是否引用同一个对象
注意:对于基本类型,==比较变量中的值,对于引用类型,==比较引用的地址
int a = 10; int b = 20; int c = 10; //基本类型比较变量的值 System.out.println(a==b); System.out.println(a==c); String s1 = new String("hello"); String s2 = new String("world"); String s3 = new String("hello"); String s4 = s1; //对于引用变量,比较的是引用的地址 System.out.println(s1==s2); //false System.out.println(s1==s3); //false System.out.println(s1==s4); //true
2. boolean equals(Object anObject)方法:按照字典序比较---字符大小的顺序
String类重写了父类Object中equals方法,Object中equals默认按照==比较,String类重写equals后,按照如下规则进行比较,比如:s1.equals(s2)
3. int compareTo(String s)方法:按照字典序比较
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型,具体比较方式:
1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符大小的差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回两个字符串长度差值。
String s1 = new String("abc"); String s2 = new String("abc"); String s3 = new String("abcdef"); String s4 = new String("ac"); System.out.println(s1.compareTo(s2)); //输出结果0 System.out.println(s1.compareTo(s3)); //输出结果-3 System.out.println(s1.compareTo(s4)); //输出结果-1
4.int compareToIgnorCase(String str)方法:与compareTo方式相同,但是忽略大小写比较
String s1 = new String("abc"); String s2 = new String("ABC"); String s3 = new String("aBcDe"); System.out.println(s1.compareToIgnoreCase(s2)); //输出结果为0 System.out.println(s2.compareToIgnoreCase(s3)); //输出结果为-2
字符串查找
字符串查找也是字符串中重要的操作,String类提供常用查找的方法
方法 | 功能 |
char charAt(int index) | 返回index位置字符 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch,int fromIndex) | 从fromIndex位置找ch第一次出现的位置,无返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,无返回-1 |
int indexOf(String str,int fromIndex) | 从fromIndex位置开始找str第一次出现的位置,无返回-1 |
int lastIndexOf(int ch) | 从后往前找ch第一次出现的位置,无返回-1 |
int lastIndexOf(int ch,int fromIndex) | 从fromIndex开始从后往前找ch第一次出现的位置,无返回-1 |
int lastIndexOf(String str) |
从后往前找str第一次出现的位置,无返回-1 |
int lastIndexOf(String str,int fromindex) | 从fromIndex开始从后往前找,返回str第一次出现的位置,无返回-1 |
public static void main(String[] args) { String s = "aabbccddccbbaa"; System.out.println(s.charAt(2)); //b System.out.println(s.indexOf('c')); //4 System.out.println(s.indexOf("dd")); //6 System.out.println(s.indexOf('c',3)); //4 System.out.println(s.indexOf("bb",5)); //10 System.out.println(s.lastIndexOf('c')); //9 System.out.println(s.lastIndexOf("bb")); //10 System.out.println(s.lastIndexOf('b',5)); //3 System.out.println(s.lastIndexOf("bb",6)); //2 }
注意:上述方法都是实例方法
转化
1.数值和字符串转化
//数字转字符串 String s1 = String.valueOf(20); String s2 = String.valueOf(3.14); String s3 = String.valueOf(true); System.out.println(s1); System.out.println(s2); System.out.println(s3); //字符串转数字 int a = Integer.parseInt("20"); double b = Double.parseDouble("3.14"); //Integer Double 都是包装类 System.out.println(a); System.out.println(b); 2. 大小写转换 /大小写转换 String s1 = "HELLO"; String s2 = "hello"; System.out.println(s1.toLowerCase()); //转小写 System.out.println(s2.toUpperCase()); //转大写 //输出结果: hello HELLO
3. 字符串与数组相互转换
//字符串转数组 String s = "hello"; char[] ch = s.toCharArray(); for(int i=0;i<ch.length;i++){ System.out.println(ch[i]); } System.out.println(); //数组转字符串 String s2 = new String(ch); System.out.println(s2);
4. 格式化
String s = String.format("%d-%d-%d",2021,10,29); System.out.println(s); //2021-10-29
字符串的不可变性
String是一种不可变的对象,字符串中的内容是不可改变的,字符换不可被修改,是因为:
1. String类在设计时就是不可改变的,String类实现描述中已经说明了
String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:
1.String类被final修饰,表示该类不能被继承
2. value被final修饰,表明value自身的值不能改变,即不能引用其他字符数组,但是引用空间中的内容可以修改
2. 所有涉及到可能修改字符串内容的操作都是在创建一个新对象,改变的是新对象
final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容可以修改
为什么String要设计成不可变的?
1. 方便实现字符串对象池,如果String可变,那么对象池就需要考虑何时深拷贝字符串的问题。
2. 不可变对象是线程安全的
3. 不可变对象更方便缓存hash code,作为key时可以更高效的保存到HashMap中。
字符串修改
注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。
public static void main(String[] args) { String s = "hello"; s += "world"; System.out.println(s); }
这种方式效率非常低,不推荐使用,中间创建了好多临时对象
StringBuilder和StringBuffer
StringBuilder的介绍
由于String的不可更改特性,为了方便字符串的修改,Java中提供了StringBuilder和StringBuffer类,这两个类大部分功能是相同的,这里介绍StringBuilder常用的一些方法。
方法 | 说明 | |
StringBuilder() | 构造一个空的字符串构建器 | |
int length() | 返回构建器中代码单元的数量 | |
StringBuilder append(String str) | 追加一个字符串 | |
StringBuilder append(char c) | 追加一个代码单元 | |
void setCharAt(int i,char c) | 将第i个代码单元设置为c | |
StringBuilder insert(int offset,String str) | 在offset位置插入一个字符串 | |
StringBuilder insert(int offset,char c) | 在offset位置插入一个代码单元 |
|
StringBuilder delete(int starIndex,int endIndex) | 删除偏移量从starIndex到endIndex-1的代码单元 | |
StringBuilder reverse() | 反转字符串 | |
String toString() | 将所有字符按照String方式返回 | |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
public static void main(String[] args) { StringBuilder s = new StringBuilder("hello"); s.append(' '); s.append("world"); System.out.println(s); System.out.println(s.length()); s.insert(6,"and"); System.out.println(s); s.reverse(); System.out.println(s); System.out.println(s.substring(5)); System.out.println(s.toString()); } 执行结果: hello world 11 hello andworld dlrowdna olleh dna olleh dlrowdna olleh
注意:String和StringBuilder类不能直接转换,要转换,采用以下原则:
· String变为StringBuilder,利用StringBuilder的构造方法或append()方法
· StringBuilder变为String,调用toString()方法
区别
· String的内容不可修改,StringBuffer与StringBuilder的内容可以修改
· StringBuffer与StringBuilder大部分功能是相似的
· StringBuffer采用同步处理,属于线程安全操作;StringBuilder未采用同步处理,属于线程不安全操作