在之前的源码阅读中,看到了一个挺眼熟的关键词instanceof
,却一下子没反应过来是用来做类比较的,包括判断是不是子类。
突然意识到其实有很多做比较的方式都被我所忽略了,绝不仅仅只有==
、!=
、equals
这些。
基本数据类型的比较方式
基本数据类型的比较使用==
、!=
、<
、>
、>=
、<=
这些基本的比较符号,char
类型、boolean
类型在被编译成字节码文件的时候被转换为int
类型。
public class Test {
public static void main(String[] args) {
int a = 50;
char b = 'a';
boolean c = true;
boolean d = false;
}
}
D:\>javap -c Test.class
Compiled from "Test.java"
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 50
2: istore_1
3: bipush 97
5: istore_2
6: iconst_1
7: istore_3
8: iconst_0
9: istore 4
11: return
}
基本数据类型的包装类的比较方式
每一种基本类型都有与之对应的包装类,例如int
类型的包装类是Integer
类、char
类型的包装类是Character
类。
Equals
包装类的比较可以使用equals(Object obj)
方法,返回值为一个boolean
类型,true
和false
分别代表相等
和不相等
,比较的是包装的值。
以Character
类为例:
/**
* Compares this object against the specified object.
* The result is {@code true} if and only if the argument is not
* {@code null} and is a {@code Character} object that
* represents the same {@code char} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Character) {
return value == ((Character)obj).charValue();
}
return false;
}
CompareTo
包装类还提供了一种比较方式:compareTo(包装类 another包装类)
方法,该方法继承于Comparable<T>
接口。
Byte
类、Short
类、Character
类返回的是做比较的两个数的差值。
以Byte
类为例:
/**
* Compares two {@code Byte} objects numerically.
*
* @param anotherByte the {@code Byte} to be compared.
* @return the value {@code 0} if this {@code Byte} is
* equal to the argument {@code Byte}; a value less than
* {@code 0} if this {@code Byte} is numerically less
* than the argument {@code Byte}; and a value greater than
* {@code 0} if this {@code Byte} is numerically
* greater than the argument {@code Byte} (signed
* comparison).
* @since 1.2
*/
public int compareTo(Byte anotherByte) {
return compare(this.value, anotherByte.value);
}
/**
* Compares two {@code byte} values numerically.
* The value returned is identical to what would be returned by:
* <pre>
* Byte.valueOf(x).compareTo(Byte.valueOf(y))
* </pre>
*
* @param x the first {@code byte} to compare
* @param y the second {@code byte} to compare
* @return the value {@code 0} if {@code x == y};
* a value less than {@code 0} if {@code x < y}; and
* a value greater than {@code 0} if {@code x > y}
* @since 1.7
*/
public static int compare(byte x, byte y) {
return x - y;
}
Integer
类、Long
类返回的是-1
、0
、1
,分别代表小于
、等于
、大于
。
以Integer
为例:
/**
* Compares two {@code Integer} objects numerically.
*
* @param anotherInteger the {@code Integer} to be compared.
* @return the value {@code 0} if this {@code Integer} is
* equal to the argument {@code Integer}; a value less than
* {@code 0} if this {@code Integer} is numerically less
* than the argument {@code Integer}; and a value greater
* than {@code 0} if this {@code Integer} is numerically
* greater than the argument {@code Integer} (signed
* comparison).
* @since 1.2
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
/**
* Compares two {@code int} values numerically.
* The value returned is identical to what would be returned by:
* <pre>
* Integer.valueOf(x).compareTo(Integer.valueOf(y))
* </pre>
*
* @param x the first {@code int} to compare
* @param y the second {@code int} to compare
* @return the value {@code 0} if {@code x == y};
* a value less than {@code 0} if {@code x < y}; and
* a value greater than {@code 0} if {@code x > y}
* @since 1.7
*/
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
Float
类、Double
类返回的也是-1
、0
、1
,与Integer
类和Long
类所不同的是,Float
类和Double
类中该方法需要分参数值不存在NaN (Not a Number,非数,是计算机科学中数值数据类型的一个值,表示未定义或不可表示的值)
和参数值存在NaN
两种情况讨论,如果为NaN
,那么需要将参数值格式化为IEEE 754 floating-point
形式后再做比较,返回值的含义和Integer
类相同。
以Double
类为例:
/**
* Compares two {@code Double} objects numerically. There
* are two ways in which comparisons performed by this method
* differ from those performed by the Java language numerical
* comparison operators ({@code <, <=, ==, >=, >})
* when applied to primitive {@code double} values:
* <ul><li>
* {@code Double.NaN} is considered by this method
* to be equal to itself and greater than all other
* {@code double} values (including
* {@code Double.POSITIVE_INFINITY}).
* <li>
* {@code 0.0d} is considered by this method to be greater
* than {@code -0.0d}.
* </ul>
* This ensures that the <i>natural ordering</i> of
* {@code Double} objects imposed by this method is <i>consistent
* with equals</i>.
*
* @param anotherDouble the {@code Double} to be compared.
* @return the value {@code 0} if {@code anotherDouble} is
* numerically equal to this {@code Double}; a value
* less than {@code 0} if this {@code Double}
* is numerically less than {@code anotherDouble};
* and a value greater than {@code 0} if this
* {@code Double} is numerically greater than
* {@code anotherDouble}.
*
* @since 1.2
*/
public int compareTo(Double anotherDouble) {
return Double.compare(value, anotherDouble.value);
}
/**
* Compares the two specified {@code double} values. The sign
* of the integer value returned is the same as that of the
* integer that would be returned by the call:
* <pre>
* new Double(d1).compareTo(new Double(d2))
* </pre>
*
* @param d1 the first {@code double} to compare
* @param d2 the second {@code double} to compare
* @return the value {@code 0} if {@code d1} is
* numerically equal to {@code d2}; a value less than
* {@code 0} if {@code d1} is numerically less than
* {@code d2}; and a value greater than {@code 0}
* if {@code d1} is numerically greater than
* {@code d2}.
* @since 1.4
*/
public static int compare(double d1, double d2) {
if (d1 < d2)
return -1; // Neither val is NaN, thisVal is smaller
if (d1 > d2)
return 1; // Neither val is NaN, thisVal is larger
// Cannot use doubleToRawLongBits because of possibility of NaNs.
long thisBits = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
/**
* Returns a representation of the specified floating-point value
* according to the IEEE 754 floating-point "double
* format" bit layout.
*
* <p>Bit 63 (the bit that is selected by the mask
* {@code 0x8000000000000000L}) represents the sign of the
* floating-point number. Bits
* 62-52 (the bits that are selected by the mask
* {@code 0x7ff0000000000000L}) represent the exponent. Bits 51-0
* (the bits that are selected by the mask
* {@code 0x000fffffffffffffL}) represent the significand
* (sometimes called the mantissa) of the floating-point number.
*
* <p>If the argument is positive infinity, the result is
* {@code 0x7ff0000000000000L}.
*
* <p>If the argument is negative infinity, the result is
* {@code 0xfff0000000000000L}.
*
* <p>If the argument is NaN, the result is
* {@code 0x7ff8000000000000L}.
*
* <p>In all cases, the result is a {@code long} integer that, when
* given to the {@link #longBitsToDouble(long)} method, will produce a
* floating-point value the same as the argument to
* {@code doubleToLongBits} (except all NaN values are
* collapsed to a single "canonical" NaN value).
*
* @param value a {@code double} precision floating-point number.
* @return the bits that represent the floating-point number.
*/
public static long doubleToLongBits(double value) {
long result = doubleToRawLongBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
DoubleConsts.EXP_BIT_MASK) &&
(result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
result = 0x7ff8000000000000L;
return result;
}
Boolean
类返回的依然是-1
、0
、1
,但是又有所不同
- 当相等时,返回
0
; - 当不相等时:
- 调用
compareTo(Boolean b)
者的值为true
,返回1
; - 调用
compareTo(Boolean b)
者的值为false
,返回-1
。
- 调用
/**
* Compares this {@code Boolean} instance with another.
*
* @param b the {@code Boolean} instance to be compared
* @return zero if this object represents the same boolean value as the
* argument; a positive value if this object represents true
* and the argument represents false; and a negative value if
* this object represents false and the argument represents true
* @throws NullPointerException if the argument is {@code null}
* @see Comparable
* @since 1.5
*/
public int compareTo(Boolean b) {
return compare(this.value, b.value);
}
/**
* Compares two {@code boolean} values.
* The value returned is identical to what would be returned by:
* <pre>
* Boolean.valueOf(x).compareTo(Boolean.valueOf(y))
* </pre>
*
* @param x the first {@code boolean} to compare
* @param y the second {@code boolean} to compare
* @return the value {@code 0} if {@code x == y};
* a value less than {@code 0} if {@code !x && y}; and
* a value greater than {@code 0} if {@code x && !y}
* @since 1.7
*/
public static int compare(boolean x, boolean y) {
return (x == y) ? 0 : (x ? 1 : -1);
}
基本数据类型和包装类的比较方式
Equals
equals(Object obj)
方法也可以传入基本数据类型参数,而且在书写的时候,可以传入任意类型的参数,但是在运行的时候却会发现例如Integer
类型的97
和char
类型的'a'
并不相等,根本原因就是虽然方法接受任意类型的参数,但是在方法体内会对参数的类型进行判断,所以我们应该自己注意参数的基本数据类型必须和调用方法的包装类是对应关系。
以Integer
类为例:
/**
* Compares this object to the specified object. The result is
* {@code true} if and only if the argument is not
* {@code null} and is an {@code Integer} object that
* contains the same {@code int} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
CompareTo
compareTo(包装类 another包装类)
方法同样也可以传入基本数据类型参数,包装类会自动执行装箱
操作,但是需要注意的是,参数的基本数据类型必须和调用方法的包装类是对应关系。
以Long
类为例:
public class BaseTest {
public static void main(String argc[]) {
Long chara = new Long(5L);
System.out.println(chara.compareTo(10L));
}
}
符号比较
因为包装类有自动拆箱的特性,因此可以完全适用==
、!=
、<
、>
、>=
、<=
这些基本的比较符号的比较规则。
String类的比较方式
String
类型如果直接使用比较符号,比较的是引用的地址的值,而不是内容的值。
public class Test {
public static void main(String[] args) {
String a = "abcd";
String b = "abcd";
String c = new String("abcd");
System.out.println(a == b);
System.out.println(a == c);
}
}
true
false
如果要比较内容的值,我们依然需要使用equals(Object anObject)
方法。
public class Test {
public static void main(String[] args) {
String a = "abcd";
String b = "abcd";
String c = new String("abcd");
System.out.println(a.equals(b));
System.out.println(a.equals(c));
}
}
true
true
除此之外,String
类还提供了很多种比较方式,将会在深入String类中学习。
对象的类型比较方式
类型的比较方式有instanceof
关键字和getClass()
方法这两种。
用instanceof
关键字对类型进行比较的时候,会考虑继承方面的关系。
子类对象和父类类型做类型比较时,结果是true;
而父类对象和子类类型做类型比较时,结果则是false;
用getClass()
方法对类型进行比较的时候,不会考虑继承方面的关系。
public class Parent {
}
public class Children extends Parent {
}
public class Test {
private static void print(Object parent, Object children) {
System.out.println("parent instanceof Parent: " + (parent instanceof Parent));
System.out.println("parent instanceof Children: " + (parent instanceof Children));
System.out.println("children instanceof Parent: " + (children instanceof Parent));
System.out.println("children instanceof Children: " + (children instanceof Children));
System.out.println("-----------------------------------");
System.out.println("parent getClass Parent: " + (parent.getClass() == Parent.class));
System.out.println("parent getClass Children: " + (parent.getClass() == Children.class));
System.out.println("children getClass Parent: " + (children.getClass() == Parent.class));
System.out.println("children getClass Children: " + (children.getClass() == Children.class));
}
public static void main(String[] args) {
Parent parent = new Parent();
Children children = new Children();
Test.print(parent, children);
}
}
parent instanceof Parent: true
parent instanceof Children: false
children instanceof Parent: true
children instanceof Children: true
-----------------------------------
parent getClass Parent: true
parent getClass Children: false
children getClass Parent: false
children getClass Children: true