文章目录
- 前言
- 一、String
- 二、 StringBuilder --- 字符串拼接和字符串反转情形下使用
- 三、StringJoiner : 同样是一个字符串容器(*)
-
- 1 public StringJoiner(间隔符号) : 创建一个StringJoiner对象,指定拼接时的间隔符号
- 2 public StringJoiner(间隔符号,开始符号,间隔符号):创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号
- 3 public StringJoiner add(添加的内容):添加数据,并返回对象本身;特别注意,这里添加的内容只能是字符串(没有StringBuilder好用)
- 4 public int length() : 返回长度(字符出现的个数)
- 5 public String toString(): 将StringJoiner转换为String
- 四、字符串相关类的底层原理(扩展*)
- 五、综合练习
前言
0 java中的 == 究竟比较的是什么?(重要重要重要!!!!!!)
Python中 == 究竟在比较什么?参考博客
- 对于基本数据类型(如int, char等),== 比较的是它们的值。
因为java中的基本数据类型是直接存在栈空间,存的直接就是值,他们压根就没有地址,自然只能比较值,不能比较引用了 - 对于对象类型(如String, List等),== 比较的是它们的内存地址。
对于String还有一点小细节留到 下面字符串的比较里面去说明
java为我们提供了很多的字符串API接口,常见的有·String 、StringBuilder、StringJomier等等
一、String
【注】:
1 开始学习字符串前,我们需要知道在java中字符串String是引用数据类型,并且是不可变的,这个不可变单独解释一下,java中的字符串对象一旦创建就不可变,要修改只能重新创建一个字符串对象重新绑定变量。
2 String这个类是定义在java最基本的类java.lang包下的,并且不需要手动导入就可以用
3 String是一个类,实例化就是对象,下面会有具体演示
String是Java中的一种特殊的引用类型,但是为了方便使用,Java设计了字符串字面量(string literals)和String对象之间的自动转换。这使得我们可以像使用基本数据类型一样使用String,而无需显式地创建对象实例。
字符串字面量:在Java中用双引号括起来的字符串字面量(例如:“Hello”)会被自动转换为String对象。
最后关于 int这些为什么能直接声明变量,不用想了,这肯定是java的语法设计,java虚拟机识别到这种语法就会内部自动进行一些操作就是了,不用想太多,这种就纯粹就是一种语法了。(看完下面String的两种构造方式就知道基本舒服了关于这个疑惑)
1 String的两种构造方式
前面讲对象实例化语法有下面两句话
- 对象通用实例化语法:类名 变量(对象)名 = new 类名(参数)
除了少部分特殊类(String等),有更加简单的实例化方法,都能使用这个通用的实例化语法(不管你有没有更加简单实例化语法,反正这个一定行)
这里就专门来讲String的两种不同实例化语法了
- 简单实例化语法(用习惯了,今后也更加常用(直接创建)):String s = “hello world”
Java设计了字符串字面量(string literals)和String对象之间的自动转换。这使得我们可以像使用基本数据类型一样使用String,而无需显式地创建对象实例。— Python中万物皆对象,列表、元组、字典这些对象实例化的语法都有这种自动转换机制。 - 通用实例化语法(通过new创建):String s = new String(“hello world”) ,另外,如果括号里面不传参数就是创建空字符串
显式地创建对象实例,当然还是可以的。
// 1. 简单常用String实例化方式
String s1 = "hello";
System.out.println(s1); // hello
// 2. 通用使用new关键字(类)实例化String对象方式
String s2 = new String("hello world");
System.out.println(s2); // hello world
2 字符数组转字符串、字节数组转字符串
下面介绍一种使用字符数组转换成字符串和字节数组转字符串的用法,刷算法题可能会碰到这种用法,这里也提一下。
// 字符数组转字符串
char[] chars = {
'a', 'b', 'c', 'd', 'e'};
String str = new String(chars);
System.out.println(str); // abcde
// 字节数组转字符串
byte[] bytes = {
97, 98, 99, 100, 101};
String str2 = new String(bytes);
System.out.println(str2); // abcde
【注】:需要特别指出如果Python用str([‘a’, ‘b’, ‘c’, ‘d’, ‘e’])会将整个列表转成一个字符串,而不是这种拼接的方式,这是区别
3 静态方法 String.valueOf(任意基本数据类型) : 将任意基本数据类型转成String
System.out.println(String.valueOf(11.7)); // 11.7
System.out.println(String.valueOf(1)); // 1
System.out.println(String.valueOf('a')); // a
4 字符串的 + 拼接
前面的练习我们以及知道了,字符串可以和几乎所有类型数据拼接。
System.out.println("Hello World!"+ 1111 + "你好!"); // Hello World!1111你好!
这个功能甚至比Python中的 f " " 这种方式都要好用。
5 字符串的内存结构
前面已经讲过字符串的两种创建方式:
-
简单实例化语法(直接创建):String s = “hello world”
-
通用实例化语法(通过new创建):String s = new String(“hello world”) ,另外,如果括号里面不传参数就是创建空字符串
下面主要讲直接创建的语法,实际上这种比new更常用是因为在内存结构中更加节省内存。
实际上这种直接创建的方式的String对象会放在堆空间的StringTable(串词)这个区域创建String对象,并且有一个特定就是直接创建的这种方式创建过的字符串分配地址后,如果后面还会创建同样的字符串对象就会直接拿之前的地址来用,不会浪费内存重新创建,而new关键字创建对象会发生这种浪费内存的行为。
直接创建内存图:
记住一点:当使用双引号直接赋值时,系统会检查该字符串在串池中是否存在。
- 不存在:创建新的
- 存在:复用
【特别注意】:上述这个规则对于Python中的整数、字符串这些简单的对象也是适用的,但是对于列表这样比较复杂的对象就不太使用了,反正了解一下这个就可以了,这个内存地址变不变没有什么关系,增加一下奇奇怪怪的知识。
new关键字创建内存图
记住,每new一次就是开辟了一个新的内存空间,每new一次就会产生一个新的地址值。
6 字符串的“相等”比较和字符串的大小比较
(1)字符串的“相等”比较
在将字符串的比较前,我们需要先了解,java中 == 究竟比的是什么。显然前面我们已经讲过引用数据类型 == 比较的是引用。但是由于String的直接创建和new创建有点小区别在内存上(上面的内存模型),由于直接创建如果是创建已存在的直接复用,但new关键字每new一次就会产生一个新的地址。因此, 二者在混合用时 == 下面有几个细节要注意:
可以看到,这就有问题了。为了解决这种混合用的比较问题,java提供了专门的方法,不比较地址,比较字符串的内容。
a、s.equals(要比较的字符串):不忽略大小写比较(比较内容)
obj1.equals(obj2)这个方法很有意思,其是Object顶级父类里面标胶两个对象是否是同一个对象的方法,和 == 一样比较的都是引用,那为什么在String这里调用就成了比较字符串内容了呢?这就涉及到String这个类对obj1.equals(obj2)顶级父类里面的这个方法进行了重写呗!
上面这段话涉及到了Object中的顶级方法以及其对于的重写,看这篇博客就理解了。
b、s.equalsIgnoreCase(要比较的字符串):不忽略大小写比较(比较内容)
String a = "Hello";
String b = "hello";
System.out.println(a.equals(b)); // false
System.out.println(a.equalsIgnoreCase(b)); // true
【注】:键盘录入String是通过new关键字创建
关于键盘录入很有意思,键盘录入的String是通过new关键字创建的,下面我们以这个例子第一次演示怎么看java源码,参考视频
Scanner sc = new Scanner(System.in);
System.out.println("请输入abc:");
String input = sc.next(); // 这个方法是 new 一个 String 对象,所以下面的比较是 false
String s = "abc";
System.out.println(input == s); // false
这里一个new出来,一个直接创建出来,直接 == 引用不一样。通过查看sc.next();的源码可以发现其是new关键字创建出来的,查看源码过程参考上面视频,虽然不是很重要,但还是了解一下。
(2)字符串的大小比较 — int compareTo(s2)方法 : 比较两个字符串的大小
Java里面字符串大小比较规则写下面代码注释里面了
String s1 = "ab"; // 97 98
String s2 = "c"; // 99 97 - 99 = -2
int i = s1.compareTo(s2);
// 比较两个字符串的大小,规则是依次比较两个字符串的每个字符的 Unicode 值,然后找到第一个不同的字符,返回这两个字符的 Unicode 值的差值
// 如果两个字符串的长度不一样,而且较短的字符串的每个字符都和较长的字符串的每个字符都相等,那么返回两个字符串的长度差值
// 如果两个字符串的每个字符都相等,那么返回 0
// 简单来说,等价于 a b c d e f g h i j k l m n o p q r s t u v w x y z 这个顺序排列
System.out.println(i); // -2 说明 s1 < s2
7 String常用方法 — 字符串的索引、字符串的长度等
(1)public char charAt(int index): 根据索引返回字符
和Python字符串一样,字符串虽然不可变,但是有索引可以访问
String str = "Hello World!";
char c = str.charAt(0);
System.out.println(c); // H
【注】:java中任何索引都没有 -1 和Python的区别
(2)public int length(): 返回字符串的长度
【注】:
1 数组的长度是属性:arr.length
2 字符串的长度是方法 str.length()
String str = "Hello World!";
int len = str.length();
System.out.println("字符串长度为:" + len); // 12