關系操作符==
關系操作符== ,適用于所有的基本數據類型,同時也適用于對象。
- == 用于基本數據類型,比較的是數據的值
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;
}
完畢??!