465-473String类

一、String类

1、String类的理解和创建对象
1)String对象用于保存字符串,所谓字符串就是一组字符序列
2)字符串常量对象是用引号括起来的字符序列。例如:
“你好”,“12.97”,“boy”等
3)字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占用两个字节
4)String类较常用的构造方法
String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex, int count)
// 1、String对象用来保存字符串,也就是一组字符序列
String name = "jack";
看看这个String的类图,追进String中查看类图
String这个类,实现了三个接口
Serializable Comparable CharSequence
一个父类
Object

image
一旦实现了这个Serializable,代表这个对象是可以串行化的,也就表示这个字符串可以在网络上面进行传输。
第二个接口是Comparable
String实现了Comparable接口库,说明String对象可以相互比较
而CharSequence是String的字符串序列的接口
重点要知道第一个接口和第二个接口
即:
Serializable
Comparable
字符串常量指的是什么

String name = "jack";这条语句当中,字符串常量指的是"jack"这个部分
使用双引号引用起来的序列

第三点字符串的字符是使用Unicode字符编码的,一个字符不区分是字母还是汉字,是占用两个字节的
String类有很多的构造器,也就是实现了构造器的重载
image
常用的构造器主要是什么呢?

String()
String(String)
String(char[])
String(byte[],int,int)
String(byte[])
前面讲到String类实现了接口Serializable,意味着String可以串行化,可以在网络传输,接口Comparable,String对象可以比较大小
String是final类,不能被其他的类继承
image
在String中还有一个非常重要的value
String在保存一个字符串常量的时候真正保存的是在value,仍然是一个char数组
String有属性 private final char value[];
并且是一个final,是一个常量,只要这个数据是final一旦赋值就不能更改。
不可修改指的是地址不能够修改
不是说里面的字符不能修改

比如:
final char[] value = {'a','b','c'};
这个就相当于是一个String
还有一个
char[] v2 = {'t','o','m'};
value[0] = 'H';  // 可以修改
value = v2;  // 不可以
但是不写final是可以的
小结:
	1、String对象用于保存字符串,也就是一组字符序列
	2、jack是一个字符串常量,需要使用双引号括起来,是字符序列
	3、字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占用两个字节
	4、String类有很多的构造器,构造器的重载
	常用的有String s1 = new String();
	String s2 = new String(String original);
	String s3 = new String(char[] a);
	String s4 = new String(char[] a,int startIndex, int count)
	String s5 = new String(byte[] b)
	5、String类实现了接口Serializable,意味着String可以串行化:可以在网络传输,接口Comparable,意味着String对象可以比较大小
	6、String是final类,不能被其他的类继承
	7、String有属性private final char value[];用于存放字符串内容
	8、一定要主义:value是一个final类型,不能修改:即value不能指向新的地址,但是单个字符内容是可以变化的。

二、String的两种创建方式以及细节

创建String对象的两种方式
1、方式一
直接赋值的方式
String s = "hello";
2、方式二
调用构造器
String s = new String("hello");
其中方式二因为构造器重载了很多,所以不只是使用这一种构造器的方式创建。
那么方式一和方式二有什么区别呢?

**两种创建String对象的区别
方式一是直接赋值
方式二是使用构造器
1、方式一:
先从常量池中查看是否有这个"hello"这个字符串常量的数据空间,如果有这个空间,就直接指向;如果没有这个空间就重新创建,然后指向。
s最终指向的是常量池的空间地址
2、方式二:先在堆中创建空间,里面维护了value属性,指向常量池的hello空间。如果常量池中没有"hello",重新创建,如果有,就直接通过value指向。最终指向的是堆中的空间地址。

String的内存结构图
image
所以这两个不是同一个对象

测试题一
String a = "abc";
String b = "abc";
System.out.println(a.equals(b));
这里其实是相等的,因为使用赋值的方式是看常量池中是否有一个字符串常量abc的空间,如果没有就创建,如果有就直接指向。
因为a = "abc"之后,在常量池中就已经存在了"abc"的空间,所以b在创建的时候看常量池中存在了abc就直接指向了
所以a==b是对的,都是同一个空间
然后equals是重写了Object的方法,这里比较的是字符串中的每个字符是否相同,确实是相同的为true。

三、String类的练习题

来看一段代码

String a = "hsp";  // 先查看常量池中是否有字符串常量hsp,因为前面并没有创建过hsp,所以是没有的,没有就在常量池中创建hsp空间,然后a在栈中直接指向常量池中的hsp。
String b = new String("hsp");  // 这里在堆中创建一个字符串对象hsp,同样真实存储的地方也是在常量池当中的。堆中创建对象,指向常量池当中的hsp,然后b指向堆中的字符串对象。
a.equals(b)  // 这里比较的是字符串的内容,所以hsp和hsp是相等的。
a == b  // 这个是不相等的,因为a直接指向的是常量池当中的字符串,而b指向的是堆区当中字符串对象的地址,而这个对象的属性才是真正的字符串常量。
a == b.intern() // intern这个方法是用来干什么的呢!?因为String是在java.lang包中的,这里在这里查找。简单来说就是intern就是返回的常量池中最终的字符串常量的地址。即:当调用intern方法的时候,如果池当中已经包含了一个等于此String对象的字符串,使用equals方法确定,则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。所以现在a直接指向的是常量池当中字符串常量的地址,而这里的b也接收最终在字符串常量当中的地址,这两个字符串常量的内容是一样的,所以在常量池当中的地址也是一样的。
b == b.intern()  // b指向的是堆当中的字符串对象的地址,而b.intern返回的是最终在常量池当中的字符串常量的地址,两者不是同一个东西,所以这里错误。

第四题
image
image

四、第五个测试题

第五题
image
image

五、字符串的特性

image
创建了两个对象

1、String是一个final类,表示不可变的字符序列
2、字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
第二题:
image
第三个:
image
image
要理解c最终是指向的堆区当中的对象,而不是直接指向常量池当中的字符串常量
因为toString底层是new的。

小结:
底层是StringBuilder sb = new StringBuilder();
sb.append(a);sb.append(b);
sb是在堆当中,并且append是在原来字符串的基础上追加的。
重要规则,
String c1 = "ab" + "cd"; 常量相加,看的是池。
String c1 = a + b;变量相加看的是堆中。

六、字符串相关的练习题

image
image

七、String类的常见方法

String类的常见方法
说明:
String类是保存字符串常量的,每次更新都需要重新开辟空间,效率较低,因此Java设计者还提供了StringBuilder和StringBuffer来增强String的功能,并提高效率。后面我们会详细介绍StringBuilder和StringBuffer
我们来看看String的类图
String的父类Object,并且实现了三个接口
我们看看String的方法
String的方法有很多
在进行软件开发的时候会一定会使用到String的相关方法。

常用方法一
image
这里需要注意:
String str = "hello";
// str[0]不对,因为底层是一个属性value
// 需要使用str.charAt(0) => h
因为equals前面已经讲过了,这里就不再进行讲解,只需要知道equals是区分大小写的。

// 1、equals是区分大小写的
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.equals(str2));
最后的结果是一个false,因为这里是区分大小写的比较内容相等。
而equalsIgnoreCase是忽略大小写的判断内容是否相等。
String username = "johN";
if ("john".equalsIgnoreCase(username)) {
	System.out.println("Success!");
} else {
	System.out.println("Failure!");
}
这里不考虑大小写仍然是相等的。
str.length可以获取字符的个数,字符串的长度
system.out.println("韩顺平".length());
indexOf获取字符在字符串对象中第一次出现的索引,索引从零开始,如果找不到,返回-1
String s1 = "wer@terwe@g";
int index = s1.indexOf('@');
System.out.println(index);
lastIndexOf获取字符在字符串中最后一次出现的索引,索引从零开始,如果找不到,返回-1
s1 = "wer@terwe@g@";
index = s1.lastIndexOf('@');
System.out.println(index);
substring 截取指定范围的子串
String name = "hello,张三";
// 下面name.substring(6)从索引6开始截取后面所有内容
System.out.println(name.substring(6));
// 截取后面的字符
// name.substring(0,5)表示从索引0开始截取,截取到第五个字符
System.out.println(name.substring(0,5));
补充一点,前面的indexOf还有lastIndexOf除了可以是字符,还可以是子字符串

常用方法2
image

// 1、toUpperCase转换成大写
String s = "heLLo";
System.out.println(s.toUpperCase());//HELLO
// 2、toLowerCase转换成小写
System.out.println(s.toLowerCase());//hello
// 3、concat拼接字符串
String s1 = "宝玉";
s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");
System.out.println(s1);
// 4、replace替换字符串中的字符
String s1 = "宝玉 and 林黛玉 林黛玉 林黛玉";
s1 = s1.replace("林黛玉", "薛宝钗");
System.out.println(s1);
返回的结果是被替换的,但是原来的字符串并没有被修改
// 5、split分割字符串,对于某些分割字符串,我们需要转义
String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
String[] split = poem.split(",");
String poem = "E:\\aaa\\bbb";
String[] split = poem.split("\\\\");
// 6、toCharArray转换成字符数组
String s = "happy";
char[] chs = s.toCharArry();

image

八、格式化字符串

image

posted @ 2025-05-20 22:05  请叫我虾  阅读(20)  评论(0)    收藏  举报