Java中 == 与 equals方法的异同
首先明确一点:java中的变量被分为基本数据类型和引用数据类型(Variables in Java are classified into primitive and reference variables.)
基本数据类型/变量(primitive type)包括:
浮点型:float(4 byte), double(8 byte)
整型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)
字符型: char(2 byte)
布尔型: boolean(JVM规范没有明确规定其所占的空间大小,仅规定其只能够取字面值"true"和"false")
而引用数据类型/变量(reference variables)包括:
String类,Date类和自己定义的类对象等。
其次,java的存储机制可以简单的分为两部分,一部分是栈(stack),而另一部分为堆(heap)。
其中,栈中存储所有的局部变量,包括参数还有调用方法时的栈帧;而堆存储所有的对象,包括数组以及类变量
(图片来源于UCB 61B)
== :
对于基本数据类型:
由于局部变量存储在栈中,且存储的就是数值,而不是对对象的引用,
所以 == 比较的就是数值本身是否相等。而由于基本数据类型并没有equals方法,所以若使用primitive type调用equals方法会报错。
比如:
int n=3;
int m=3;
System.out.println(n==m); // 结果为 true
System.out.println(n.equals(m)); //会直接报错
对于引用类型:
== 比较的是变量所引用的对象的地址是否相等,其中变量存在栈中,而对象存储在堆中,比如:
String str1 = new String("123");
String str2 = new String("123");
System.out.println(str1==str2); //结果会为false
str1 = str2;
System.out.println(str1==str2); //结果会为true
对于第一个结果会为false,有如下讲解:
String str1 这句话声明了一个引用类型的变量,此时它并没有和任何对象关联。而通过new String(“123”)来产生一个对象,并将str1引用了这个对象:
str1= new String(“hello”);
那么str1指向了一个对象,此时变量str1中存储的是它指向的对象在内存中的存储地址,并不是“值”本身。
对于第二个结果为true, 因为str1 = str2 表明将str2的引用也赋给了str1,它们现在都在指向str2所引用的对象,所以他们所引用的对象地址相同,结果为true。
equals方法:
对于基本数据类型:
前面已经讲解了,基本数据类型不具有equals方法。
对于引用类型:
- 对于自己定义的类对象,equals方法的使用是和 == 一样的,如下代码片段:
public class Test {
protected int number;
protected String name;
public Test(){}
public Test(int number,String name){
this.number = number;
this.name = name;
}
public static void main(String[] arg){
Test test1 = new Test(123,"name"); //初始化时对象的值不同
Test test2 = new Test(); //初始化时对象的值不同
test1 = test2; // 令test1和test2指向同一个对象
System.out.println(test1.equals(test1)); //由此可判断并不是判断是否对象中值相等
System.out.println(test1 == test2);
Test test3 = new Test(); //初始化时值均为空
Test test4 = new Test();//初始化时值均为空
System.out.println(test3.equals(test4));//但指向不同对象,所以还是为false
System.out.println(test3 == test4);
}
}
得到的结果是true, true, false , false。
如果需要使equals方法有其它的用途,我们可以将此方法进行重写。
- 有的人有疑问了,像String类型使用equals方法时,比较的就是两个String变量里的内容是否相等呀,比如如下的代码,输出的结果为true。
String str1 = new String("123");
String str2 = new String("123");
System.out.println(str1.equals(str2));
这是因为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;
}
重写之后,比较的就是两个字符串内容是否相等。
补充:
4 degrees of equality:
① Reference equality, just simple == equality
② Shallow structural equality: two objects may be not the same, but their fields have same reference(==)
③ Deep structural equality: two objects may be not the same, and their fields may not have same reference, but fields are equals() (*the equals() methods are usually overridden to compare the content in fields are equal) // can call recursively
Take single list for example:
public class SList{
private SListNode head;
private int size;
public SList(){
head = null;
size = 0;
}
public int getSize(){
return this.size;
}
public void insertFront(String item){
head = new SListNode(item,head);
size++;
}
public boolean equals(Object other){
if(!(other instanceof SList)){
return false;
}
SList o = (SList)other;
if(size != o.size){ // SList
return false;
}
SListNode n1 = head;
SListNode n2 = o.head;
while(n1 != null){
if(!n1.item.equals(n2.item)){
return false;
}
n1 = n1.next;
n2 = n2.next;
}
return true;
}
public static void main(String[] arg){
SList s1 = new SList();
s1.insertFront("2");
s1.insertFront("5");
System.out.println("size of s1: " + s1.getSize());
SList s2 = new SList();
s2.insertFront("2");
s2.insertFront("5");
System.out.println("size of s2: " + s2.getSize());
System.out.println("if s1 equals to s2 : " + s1.equals(s2)); // true
}
}
class SListNode {
String item;
SListNode next;
public SListNode(String item,SListNode next){
this.item = item;
this.next = next;
}
public SListNode(String item){
this(item,null);
}
public SListNode(){}
}
④ Logical equality: the same meaning of two different data structures
examples:
a) fractions 1/3 and 2/6
b) mathematical “set” objects are equals if they contain same elements(even stored in different orders)