个人博客 https://raptor1998.top/
概述
在理解String类之前,需要了解java内存的栈(对象引用)、堆(对象本身)和方法区(共享数据区,常量池等)等。此处不做赘述。
==与equals方法的比较
==操作符
- 引用类型比较引用(是否指向同一个对象)
- 基本类型比较值
equals()
- 是Object类的方法,由于所有类都继承Object类,也就继承了equals()方法。只能比较引用类型。在Object类的定义中,其作用与“==”相同,比较是否指向同一个对象。
- 注意:对类File、String、Date、封装类(Wrapper Class)及很多重写了equals()方法的类来说,是比较类型及内容而不考虑引用是否指向同一个对象
equals源码
public boolean equals(Object obj) {
return (this == obj);
}
demo1
Student student1 = new Student();
Student student2 = new Student();
System.out.println(student1 + "\n" + student2);// com.raptor.entity.Student@106d69c
// com.raptor.entity.Student@52e922
System.out.println(student1 == student2);// false
System.out.println(student1.equals(student2));// false
String重写的equals()
重写后的方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
案例分析
demo1:String创建
String newS1 = new String("hello");
String newS2 = new String("hello");
String ss1 = "hello";
String ss2 = "hello";
System.out.println("ss1==ss2是" + (ss1 == ss2));//true
System.out.println("ss1==newS1是" + (ss1 == newS1));//false
System.out.println("newS1==newS2是" + (newS1 == newS2));//false
demo1内存分析
- 使用直接赋值,即ss1和ss2方式创建字符串常量时。JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就将此字符串对象的地址赋值给引用ss1和ss2。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中,并将此字符串对象的地址赋值给引用ss1和ss2。
- 使用new关键字创建字符串常量时。JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么不再在字符串常量池创建该字符串对象,而直接堆中复制该对象的副本,然后将堆中对象的地址赋值给引用newS1,newS2,如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中,然后在堆中复制该对象的副本,然后将堆中对象的地址赋值给引用newS1,newS2。
demo2:String类型拼接
String类的引用可以指向不同的字符串,这是因为字符串对象虽然是不能修改的, 但是它们的地址可以共享。
java中String类型不可变,‘+’的实现:jvm复制了一份“hello”对象与“world”做拼接,并没有改变原来的“hello”的值。
String s = "hello";
s+="world";
System.out.println(s); //helloworld