In the previous source code reading, I saw a familiar keyword instanceof
, but I didn't realize that it was used for class comparison, including judging whether it was a subclass.
Suddenly I realized that there are actually many ways to make comparisons that I have overlooked, not just ==
, !=
, and equals
these.
How to compare primitive data types
The comparison of basic data types uses ==
, !=
, <
, >
, >=
, <=
these basic comparison symbols, and char
types and boolean
types are converted to types when they are compiled into bytecode files 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
}
How to compare wrapper classes for primitive data types
Each basic type has a corresponding wrapper class. For example int
, the wrapper class of a type is a Integer
class, and char
the wrapper class of a type is a Character
class.
Equals
The comparison of the wrapper class can use the equals(Object obj)
method, the return value is a boolean
type, true
and the sum false
represents 相等
and respectively 不相等
, and the comparison is the wrapped value.
Take a Character
class as an example:
/**
* 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
Wrapper classes also provide a way to compare: compareTo(包装类 another包装类)
methods, which inherit from Comparable<T>
interfaces.
Byte
class, Short
class, Character
class returns the difference between the two numbers being compared.
Take a Byte
class as an example:
/**
* 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
Class and Long
class return -1
, 0
, 1
, which represent 小于
, 等于
, respectively 大于
.
Take for Integer
example:
/**
* 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
Classes and Double
classes also return -1
, 0
, 1
. The difference between classes and Integer
classes is that the method in classes and classes needs to be discussed in two cases : the absence of parameter values and the existence of parameter values . If yes , then the parameter values need to be formatted as After comparing the form, the meaning of the return value is the same as that of the class.Long
Float
Double
NaN (Not a Number,非数,是计算机科学中数值数据类型的一个值,表示未定义或不可表示的值)
NaN
NaN
IEEE 754 floating-point
Integer
Take a Double
class as an example:
/**
* 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
The class returned is still -1
, 0
, 1
, but it is different
- When equal, return
0
; - When not equal:
- The value of the caller
compareTo(Boolean b)
istrue
, return1
; - The caller
compareTo(Boolean b)
's value isfalse
, return-1
.
- The value of the caller
/**
* 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);
}
How primitive data types and wrapper classes compare
Equals
equals(Object obj)
The method can also pass in basic data type parameters, and when writing, you can pass in parameters of any type , but when running, you will find that Integer
the type 97
and char
type are 'a'
not equal, the fundamental reason is that although the method accepts any type The parameters of the parameter, but the type of the parameter will be judged in the method body , so we should pay attention to the basic data type of the parameter must correspond to the wrapper class of the calling method .
Take a Integer
class as an example:
/**
* 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包装类)
The method can also pass in the basic data type parameter, and the wrapper class will automatically perform the 装箱
operation, but it should be noted that the basic data type of the parameter must correspond to the wrapper class that calls the method .
Take a Long
class as an example:
public class BaseTest {
public static void main(String argc[]) {
Long chara = new Long(5L);
System.out.println(chara.compareTo(10L));
}
}
Symbol comparison
Because the wrapper class has the feature of automatic unboxing, it can fully apply the comparison rules of ==
, !=
, <
, >
, >=
, <=
these basic comparison symbols.
How to compare String classes
String
If the type uses the comparison symbol directly, the value of the referenced address is compared, not the value of the content.
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
If we want to compare the value of the content , we still need to use equals(Object anObject)
methods.
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
In addition, the String
class also provides a variety of comparison methods, which will be learned in the in-depth String class.
How to compare the types of objects
There are two ways to compare types: instanceof
keywords and getClass()
methods.
Inheritance aspects areinstanceof
considered when comparing types using keywords.
When the subclass object is compared with the superclass type, the result is true;
When the parent class object and the child class type are compared, the result is false;
getClass()
When comparing types with methods, inheritance is not considered.
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