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。

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

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)

该方法的源代码如下:

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()方法实现特殊的比较规则:

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 对象是不可变的,所以可以共享。例如:
String str = “abc”;

等效于:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);

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

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

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

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

String str = “abc”;

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

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

② 使用new关键字创建String:

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 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

arthinking wechat
欢迎关注itzhai公众号