Object
指示其他某个对象是否“等于”这个对象。
equals方法在非空对象引用上实现等价关系:
- 它是自反的:对于任何非空引用值x , x.equals(x)应该返回true 。
- 它是对称的:对于任何非空引用值x和y , x.equals(y)应返回true当且仅当y.equals(x)返回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 。
Object类的equals方法实现了Object上最有区别的可能等价关系; 也就是说,对于任何非空引用值x和y ,当且仅当x和y引用同一个对象( x == y的值为true )时,此方法才返回true 。
请注意,每当重写此方法时,通常都需要重写hashCode方法,以维护hashCode方法的一般约定,即相等的对象必须具有相等的哈希码。
public boolean equals(Object obj) {
return (this == obj);
}
Byte
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
public byte byteValue() {
return value;
}
Character
equals 变形
public int compareTo(Character anotherCharacter) {
return compare(this.value, anotherCharacter.value);
}
public static int compare(char x, char y) {
return x - y;
}
如果x == y ,则值为0 ; 如果x < y则小于0的值; 如果x > y则值大于0
Short
public boolean equals(Object obj) {
if (obj instanceof Short) {
return value == ((Short)obj).shortValue();
}
return false;
}
public short shortValue() {
return value;
}
private final short value;
Short 是建立在 short 的基础上。所以称呼他为包装类。
还记得 io
模块的处理流吗,处理流采用装饰器设计模式,建立在节点流的基础上。
Integer
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public int intValue() {
return value;
}
Long
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
public long longValue() {
return value;
}
Float
public boolean equals(Object obj) {
return (obj instanceof Float)
&& (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}
public static int floatToIntBits(float value) {
int result = floatToRawIntBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & FloatConsts.EXP_BIT_MASK) ==
FloatConsts.EXP_BIT_MASK) &&
(result & FloatConsts.SIGNIF_BIT_MASK) != 0)
result = 0x7fc00000;
return result;
}
public static final int EXP_BIT_MASK = 2139095040;
public static native int floatToRawIntBits(float value);
根据 IEEE 754 浮点“单一格式”位布局返回指定浮点值的表示形式。
第 31 位(由掩码0x80000000选择的位)表示浮点数的符号。 位 30-23(由掩码0x7f800000选择的位)表示指数。 位 22-0(由掩码0x007fffff选择的位)表示0x007fffff的有效数(有时称为尾数)。
如果参数为正无穷大,则结果为0x7f800000 。
如果参数为负无穷大,则结果为0xff800000 。
如果参数为 NaN,则结果为0x7fc00000 。
在所有情况下,结果都是一个整数,当将其提供给intBitsToFloat(int)方法时,将产生与floatToIntBits的参数相同的浮点值(除了所有 NaN 值都折叠为单个“规范”NaN 值)
Double
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
float 和 double 看看就好。
String
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 很简单,最重要的是要知道他是建立在 char [] 的基础上。
他也提供了一个简洁优秀的 equals 模板:
- 比较对象的引用是否相同
- instance of 判断是否是同一个类
- 再去判断他的 核心 value (也就是你希望用来作为比较标准的成员变量)
Arrays
- byte[]
public static boolean equals(byte[] a, byte[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false;
return true;
}
为何 String 就没有比较 null 呢! 因为 String 是 “str”.equals(“other”),
调用这个方法的时候已经决定了调用者不能为 null,否则空指针异常。
数组没有使用 instance of 运算符,因为它在参数上已经限制了。
为何 String 的参数没有用 String 呢!因为 String 进行强制类型转换方便,而数组则很不方便。甚至很多方法的方法体都是一样的。
- char
public static boolean equals(char[] a, char[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false;
return true;
}
- int
public static boolean equals(int[] a, int[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false;
return true;
}
- Object
public static boolean equals(Object[] a, Object[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++) {
Object o1 = a[i];
Object o2 = a2[i];
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return true;
}
别的几个都是这样,也说明了 给数组进行类型转换不划算。
同时,我们也可以学到,写一个函数的时候大概分三部分:
- 特殊情况的处理
- 正常情况的处理
- 返回结果
Collection
数组因为类型转换不方便,所以相同的方法体,他为八个基本数据类型都写了重载方法。
但是 Collection 的元素更丰富了,所以就没有重写这个方法。