0%
这是一片思考的空间 -- arthinking
Spring 重构&代码整洁之道 软件设计 JVM 并发编程 数据结构与算法 分布式 存储 网络 微服务 设计模式
Java技术栈 - 涉及Java技术体系

Java基础笔记 - String字符串详解 字符串实现原理 StringBuffer

1、String类的equals方法:

String类的equals方法继承自Object类,但是由于重写了,所以实现了不一样的功能。 首先看到Object类的equals方法:

1.1、Object类的equals方法:

equals
public boolean equals(Object obj)

指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:

  • 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
  • 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
  • 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
  • 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
  • 对于任何非空引用值 x,x.equals(null) 都应返回 false。

查看该方法的源代码如下:

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

可以发现,Object类的equals方法使用了“==”判断,其功能是判断了比较的两个对象的引用地址是不是一样,判断是不是同一个对象。

下面看String类的equals方法。

1.2、String类的equals方法:

equals
public boolean equals(Object anObject)

将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。
覆盖:
类 Object 中的 equals
参数:
anObject - 与此 String 进行比较的对象。
返回:
如果给定对象表示的 String 与此 String 相等,则返回 true;否则返回 false。
另请参见:

compareTo(String), equalsIgnoreCase(String)

该方法的源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}

可以发现,如果判断的不是同一个对象,继续判断比较的对象是不是Strinig类的实例,如果是的话就按照字符串的字面值进行判断,如果字面值相等,则返回true。

1.3、总结:

Object类中的equals方法判断两个引用是否一致,里面只是使用了==进行判断,等价于==。

String类的equals方法判断当前字符串与传进来的字符串的内容是否一致。

所以一般判断字符串相等都是用equals方法,而不使用==。

2、equals()方法重写的例子:

模仿String类的equals()方法实现,给一个类重写equals()方法实现特殊的比较规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A{
private String id;
public A(String id){
this.id = id;
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
} else if(obj instanceof A){
A a = (A)obj;
if(a.id.equals(this.id)){
return true;
}
}
return false;
}
}

3、String字符串详解:

public final class String
extends Object
implements Serializable, Comparable, CharSequence

String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。例如:

1
String str = "abc";

等效于:

1
2
char data[] = {'a', 'b', 'c'};
String str = new String(data);

3.1、拼接字符串时创建对象:

当使用+号拼接字符串时,会生成新的String对象,而不是向原有的String对象追加内容。

3.2、创建String对象的两种方法:

① 直接采用字符串赋值方式:

1
String str = “abc”;

首先查找String Pool中是否存在“abc”这个字符串对象,如果不存在,则在字符串池中创建该对象,并将String Pool中的该对象的地址返回来,赋给引用变量str。

如果存在,则不创建任何对象,而是直接把String Pool中的该对象地址返回并赋给str引用。

② 使用new关键字创建String:

1
String str = new String(“abc”);

如果在String Pool中存在“abc”这个字符串对象,则在队中创建“abc”字符串对象,然后将堆中的该对象地址返回并赋给str引用。

如果在String Pool中不存在“abc”字符串对象,则首先在String Pool中创建“abc”字符串对象,然后再在堆中创建一个,并返回队中的该对象地址,赋给str引用。

3.3、intern方法:

intern
public String intern()

返回字符串对象的规范化表示形式。

一个初始为空的字符串池,它由类 String 私有地维护。

当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。

它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作。字符串字面值在 Java Language Specification 的 §3.10.5 定义。

返回:
一个字符串,内容与此字符串相同,但一定取自具有唯一字符串的池。

4、StringBuffer类:

public final class StringBuffer
extends Object
implements Serializable, CharSequence

线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。

可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符添加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。从 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

欢迎关注我的其它发布渠道

订阅IT宅
内功修炼
Java技术栈
Java架构杂谈是IT宅精品文章公众号,欢迎订阅:
📄 网络基础知识:两万字长文50+张趣图带你领悟网络编程的内功心法 📄 HTTP发展史:三万长文50+趣图带你领悟web编程的内功心法 📄 HTTP/1.1:可扩展,可靠性,请求应答,无状态,明文传输 📄 HTTP/1.1报文详解:Method,URI,URL,消息头,消息体,状态行 📄 HTTP常用请求头大揭秘 📄 HTTPS:网络安全攻坚战 📄 HTTP/2:网络安全传输的快车道 📄 HTTP/3:让传输效率再一次起飞 📄 高性能网络编程:图解Socket核心内幕以及五大IO模型 📄 高性能网络编程:三分钟短文快速了解信号驱动式IO 📄 高性能网络编程:彻底弄懂IO复用 - IO处理杀手锏,带您深入了解select,poll,epoll 📄 高性能网络编程:异步IO:新时代的IO处理利器 📄 高性能网络编程:网络编程范式 - 高性能服务器就这么回事 📄 高性能网络编程:性能追击 - 万字长文30+图揭秘8大主流服务器程序线程模型
📄 Java内存模型:如果有人给你撕逼Java内存模型,就把这些问题甩给他 📄 一文带你彻底理解同步和锁的本质(干货) 📄 AQS与并发包中锁的通用实现 📄 ReentrantLock介绍与使用 📄 ReentrantReadWriteLock介绍与使用 📄 ReentrantLock的Condition原理解析 📄 如何优雅的中断线程 📄 如何优雅的挂起线程 📄 图解几个好玩的并发辅助工具类 📄 图解BlockingQueue阻塞队列
📄 消息队列那么多,为什么建议深入了解下RabbitMQ? 📄 高并发异步解耦利器:RocketMQ究竟强在哪里? 📄 Kafka必知必会18问:30+图带您看透Kafka
📄 洞悉MySQL底层架构:游走在缓冲与磁盘之间 📄 SQL运行内幕:从执行原理看调优的本质 📄 洞悉Redis技术内幕:缓存,数据结构,并发,集群与算法