目录
字符串在编程中的应用是非常广泛的,在C语言中,我们用字符数组表示一个字符串,但是在Java中专门提供了String类,让我们在使用字符串时更加方便。
一、String类中的常用方法
1、构造方法
当我们查看String类的原码时,会发现它提供了许多种构造方法,而我们常用以下三种方式来创建一个字符串对象:
注意:
String是引用类型,它本身存储的是对象的地址,而不是字符串内容。
观察String类的原码,可以发现String类创建的对象中存放的是一个字符数组value和一个hash:
原码中,value和hash都是被private修饰的,并且没有对外提供get和set方法,所以说字符串是不可以被修改的。
通过调试也可以发现,字符串是由字符数组value和hash组成的:
用一张图来表示字符串在内存中的存储就是这样的:
public static void main(String[] args) {
String s1 = "hello";
char[] ch = {'h','e','h','e'};
String s2 = new String(ch);
}
2、字符串比较常用方法
2.1 ==比较
因为String类型是引用类型,所以==比较的是引用中存放的地址,看两个变量引用的是否为同一个对象。
2.2 equals方法比较
String类同样继承了Object类,但是String类中重写了equals方法,不再是通过==比较,而是进行逐个字符的比较。
String类中的equals方法原码:
String类的equals方法比较的是两个字符串中的内容是否相同,不再是比较是否引用同一个对象:
2.3 compareTo方法
equals方法的返回值类型是布尔类型,而compareTo返回值类型是int类型。具体比较方式如下:
1、先按照字典次序大小比较,如果出现不同的字符,则返回两个字符的差值;
2、若两个字符完全相同,返回0;
3、如果前n个字符相同(n为较短的字符串的长度),返回两个字符串长度的差值。
2.4 compaToIgnoreCase方法
和compareTo的比较方式相同,但是忽略大小写:
3、字符串查找常用方法
字符串查找是字符串中常用的一种操作,String类中常用的查找方法有以下几种:
3.1 charAt方法
charAt()方法会返回字符串中index位置的字符,如果传入的参数index为负数或者超过字符串长度,则会抛出一个数组越界的异常:
3.2indexOf方法
indexOf方法有4个重载方法,可以传一个字符,也可以传一个字符串,它会返回这个字符或字符串在目标字符串中第一次出现的位置,没有找到返回-1。
如果后面再传入一个int类型的fromIndex参数,它就会从fromIndex位置开始找传入的字符或字符串在目标字符串中第一次出现的位置,没有找到返回-1:
3.3 lastIndexOf方法
lastIndexOf方法的使用和indexOf方法一样,不过它是从后往前查找:
4、字符串转换常用方法
4.1 数值和字符串之间的转换
通过valueOf方法转换,支持以下类型的数据转换为字符串:
字符串转数字需要使用数据类型对应的包装类型调用valueOf方法或者对应的parse方法:
4.2 大小写的转换
调用toUpperCase和toLowerCase方法即可:
由于字符串是不可以被修改的,所以原来的字符串是没有发生改变的:
4.3 字符串和数组之间的转换
字符串转数组调用toCharArray方法即可:
4.4 格式化
format方法可以根据你给的格式转换为相应的字符串:
5、字符串替换
5.1 replaceFirst方法
这个方法会替换掉目标字符串中指定的首个内容(原字符串内容不会变):
5.2 replaceAll方法
这个方法会替换掉目标字符串中指定的所有内容(原字符串内容不变):
6、字符串拆分
字符串拆分可以调用spilt方法,以指定的格式全部拆分:
如果再给一个int类型的参数limit,就会将字符串以指定的格式拆分为limit组:
注意:
1、如果以字符‘.’ ‘+’ ‘*’ ‘|’ 的格式进行拆分,前面需要加上转义字符"\\",否则会拆分失败:
2、如果以'\'的形式进行拆分,需要写成"\\\\":
3、一个字符串可以实现多次拆分:
7、字符串截取方法
从一个完整的字符串中截取部分内容,可以使用substring方法:
注意:
第二种方式中substring(2,5)是左闭右开的写法,截取的是2~4下标的字符,不包含5下标。
8、trim方法的使用
trim方法会去掉字符串开头和结尾的空白字符(空格,换行,制表符等):
中间的空格不会被去掉~
二、字符串常量池
观察上述代码,可以发现s1和s2的内容相同,s3和s4的内容相同,而s1和s2引用的是同一个对象,s3和s4却不是,这是为什么呢?
为了使程序的运行速度更快、更节省内存,Java中引入了字符串常量池(StringTable),而s1和s2引用的是同一个常量字符串,所以s1==s2结果为true。
上述代码中的4个字符串在内存中的存储如下图:
通过观察上图可以发现:
1、new出来的对象都是唯一的;
2、使用常量字符串创建String类对象的效率更高,更节省空间。
我们也可通过intern方法手动将自己创建的String对象添加到常量池中:
三、字符串的不可变性
我们从String类的原码中可以发现:
1、String类被final修饰,说明String类是不能被继承的
2、value被private修饰,说明value自身的值是不能被改变的,又因为value被final修饰,说明value不能引用其他的字符数组,但是它当前所引用的对象的内容是可以被修改的。
(字符串不可变是因为value被final修饰了,这种说法是错误的):
以上结论可以推出:所有涉及到可能修改字符串内容的方法都是创建一个新对象,改变的是新对象,原字符串的内容不会被改变,如replace、toUpperCase、toLowerCase方法等。
注意:
String类是不可以被修改的,所有的修改都会创建新对象,效率非常低下。
这种方式不推荐使用,因为其效率非常低,中间创建了许多临时对象。
如果需要修改字符串内容,我们可以使用StringBuilder或者StringBuffer。
四、StringBuilde和StringBuffer
StringBuilde和StringBuffer的功能大部分都是相同的,以下是它们的一些常用方法:
从上面的代码中可以发现,String类和StringBuilder类最大的区别在于String的内容无法修改,而StringBuilder的内容可以被修改。如果你的字符串需要被频繁修改,建议使用StringBuilder类。
注意:
1、String和StringBuilder不能直接转换,如果需要转换,可以使用以下方法:
String转StringBuilder:使用StringBuilder的构造方法或者append方法;
StringBuilder转String:调用toString方法(toString方法会new一个新的String对象然后赋值给String的引用)。
2、String、StringBuilder、StringBuffer的区别:
(1)String的内容不可以被修改,StringBuilder和StringBuffer的内容可以被修改;
(2)StringBuilder和StringBuffer的大部分功能是一样的;
(3)StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。
String类到此结束,溜了溜了~