String类
String类
String类型的基本认识
String对象用于保存字符串,也就是一组字符序列
字符串常量的对象是用双引号括起的字符序列
字符串通常使用Unicode字符编码,一个字符(不管时字母还是汉字)占用两个字节
字符串String拥有很多的构造器
String类时final类,不能被其他的类所继承。private final byte[] value;String类拥有value属性,并且为final性质,表示不能被做出修改。比如从TOM变成TOO。也就是一句话,当我们的str发生更改之后,其地址已经改变,原地址的内容不会发生改变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package Learn;
public class Test{
public static void main(String[] args) {
final char c[]={'t','t','0'};
//这里我们可以发现我们成功更改了c的值,并且没有报错
for (int i=0;i< c.length;i++){
c[i]='v';
}
System.out.println(c);
//但是当我们重新写一个数组
final char b[]={'t','t','0'};
//下面的这个赋值就是错误的
//c=b;
//说完上面的,我们来看一下String类不可变的
String str1="tom";
System.out.println(str1.hashCode());
System.out.println(str1);
//我将m替换为o,我们可以根据结果发现,这个根本就没有改变,而且地址没有改变
//说明在replace过程中其实创建的新的去存储这个字符串,而源地址的字符串是不会发生改变的
str1.replace('m','0');
System.out.println(str1.hashCode());
System.out.println(str1);
//但是我们在平常的时候,明明可以改变String的值,这是因为我们new了一个string对象,str1指向的对象地址改变了
String str2="jack";
str1=str2;
System.out.println(str1);
System.out.println(str1.hashCode());
}
}
查看上述的图可以发现,String继承了以上的接口,而继承Serializable表示该字符可以在网络上传输,而对于Comparable则表示可以用于比较。
String类型的创建剖析
方式一:直接赋值
1
String str1="jack";
先从常量池查看是否有”jack“是数据空间,如果有,则直接指向;如果没有,则重新创建,然后指向。str1最终指向的是常量池的地址空间。
调用构造器:
1
String str2=new String("tom");
先在堆中创建空间,里面维护了value属性,指向常量池tom空间。如果常量池没有tom,重写创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。但是由于value是String的私有方法,所以我们无法查看value的值
练习1
1 | package Learn; |
他们虽然值相等,但是他们的地址却不相等。
练习2
intern
1
public String intern()
返回字符串对象的规范表示。
最初为空的字符串池由
String
类String
。当调用intern方法时,如果池已经包含与
equals(Object)
方法确定的相当于此String
对象的字符串,则返回来自池的字符串。 否则,此String
对象将添加到池中,并返回对此String
对象的引用。由此可见,对于任何两个字符串
s
和t
,s.intern() == t.intern()
是true
当且仅当s.equals(t)
是true
。所有文字字符串和字符串值常量表达式都被实体化。 字符串文字在The Java™ Language Specification的 3.10.5节中定义。
结果
一个字符串与该字符串具有相同的内容,但保证来自一个唯一的字符串池。
1 | package Learn; |
练习3
1 | package Learn; |
String类型字符串的特性
编译器会堆常量池的对象进行优化。下面的一段代码中,按照本意会生成三个对象,但是编译器会自动识别出其中的关系,从而仅仅创建一个adcdac对象。查看以下代码之后我们可以看出,在str3中是创建了一个新对象的,否则不会与4和5的对象不相同。在3执行的过程,首先创建了StringBuilder对象,利用append接受str1与str2,然后在将值给与str3,由于使用了StringBuilder,所以本次的str3与String str3=new String(“adcdac”);效果相同。所以常量的相加在,常量池中进行操作,如果是变量则是在堆中进行操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test{
public static void main(String[] args) {
String str1="adc";
String str2="dac";
String str3=str1+str2;
String str4="adcdac";
String str5="adc"+"dac";
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
System.out.println(str3.hashCode());
System.out.println(str4.equals(str3));
System.out.println(str4==str3);
System.out.println(str5==str3);
System.out.println(str4==str5);
}
}
Java中当数组与字符串在方法中被更改时
1 |
|
String类的常见方法
方法名 | 用法 |
---|---|
equals | 区分大小写,判断是否相等 |
equalsIgnoreCase | 忽略大小写,判断是否相等 |
length | 获得长度 |
indexOf | 获得字符在字符串中第一次出现的索引,从0开始,找不到就返回-1 |
lastindexOf | 获得字符在字符串中最终出现的位置,索引从0开始 |
substring(a,b) | 截取指定范围的字符串(不包含位置b) |
trim | 去除前后空格 |
charAt | 获取某索引处的字符 |
1 | package Learn; |
方法名 | 用法 |
---|---|
toUpperCase | 变成大写 |
toLowerCase | 变成小写 |
concat | 获得长度 |
replace | 替换字符串中的字符 |
split | 分割字符串 |
compareTo | 比较字符串的大小 |
toCharArray | 转换成字符数组 |
format | 格式化字符串 |
1 | package Learn; |
注意
对于喜欢使用表情包的同学,例如,其实表情包的表示使用的是两个代码单元,这是想要如果我们想要得到的第三个char字符不是最后一个,如果此时想要精确使用,就需要我们调用另外的方法。
1 | /** |
此时我们输出length为4,如果想要输出正确的结果,需要首先转换为数组
1 | /** |
额,怎么顺利遍历正在思考中。。。,在《Java技术核心卷》中建议不要使用charAt方法,