1. ?String类的重要性
在 C 语言中已经涉及到字符串了,但是在 C 语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了 String 类。
在开发和校招笔试中,字符串也是常客,比如 :
字符串转整形数字 字符串相加 而且在面试中也频繁被问到,比如: String 、 StringBuff 和 StringBulider 之间的区别等。2. ?常用方法
2.1 ?字符串构造
常用的三种:
其他方法需要用到时,大家参考Java在线文档:String官方文档
【 注意 】 1. String 是引用类型,内部并不存储字符串本身 ,在 String 类的实现源码中, String 类实例变量如下: 案例:public static void main(String[] args) { // s1和s2引用的是不同对象 s1和s3引用的是同一对象 String s1 = new String("hello"); String s2 = new String("world"); String s3 = s1; System.out.println(s1.length()); // 获取字符串长度---输出5 System.out.println(s1.isEmpty()); // 如果字符串长度为0,返回true,否则返回false}
2. 在 Java 中 “” 引起来的也是 String 类型对象。 // 打印 "hello" 字符串 (String 对象 ) 的长度 System . out . println ( "hello" . length ()); 2.2 ?String对象的比较
字符串的比较是常见操作之一,比如:字符串排序。 Java 中总共提供了 4 中方式: 1. == 比较是否引用同一个对象 注意:对于内置类型,==比较的是变量中的值;对于引用类型== 比较的是引用中的地址。 代码:public static void main(String[] args) { int a = 10; int b = 20; int c = 10; // 对于基本类型变量,==比较两个变量中存储的值是否相同 System.out.println(a == b); // false System.out.println(a == c); // true // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象 String s1 = new String("hello"); String s2 = new String("hello"); String s3 = new String("world"); String s4 = s1; System.out.println(s1 == s2); // false System.out.println(s2 == s3); // false System.out.println(s1 == s4); // true}
2. boolean equals(Object anObject) 方法:按照字典序比较
String 类重写了父类 Object 中 equals 方法, Object 中 equals 默认按照 == 比较, String 重写 equals 方法后,按如下规则进行比较,比如: s1.equals(s2) 代码: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方式相同,但是忽略大小写比较 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.compareToIgnoreCase(s2)); // 不同输出字符差值-1 System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0 System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3}
2.3 ?字符串查找
字符串查找也是字符串中非常常见的操作,String类提供的常用查找的方法:
方法 | 功能功能 |
char charAt(int index) | 返回 index 位置上字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException 异常 |
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 |
案例:
代码:
String s = "aaabbbcccaaabbbccc";System.out.println(s.charAt(3)); // 'b'System.out.println(s.indexOf('c')); // 6System.out.println(s.indexOf('c', 10)); // 15System.out.println(s.indexOf("bbb")); // 3System.out.println(s.indexOf("bbb", 10)); // 12System.out.println(s.lastIndexOf('c')); // 17System.out.println(s.lastIndexOf('c', 10)); // 8System.out.println(s.lastIndexOf("bbb")); // 12System.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. ?大小写转换
代码:
public static void main(String[] args) { String s1 = "hello"; String s2 = "HELLO"; // 小写转大写 System.out.println(s1.toUpperCase()); // 大写转小写 System.out.println(s2.toLowerCase()); }
输出结果:
3. ?字符串转数组
代码:
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 replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换收个内容 |
public static void main(String[] args) { String str = "helloworld" ; System.out.println(str.replaceAll("l", "_")); System.out.println(str.replaceFirst("l", "_")); }
输出结果:
注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.
2.6 ?字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。 可用方法如下:
方法 | 功能 |
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex, int limit) | 将字符串以指定的格式,拆分为limit 组 |
public static void main(String[] args) { String str = "hello world hello bit" ; String[] result = str.split(" ") ; // 按照空格拆分 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 ?字符串截取
从一个完整的字符串之中截取出部分内容。可用方法如下:方法 | 功能 |
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分内容 |
String str = "helloworld" ;System.out.println(str.substring(5));System.out.println(str.substring(0, 5));
注意事项 : 1. 索引从0开始 2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标 2.8 ?其他操作方法
方法 | 功能 |
String trim() | 去掉字符串中的左右空格,保留中间空格 |
String toUpperCase() | 字符串转大写 |
String toLowerCase() | 字符串转小写 |
代码示例: 观察trim()方法的使用
String str = " hello world " ;System.out.println("["+str+"]");System.out.println("["+str.trim()+"]");
输出结果:
trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).
代码示例: 大小写转换
String str = " hello$%world" ;//小写转大写System.out.println(str.toUpperCase());//大写转小写System.out.println(str.toLowerCase());
输出结果:
这两个函数只转换字母。
2.9 ?字符串的不可变性
1. String类在设计时就是不可改变的,来看看String内部
第一种:
第二种:
2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
比如 replace 方法:
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。为什么 String 要设计成不可变的?(不可变对象的好处是什么?)
1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
2. 不可变对象是线程安全的 . 3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中 .那如果想要修改字符串中内容,该如何操作呢?
2.10 ?字符串修改
注意:尽量避免直接对 String 类型对象进行修改,因为 String 类是不能修改的,所有的修改都会创建新对象,效率 非常低下。 来看看:public static void main(String[] args) { String s = "hello"; s += " world"; System.out.println(s); // 输出:hello world}
但是这种方式不推荐使用,因为其效率非常低,中间创建了好多临时对象 因此:尽量避免对 String 的直接需要,如果要修改建议尽量 使用StringBuffer 或者 StringBuilder 。 3. ?StringBuilder和StringBuffer
3.1 ?StringBuilder的介绍
由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer 类。这两个类大部分功能是相同的,这里介绍 StringBuilder 常用的一些方法,其它需要用到了大家可参阅 StringBuilder 在线文档
StringBuff append(String str) | 在尾部追加,相当于 String 的 += ,可以追加: boolean 、 char 、 char[] 、 double 、 float 、 int 、 long 、 Object 、 String 、 StringBuff 的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index, char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start , int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
案例:
public static void main(String[] args) { StringBuilder sb1 = new StringBuilder("hello"); StringBuilder sb2 = sb1; // 追加:即尾插-->字符、字符串、整形数字 sb1.append(' '); // hello sb1.append("world"); // hello world sb1.append(123); // hello world123 System.out.println(sb1); // hello world123 System.out.println(sb1 == sb2); // true System.out.println(sb1.charAt(0)); // 获取0号位上的字符 h System.out.println(sb1.length()); // 获取字符串的有效长度14 System.out.println(sb1.capacity()); // 获取底层数组的总大小 sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123 sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123 System.out.println(sb1); System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置 System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置 sb1.deleteCharAt(0); // 删除首字符 sb1.delete(0,5); // 删除[0, 5)范围内的字符 String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回 System.out.println(str); sb1.reverse(); // 字符串逆转 str = sb1.toString(); // 将StringBuffer以String的方式返回 System.out.println(str);}
3.2?StringBuilder和StringBuffer的区别
注意: String 和 StringBuilder 类不能直接转换。如果要想互相转换,可以采用如下原则 : String变为StringBuilder: 利用StringBuilder的构造方法或append()方法 StringBuilder变为String: 调用toString()方法。3.2 ?面试题:
1. String、StringBuffer、StringBuilder的区别
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改. StringBuffer与StringBuilder大部分功能是相似的 StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
2. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】
String str = new String ( "ab" ); // 会创建多少个对象 String str = new String ( "a" ) + new String ( "b" ); // 会创建多少个对象好啦,今天的分享就到这里了,感谢观看。