一.String类中的常用方法
public boolean equals ( Object anObject ) {
// 1. 先检测 this 和 anObject 是否为同一个对象比较,如果是返回 true
if ( this == anObject ) {
return true ;
}
// 2. 检测 anObject 是否为 String 类型的对象,如果是继续比较,否则返回 false
if ( anObject instanceof String ) {
// 将 anObject 向下转型为 String 类型对象
String anotherString = ( String ) anObject ;
int n = value . length ;
// 3. this 和 anObject 两个字符串的长度是否相同,是继续比较,否则返回 false
if ( 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 ;
}
public static void main ( String [] args ) {
String s1 = new String ( "hello" );
String s2 = new String ( "hello" );
String s3 = new String ( "Hello" );
// s1 、 s2 、 s3 引用的是三个不同对象,因此 == 比较结果全部为 false
System . out . println ( s1 == s2 ); // false
System . out . println ( s1 == s3 ); // false
// equals 比较: String 对象中的逐个字符
// 虽然 s1 与 s2 引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出 true
// s1 与 s3 引用的不是同一个对象,而且两个对象中内容也不同,因此输出 false
System . out . println ( s1 . equals ( s2 )); // true
System . out . println ( s1 . equals ( s3 )); // false
}
3. int compareTo(String s) 方法 : 按照 字典序进行比较
与 equals 不同的是, equals 返回的是 boolean 类型 ,而 compareTo 返回的是 int 类型 。具体比较方式:
1. 先按照字典次序大小比较,如果 出现不等的字符,直接返回这两个字符的大小差值
2. 如果前 k 个字符相等 (k 为两个字符长度最小值 ) ,返回值两个字符串长度差值
public static void main ( String [] args ) {
String s1 = new String ( "abc" );
String s2 = new String ( "ac" );
String s3 = new String ( "abc" );
String s4 = new String ( "abcdef" );
System . out . println ( s1 . compareTo ( s2 )); // 不同输出字符差值 -1
System . out . println ( s1 . compareTo ( s3 )); // 相同输出 0
System . out . println ( s1 . compareTo ( s4 )); // 前 k 个字符完全相同,输出长度差值 -3
}
4. int compareToIgnoreCase(String str) 方法:与 compareTo 方式相同,但是忽略大小写比较
2.3 字符串查找
public static void main ( String [] args ) {
String s = "aaabbbcccaaabbbccc" ;
System . out . println ( s . charAt ( 3 )); // 'b'
System . out . println ( s . indexOf ( 'c' )); // 6
System . out . println ( s . indexOf ( 'c' , 10 )); // 15
System . out . println ( s . indexOf ( "bbb" )); // 3
System . out . println ( s . indexOf ( "bbb" , 10 )); // 12
System . out . println ( s . lastIndexOf ( 'c' )); // 17
System . out . println ( s . lastIndexOf ( 'c' , 10 )); // 8
System . out . println ( s . lastIndexOf ( "bbb" )); // 12
System . out . println ( s . lastIndexOf ( "bbb" , 10 )); // 3
2.4 转化
1. 数值和字符串转化
public static void main ( String [] args ) {
// 数字转字符串
String s1 = String . valueOf ( 1234 );
String s2 = String . valueOf ( 12.34 );
String s3 = String . valueOf ( true );
String s4 = String . valueOf ( new Student ( "Hanmeimei" , 18 ));
System . out . println ( s1 );
System . out . println ( s2 );
System . out . println ( s3 );
System . out . println ( s4 );
System . out . println ( "=================================" );
// 字符串转数字
// 注意: Integer 、 Double 等是 Java 中的包装类型,这个后面会讲到
int data1 = Integer . parseInt ( "1234" );
double data2 = Double . parseDouble ( "12.34" );
System . out . println ( data1 );
System . out . println ( data2 );
2. 大小写转换
3. 字符串转数组
4. 格式化
2.5 字符串替换
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
System . out . println ( s1 );
System . out . println ( s2 );
System . out . println ( s3 );
System . out . println ( s4 );
System . out . println ( "=================================" );
// 字符串转数字
// 注意: Integer 、 Double 等是 Java 中的包装类型,这个后面会讲到
int data1 = Integer . parseInt ( "1234" );
double data2 = Double . parseDouble ( "12.34" );
System . out . println ( data1 );
System . out . println ( data2 );
}
public static void main ( String [] args ) {
String s1 = "hello" ;
String s2 = "HELLO" ;
// 小写转大写
System . out . println ( s1 . toUpperCase ());
// 大写转小写
System . out . println ( s2 . toLowerCase ());
}
public static void main ( String [] args ) {
String s = "hello" ;
// 字符串转数组
char [] ch = s . toCharArray ();
for ( int i = 0 ; i < ch . length ; i ++ ) {
System . out . print ( ch [ i ]);
}
System . out . println ();
// 数组转字符串
String s2 = new String ( ch );
System . out . println ( s2 );
}
4.格式化
public static void main ( String [] args ) {
String s = String . format ( "%d-%d-%d" , 2019 , 9 , 14 );
System . out . println ( s );
}
2.5 字符串替换
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
代码示例 : 字符串的替换处理
String str = "helloworld" ;
System . out . println ( str . replaceAll ( "l" , "_" ));
System . out . println ( str . replaceFirst ( "l" , "_" ));
注意事项 : 由于字符串是不可变对象 , 替换不修改当前字符串 , 而是产生一个新的字符串
2.6 字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
如果limit大于最多拆分的数组数,则能拆分几组就拆分几组
String str = "hello world hello bit" ;
String [] result = str . split ( " " ) ; // 按照空格拆分
for ( String s : result ) {(注意:字符串本身不能改变,是将拆分的字符串放入新的字符串数组)
System . out . println ( s );
}
代码示例 : 字符串的部分拆分
String str = "hello world hello bit" ;
String [] result = str . split ( " " , 2 ) ;
for ( String s : result ) {
System . out . println ( s );
}
拆分是特别常用的操作 . 一定要重点掌握 . 另外有些 特殊字符作为分割符可能无法正确切分 , 需要加上转义
代码示例 : 拆分 IP 地址
String str = "192.168.1.1" ;
String [] result = str . split ( "\\." ) ;
for ( String s : result ) {
System . out . println ( s );
}
注意事项 :
1. 字符 "|","*","+" 都得加上转义字符,前面加上 "\\" .
2. 而 如果是 "\" ,那么就得写成 "\\\\" .
3. 如果一个字符串中有多个分隔符, 可以用 "|" 作为连字符 .
代码示例 : 多次拆分
String str = "name=zhangsan&age=18" ;
String [] result = str . split ( "&" ) ;
for ( int i = 0 ; i < result . length ; i ++ ) {
String [] temp = result [ i ]. split ( "=" ) ;
System . out . println ( temp [ 0 ] + " = " + temp [ 1 ]);
}
2.7 字符串截取
2.8 其他操作方法
其他方法需要用到时,大家参考 Java 在线文档: Java Platform SE 8
在 Java 程序中, 为了使程序的运行速度更快、
更节省内存 , Java 为 8 种基本数据类型和 String 类都提供了常量池。
为了节省存储空间以及程序的运行效率,Java中引入了:
1.Class文件常量池:每个.Java源文件编译后生成.Class文件中会保存当前类中的字面常量以及符号信息
2.运行时常量池:在.Class文件被加载时,.Class文件中的常量池被加载到内存中称为运行时常量池,运行时常
量池每个类都有一份。
3. 字符串常量池
2.9.2 字符串常量池 (StringTable)
字符串常量池在 JVM 中是 StringTable 类,实际 是一个固定大小的 HashTable ( 一种高效用来进行查找的数据结构,
后序给大家详细介绍 ) ,不同 JDK 版本下字符串常量池的位置以及默认大小是不同的
2.9.3再谈String对象创建
由于不同JDK版本对字符串常量池的处理方式不同,此处在Java8 HotSpot上分
1. 直接使用字符串常量进行赋值
public static void main ( String [] args ) {
String s1 = "hello" ;
String s2 = "hello" ;
System . out . println ( s1 == s2 ); // true
}
3. intern 方法
intern 是一个 native 方法 (Native 方法指:底层使用 C++ 实现的,看不到其实现的源代码 ) , 该方法的作用是手
动将创建的 String 对象添加到常量池中 。
2.10字符串的不可变性
String是一种不可变对象.字符串中的内容是不可改变。字符串不可被修改,是因为:
1.String类在设计时就是不可改变的,String类实现描述中已经说明了
String 类中的字符实际保存在内部维护的 value 字符数组中 ,该图还可以看出:
1. String 类被 fifinal 修饰,表明 该类不能被继承
2. value 被修饰 被 final 修饰,表明 value 自身的值不能改变,即不能引用其它字符数组,但是其引用空间中
的内容可以修改。
2. 所有涉及到可能 修改字符串内容的操作都是创建一个新对象,改变的是新对象
比如 replace 方法:
【 纠正 】网上有些人说: 字符串不可变是因为其内部保存字符的数组被 final 修饰了,因此不能改变。
这种说法是错误的,不是因为 String 类自身,或者其内部 value 被 fifinal 修饰而不能被修改。
fifinal 修饰类表明该类不想被继承, final 修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内
容是可以修改的 。 真正原因:设计时规定String类是不能进行修改的。
为什么 String 要设计成不可变的 ? ( 不可变对象的好处是什么 ?) ( 选学 )
1. 方便实现字符串对象池. 如果 String 可变 , 那么对象池就需要考虑写时拷贝的问题了.
2. 不可变对象是线程安全的 .
3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中
2.11 字符串修改
注意:尽量避免直接对 String 类型对象进行修改,因为 String 类是不能修改的,所有的修改都会创建新对象,效率
非常低下。
可以看待在对 String 类进行修改时,效率是非常慢的,因此:尽量避免对 String 的直接需要,如果要修改建议尽量
使用 StringBuffffer 或者 StringBuilder 。(我们可以理解的是,用StringBuffer和StringBuilder进行字符串修改时,其内部可以进行字符串的修改,直接用其修改,可以避免String和这两类之间的转化,同时避免转化后建立新的对象,有利于提高效率)
二.StringBuffer和Stringbuilder
3.1 StringBuilder的介绍
由于 String 的不可更改特性,为了方便字符串的修改, Java 中又提供 StringBuilder 和 StringBuffffer 类。这两个类大
部分功能是相同的,这里介绍 StringBuilder 常用的一些方法,其它需要用到了大家可参阅 StringBuilder 在线文档( Java Platform SE 8 )
从上述例子可以看出: String 和 StringBuilder 最大的区别在于 String 的内容无法修改,而 StringBuilder 的内容可
以修改 。频繁修改字符串的情况考虑使用 StringBuilder 。
注意: String 和 StringBuilder 类不能直接转换。如果要想互相转换,可以采用如下原则:
String 变为 StringBuilder: 利用 StringBuilder 的构造方法或 append() 方法
StringBuilder 变为 String: 调用toString方法
1. String 、 StringBuffer 、 StringBuilder 的区别
String 的内容不可修改, StringBuffer 与 StringBuilder 的内容可以修改 .
StringBuffer 与 StringBuilder 大部分功能是相似的
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作