深入理解Java的==和equals
關係操作符==
關係操作符== ,適用於所有的基本資料型別,同時也適用於物件。
- == 用於基本資料型別,比較的是資料的值
Java中有8種基本資料型別,其中有4種整型(int ,short,long,byte)、2種浮點型別(float,double)、1種用於表示Unicode編碼的字元單元的字元型別char和1種用於表示真值的boolean型別。
下面對基本資料型別進行相等性測試:
public class Test {
public static void main(String[] args) {
boolean b1 = true;
boolean b2 = true;
System.out.println("b1 == b2: "+(b1==b2));
char c1 = 'c';
char c2 = 'c';
System.out.println("c1 == c2: "+(c1==c2));
byte by1 = 1;
byte by2 =1;
System.out.println("by1 == by2: "+(by1==by2));
short sh1 = 2;
short sh2 =2;
System.out.println("sh1 == sh2: "+(sh1==sh2));
int n1 = 1;
int n2 =1;
System.out.println("n1 == n2: "+(n1==n2));
long l1 = 1L;
long l2 = 1L;
System.out.println("l1 == l2: "+(l1==l2));
float f1 =1F;
float f2 = 1F;
System.out.println("f1 == f2: "+(f1==f2));
double d1 = 3.14;
double d2 = 3.14;
System.out.println("d1 == d2: "+(d1==d2));
}
}
結果如下:
b1 == b2: true
c1 == c2: true
by1 == by2: true
sh1 == sh2: true
n1 == n2: true
l1 == l2: true
f1 == f2: true
d1 == d2: true
上面的測試都是對同一型別的值進行比較(如 by1與by2都是byte型別的整數)
如果,我們對不同型別的數字進行比較會得出什麼結果?
public class Test {
public static void main(String[] args) {
int n= 100;
byte b = 100;
long l = 100L;
short s = 100;
System.out.println("n==b: "+ (n==b));
System.out.println("b==l: "+ (b==l));
System.out.println("l==s: "+(l==s));
float f1 = 3.14F;
float f2 =100F;
double d1 = 3.14;
double d2 = 100;
System.out.println("f1==d1: "+(f1==d1));
System.out.println("f2==n: "+(f2==n));
System.out.println("d2==n:"+(d2==n));
}
}
結果:
n==b: true
b==l: true
l==s: true
f1==d1: false
f2==n: true
d2==n:true
結論:
1、不同型別的整數之間可以進行相等性比較。
2、不同型別的小數之間不要使用==比較,因為精度不同。
3、 整數和小數可以進行相等性比較,整數會自動轉成相應的浮點型別。
- == 用於物件,比較的是物件的引用
先看個下面這個例子,建立兩個字串物件s1和s2,然後進行相等性比較。
public class Test {
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2);
}
}
結果: false
雖然s1和s2的值相等,但是s1和s2的引用卻是不同時的,這是兩個物件,因此返回false。
接下來看個奇怪的問題:
public class Test {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);
}
}
你猜出正確結果嗎?
你可能會想,這不是生成了兩個字串嗎,一定是不相等的。
輸出結果是:
true
這是為什麼?
原因是:在java中,字串是不可修改的,是不可變的。修改字串實際是將變數引用了新的字串。不可變字串有個優點:編譯器可以讓字串共享。
上面的程式碼可以這麼理解:當建立s1時,儲存池放置了一個字串,當建立s2時,發現建立的是同樣的字串,就不再放入字串了,因為這樣會重複,所以s2就直接引用了儲存池中已經存在的字串。
如果s1改變了,那麼儲存池就會再放入一個新字串,這時候,s1,s2指向的字串地址就不一樣了。
- ==用於包裝器物件
public class Test {
public static void main(String[] args) {
Integer a =1000;
Integer b=1000;
System.out.println(a==b);
Integer c =100;
Integer d=100;
System.out.println(c==d);
}
}
執行結果:
false
true
出現這種現象的原因是:自動裝箱規範要求boolean、byte、char<=127,介於-128~127之間的short和int被包裝到固定的物件中。
因此,在比較兩個包裝器物件時呼叫equals方法。
equals方法
equals方法適用於物件,而不能用於基本資料型別。
- 自定義類的例項物件equals操作
class Person{}
public class Test {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.equals(p2));
}
}
結果是:
false
Java中所有類都預設繼承Object,而Object類中的equals方法會判斷兩個物件是否具有相同的引用。如果兩個物件具有相同的引用,它們一定是相等的。因此,兩個物件的equals操作預設是比較引用。
Object類中的equals原始碼如下所示:
public boolean equals(Object obj) {
return (this == obj);
}
- 字串的equals操作
public class Test {
public static void main(String[] args) {
String s1 = "noshower";
String s2 = "noshower";
System.out.println(s1.equals(s2));
}
}
結果如下:
true
String的equals方法重寫了,覆蓋了Object類的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;
}
從原始碼中可以看出String類的equals方法,先是比較兩個變數是否指向同一個引用,如果是,直接返回相等。如果不是,就要判斷equals括號內的變數,是否是String的例項,如果不是直接返回不相等。如果是String的例項,就比較兩個變數代表的字串長度是否相等,如果不相等就返回不相等的結果。如果長度相等,就把字串轉成char陣列,比較每個字元是否相等。如果都相等,就返回相等的結果。如果有一個字元不相等,就返回不相等的結果。
由此我們可以得出,String的equals方法對相同引用的變數和不同引用,但是值相等的變數,都返回true。
我們再來看一個有趣的問題:
public class Test {
public static void main(String[] args) {
String s = "noshower";
System.out.println(s+"2" == "noshower2");
System.out.println("noshower2".equals(s+"2"));
}
}
結果如下:
false
true
這是為什麼呢?
如果兩個字串放置在同一個位置上,它們必然相等。但是,完全有可能將內容相同的多個字串的拷貝放置在不同的位置上。所以s+"2" 與"noshower2"放置在不同的位置。
實際上,只有字串常量是共享的,而+或substring等操作產生的結果並不是共享的。
因此,千萬千萬不要用==測試字串的相等性
- 基本型別的包裝類equals
這裡只舉例Integer包裝類,因為其他包裝類的實現邏輯都是一樣的。都是先比較某個變數是不是這個包裝類的例項,如果不是,返回false。否則,比較值是否相等。如果相等,就返回true。否則返回false。
public class Test {
public static void main(String[] args) {
Integer n1 =new Integer(47);
Integer n2 =new Integer(47);
System.out.println(n1==n2);
System.out.println(n1.equals(n2));
}
}
結果如下:
false
true
不是同一個引用,所以==返回false。值相等,所以equals返回true。
Integer類equals方法原始碼如下:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
正如我上面所說的,先比較是不是同一個型別,再比較值是否相等。
其他幾個包裝類就不一一講述了。這裡貼上,它們的equals原始碼。
Short
public boolean equals(Object obj) {
if (obj instanceof Short) {
return value == ((Short)obj).shortValue();
}
return false;
}
Long
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
Byte
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
Float
public boolean equals(Object obj) {
return (obj instanceof Float)
&& (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}
Double
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
Character
public boolean equals(Object obj) {
if (obj instanceof Character) {
return value == ((Character)obj).charValue();
}
return false;
}
Boolean
public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}
完畢!!
相關文章
- 深入理解equals和==的區別
- 深入探究Java中equals()和==的區別是什麼Java
- java == 和equalsJava
- 『Java 語法基礎』對 equals() 和 hashCode() 的理解Java
- 【Java】equals 和 == 的區別Java
- 深入理解Java的介面和抽象類Java抽象
- java 中equals和==的區別Java
- Java中equals和==的區別Java
- Java equals 和 == 完全解析Java
- Java equals和==完全解析Java
- 從原始碼探究JAVA的equals和==原始碼Java
- Java中 equals() 方法和 == 的區別Java
- 在java中“equals”和“==”的區別Java
- Java備忘錄《“==” 和 “equals”》Java
- 深入理解java中的組合和繼承Java繼承
- 深入理解java的抽象類和介面(轉載)Java抽象
- Java中HashMap和TreeMap的區別深入理解JavaHashMap
- 深入理解 Java 反射和動態代理Java反射
- Java中Thread 和Runnable 深入理解Javathread
- Java中equals和==比的是什麼Java
- java equalsJava
- java - equals()Java
- 搞懂 Java equals 和 hashCode 方法Java
- java~重寫hashcode和equalsJava
- Java基礎- ==和equals和hashCode的區別Java
- JAVA基礎(一)equals和==和hashCodeJava
- 深入理解Java中的鎖Java
- 深入理解 Java 中的 LambdaJava
- 深入理解Java中的AQSJavaAQS
- 深入探討、理解Java的CLASSPATHJava
- 關於HashMap的key重寫hashcode和equals的理解HashMap
- 深入理解Java PriorityQueueJava
- 深入理解 Java 方法Java
- 深入理解Java反射Java反射
- Java:IO:深入理解Java
- 深入理解Java HelloWorldJava
- Java經典面試題: == 和 equals( )的區別Java面試題
- Java物件之間的比較之equals和==Java物件