提示:学习使用,仅供参考!
目录
String类用于保存字符串,也即是一组字符序列,类图如下
一、特点
- 无法被继承:String 类被 final 修饰
- 采用
Unicode
编码:一个字符(不论是字母还是汉字)都占两个字节 - 可串行化:实现了 Serializeble 接口,可进行网络传输
- 可比大小:实现了 Comparable接口,可调用**compareTo()**进行字符串大小的比较
- 线程安全:String 类是不可变类,而不可变类是线程安全的
有些彦祖可能会问:如果 String 类不可变,那下面代码为啥可行,这s1不是发生了变化吗?
String s1 = "hello";
s1 = "world";
System.out.println(s1); // world
这么一看,确实发生了变化,不过此变非彼变
二、不可变
String 是引用类型
,其值实际上保存的是具体内容的地址,而String 的创建一般有两种:通过 " "
直接赋值和通过构造器
创建
- 通过
" "
创建,字符串会直接存储到字符串常量池中,此时String对象指向的地址是存储在字符串常量池中的字符串的地址 - 通过
构造器
创建,会先在堆上创建一个String对象, 里面维护一个字符数组属性 value[](存放字符串),value指向字符串常量池,此时String对象指向的是堆
中的对象地址,而非常量池
中的地址
String s1 = "a";
String s2 = new String("a")
问题1:
s1 == s2 ?
s1保存的是字符串常量池中字符串的地址,而s2保存的是堆中对象的地址,显然不相等,返回 false
—
问题2:s1.equals(s2) ?
String类对Object类中的equals()方法进行了重写,比较的字符串的内容是否一致,而 s1 、s2 都为 “hello”,所以返回 true
上面说到,通过 " ",字符串会直接存储到字符串常量池中,再看彦祖提出的问题
String s1 = "hello";
s1 = "world";
第一行 s1 指向字符串常量池中 “hello” 地址,第二行 s1 又指向了字符串常量池 “world” 地址,如下图:
可以看出,s1 所谓的变化,实际是指向了另一个字符串常量,而非在原来的字符串常量上做修改
结论:被final
修饰的引用类型不能再指向其他对象,而字符串内容实际存储在 String 类中的字符数组 value[]。value[]为引用类型
,被 final 修饰,导致其不能指向其他字符数组对象,若只是被final修饰的话,其数组内容依旧可以修改,但坏就坏在 value[] 还被修饰符private
修饰,加之 String 类本身没有提供修改 value [] 的方法,所以 String 不可变
所谓 String 发生变化实际指的不是在原来的基础上做修改,而是指向一个新的字符串地址
原因
1)String类被 final
修饰导致其不能被继承,进而避免了子类破坏 String不可变。
2)String 类有一个私有
并被 final 修饰的字符数组 value[],字符串内容实际保存在数组中,而String并未提供可修改此数组的方法
拓展
被 finale修饰的变量是基本数据类型则值不能改变
被 finale修饰的变量是引用类型则不能再指向其他对象,但其内容可以发生变化
三、方法
1、intern()
返回字符串常量池中对应字符串的地址
String str1 = "abc";
String str2 = new String("abc");
str1 == str2; // false
str1 == str2.intern(); // true
2、split()
分割符,返回一个数组
String a = "a,b,v,d";
String[] str = a.split(","); // str = {a, b, v,d};
// 若有特殊字符,如 | 、 \\ 等, 需要加入转义符 \
String a = "a\\b\\v\\d";
String[] str = a.split("\\"); // 错误,需要转义
String[] str = a.split("\\\\");
3、equals() 与 equalsIgnoreCase()
eqauls():比较内容
equalsIgnoreCase():忽略大小写比较字符串内容
"hello".equals("Hellow"); // false
"hello".eqaulsIgonreCase("HELLOW"); // true
4、subString()
截取指定范围内容
str.subString(int i):从索引第 i 开始截取后面所有内容
str,subString(int i, int j ):从索引第 i 开始截取到索引为 ( j - 1)的内容
"hello,张三".subString(6); // 张三
"hello,张三".subString(0,5); // hello
"hello,张三".subString(3,5); // lo
5、indexOf() 与 lastIndexOf()
indexOf(String str):返回字符在字符串中第一次出现的索引位置,找不到返回-1
lastIndexOf(String str):返回字符在字符串最后一次出现的索引位置,**找不到返回-1
"abcdbcd".indexOf("b"); // 返回 2
"abcdbcd".lastindexOf("b"); // 返回 4
6、toUpperCase() 与 toLowerCase()
toUpperCase():转为大写
toLowerCase():转为小写
"abcd".toUpperCase(); // ABCD
"ABCD".toUpperCase(); // abcd
7、concat()
拼接字符串
"a".concat("b").concat("c"); // abc
8、compareTo()
比较字符串大小
1)长度相同,且内容相同:返回 0 (str1.length - str2.length)
"abcd".compareTo("abcd"); // 0
2)长度相同,内容不同:返回 str1 与 str2 第一个不同的字符进行相减的结果
"abcd".compareTo("abdd"); // 第一个不同的字符相减: c - d = -1
3)若长度不同,前面内容相同:返回 str1.length - str2.length 的结果
"abcd".compareTo("abcdabc"); // -3
9、replace()
替换,但不对原字符串做改变,返回的是一个新字符串
String s1 = "abbbccbc";
String s2 = s1.replace("b", "z"); // 将 "b" 全部替换成 "z"
// 此时 s1 还是"abbbccbc",而 s2 为"azzzcczc"
总结
步入筑基,金丹有望,若有错误,还望雅正