Public number: ByteCode, committed to sharing the latest technology original articles, involving Kotlin, Jetpack, translation, system source code, LeetCode/sabre-point Offer/multi-threading/domestic and foreign big factory algorithm and so on a series of articles.

I have written three articles to introduce Sealed Classes from different perspectives, including principles, optimizations, practices, and new features (Sealed interface).

  • The Kotlin seal class evolved
  • Sealed classes in Kotlin are superior to labeled classes
  • What’s Kotlin Sealed? Why does Google use it

In this article, we will analyze the difference between Kotlin operators == and ===, and the situations in which they are used. These operators are used very frequently in real projects and open source projects. The main contents are as follows:

  • In Java= =equalsThe difference between?
  • Operator provided by Kotlin= == = =What are they for?
    • Compare the structures of objects for equality (= =orequals )
    • Compare references to objects for equality (= = = )
  • The operators in Kotlin are used in the following scenarios
    • Basic data type
    • A wrapper class
    • Ordinary class
    • Data classes

Before we begin, let’s briefly review the difference between the Java operators == and equals.

The difference between Java operators == and equals

The operator = =

  • If the basic data type is compared to the value
  • If it is a reference data type, the comparison is the address

Operator equals

  • The default is not to overrideequalsMethod, is equivalent to= =, the comparison is the address
public boolean equals(Object obj) {
    return (this == obj);
}
Copy the code
  • rewriteequalsMethod is generally used to compare whether structures are equal, for exampleString
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; }Copy the code

However, it is important to note that when overriding equals, you need to override hashCode(), otherwise it will not work with the hash collection class. You can automatically generate equals(), hashCode(), toString(), and so on using shortcut keys.

  • Mac: Cmd + N
  • Win/Linux: Alt+Insert

See the following article for more tips on using AndroidStudio shortcuts:

  • Multi-platform AndroidStudio
  • Illustrated multi-platform AndroidStudio tips (part 2)
  • Multi-platform AndroidStudio tips (3)

So much for Java operators, let’s focus on Kotlin operators.

The Kotlin operators == and === and equals

Kotlin provides two ways to compare objects.

  • Compare the structure of objects for equality (== or equals)

    The equals operator in Kotlin is equivalent to equals, which is used to compare objects for equality. In many cases, equals is used because the equals implementation does not comply with the IEEE 754 floating-point standard for Float and Double.

  • Compare references to objects for equality (===)

    The Kotlin operator === is used to compare whether references to objects refer to the same object, and is equivalent to == at run time for the basic data type ===.

Now that we know the basic concepts, let’s look at how these operators (== and === and equals) are used in the following scenarios.

  • Basic data type
  • A wrapper class
  • Ordinary class
  • Data classes

Basic data type

Let’s start with an example:

val a1 = -0 val a2 = 0 println(a1 == a2) // true println(a1.equals(a2)) // true println(a1 === a2) // true a1 = 100 a2 =  100 println(a1 == a2) // true println(a1.equals(a2)) // true println(a1 === a2) // trueCopy the code

At runtime, the value (i.e., whether the structure of the object is equal) is equivalent to that of the base datatype ===. If === is used when comparing the base datatype, the compiler will give a warning that it is not recommended.

However, equals is special and has a different representation for Float and Double, as shown below.

val a3 = -0f
val a4 = 0f
println(a3 == a4)       // true
println(a3.equals(a4))  // false
println(a3 === a4)      // true
Copy the code

As you can see, a3.equals(A4) is false. To see why this happens, let’s take a look at what the decompiled Java code does. Tools → Kotlin → Show Kotlin Bytecode.

Float a3 = 0.0 F; Float a4 = 0.0 F; boolean var2 = Float.valueOf(a3).equals(a4); boolean var3 = false; System.out.println(var2);Copy the code

Convert float to the wrapper type float and call its equals method for comparison. Take a look at the equals method.

The result is as highlighted in the source comment, which compares +0.0f to -0.0f using the equals method to false and true using the == operator.

The floatToIntBits method is called in the equals method. In this method, according to the IEEE 754 floating-point algorithm standard, the floatToIntBits method returns the representation of the specified floating-point value. The result is an integer, as shown below:

System.out.println(Float.floatToIntBits(-0f)); // -2147483648 System.out.println(Float.floatToIntBits(0f)); / / 0Copy the code

As you can see, float. floatToIntBits(-0f) is calculated as the minimum value of the integer -2147483648. It does not comply with the IEEE 754 floating-point arithmetic standard. For more information, see IEEE 754 Floating Point Arithmetic Standards

For Float and Double, the equals implementation does not comply with the IEEE 754 floating-point arithmetic standard:

  • NaNIs considered equal to itself
  • NaNIs thought to be larger than any other element, including infinity
  • 0.0Less than+ 0.0

So be aware of this situation when using equals in Kotlin.

A wrapper class

There is a unique wrapper class for each of the basic types in both Java and Kotlin, but they are distinguished differently.

Basic data type A wrapper class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
val a5 = Integer(10) val a6 = Integer(10) println(a5 == a6) // true println(a5.equals(a6)) // true println(a5 === a6) //  falseCopy the code

Because the wrapper class overrides the equals method, using the equals operators compares the structure of an object to equals, so the result is true. The === operator compares a reference to an object, whether it refers to the same object, and because it’s a different object, the result is false.

Ordinary class

The normal class is just a new class that doesn’t override equals. Let’s take a look at the results of these three operators.

class Person1(val name: String, val age: Int)

val p1 = Person1(name = "hi-dhl", age = 10)
val p2 = Person1(name = "hi-dhl", age = 10)
println(p1 == p2)       // false
println(p1.equals(p2))  // false
println(p1 === p2)      // false

println(p1.name == p2.name)         // true
println(p1.name.equals(p2.name))    // true
println(p1.name === p2.name)        // true
Copy the code

Because the ordinary Person1 class does not implement equals, the result of the comparison with equals is false using the == operator, whereas p1 and P2 are different objects so the === operator results in false.

The name argument is of type String. As we have seen above, String overrides equals. The equals operator == compares to true. P1.name === P2.name = true because “hi-DHL” exists in the constant pool first. If there is, the reference in the constant pool is returned directly.

Data classes

Finally, let’s look at how these three operators behave in data classes.

data class Person2(val name: String, val age: Int)

val p3 = Person2(name = "ByteCode", age = 10)
val p4 = Person2(name = "ByteCode", age = 10)
println(p3 == p4)       // true
println(p3.equals(p4))  // true
println(p3 === p4)      // false

println(p3.name == p4.name)     // true
println(p3.name.equals(p4.name))// true
println(p3.name === p4.name)    // true
Copy the code

Because the compiler automatically generates equals, hashCode, toString, and so on based on the parameters in the data class, the compiled code looks like this.

public int hashCode() { String var10000 = this.name; return (var10000 ! = null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age); } public boolean equals(@Nullable Object var1) { if (this ! = var1) { if (var1 instanceof Person2) { Person2 var2 = (Person2)var1; if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) { return true; } } return false; } else { return true; }}Copy the code

So using the == and equals operators, the output will be true, but p3 and p4 are different objects so the result of the === operator will be false.

conclusion

Operators in Java

The operator = =

  • If the basic data type is compared to the value
  • If it is a reference data type, the comparison is the address

Operator equals

  • The default is not to overrideequalsMethod, is equivalent to= =, the comparison is the address
  • rewriteequalsMethod, often used to compare whether structures are equal, can be automatically generated by shortcut keysequals()hashCode()toString()And so on.
    • Mac: Cmd + N
    • Win/Linux: Alt+Insert

Operator in Kotlin

Kotlin provides two ways to compare objects.

  • Compare the structure of objects for equality (== or equals)

    The equals operator in Kotlin is equivalent to equals, which is used to compare objects for equality. In many cases, equals is used because the equals implementation does not comply with the IEEE 754 floating-point standard for Float and Double.

  • Compare references to objects for equality (===)

    The Kotlin operator === is used to compare whether references to objects refer to the same object, and is equivalent to == at run time for the basic data type ===.

That’s the end of the article. At the end of the article, I enclose a concise example. Can you tell the results of the following code without running the program?

class Person1(val name: String, val age: Int)
data class Person2(val name: String, val age: Int)

fun main() {
    val a1 = -0
    val a2 = 0
    println(a1 == a2)
    println(a1.equals(a2)

    val a3 = -0f
    val a4 = 0f
    println(a3 == a4)
    println(a3.equals(a4))

    //-------------

    val p1 = Person1(name = "hi-dhl", age = 10)
    val p2 = Person1(name = "hi-dhl", age = 10)
    println(p1 == p2)
    println(p1.equals(p2))
    println(p1 === p2)
    println(p1.name === p2.name)

    //-------------

    val p3 = Person2(name = "ByteCode", age = 10)
    val p4 = Person2(name = "ByteCode", age = 10)
    println(p3 == p4)
    println(p3.equals(p4))
    println(p3 === p4)
    println(p3.name === p4.name)

}
Copy the code

The running result is as follows:

a1 == a2 true a1.equals(a2) true a3 == a4 true a3.equals(a4) false -------------------------- p1 == p2 false p1.equals(p2) false p1 === p2 false p1.name === p2.name true -------------------------- p3 == p4 true p3.equals(p4) true  p3 === p4) false p3.name === p4.name trueCopy the code


If it helps, a “like” is the biggest encouragement to me

The code doesn’t stop, the article doesn’t stop

Welcome to the public account: ByteCode, continue to share the latest technology



Finally, I recommend the projects and websites THAT I have been updating and maintaining:

  • This is an independent blog post: this post is categorized

  • We are planning to build a complete and up-to-date practical project of AndroidX Jetpack-related components and analysis articles of related components. We are gradually adding new members of Jetpack, and the warehouse is continuously updated. Welcome to check out: AndroidX Jetpack-Practice

  • LeetCode/Jian Point Offer/domestic and foreign big factory interview questions/multi-threaded problem solving, language Java and Kotlin, including a variety of solutions, problem solving ideas, time complexity, space complexity analysis

    • Jian refers to offer and domestic and foreign dafang interview questions: online reading
    • LeetCode series of questions: online reading
  • The latest Android10 Source code Analysis series articles, understand the system Source code, not only help to analyze the problem, in the interview process, is also very helpful to us, the warehouse continues to update, welcome to check Android 10-source-Analysis

  • Collate and translate a series of selected foreign Technical articles, each Article will have a translator’s thinking part, more in-depth interpretation of the original text, the warehouse continues to update, welcome to check Technical articles-translation

  • “Designed for the Internet people, domestic and foreign famous station navigation” includes news, sports, life, entertainment, design, product, operation, front-end development, Android development and so on website, welcome to go to see for the Internet people and design navigation website

Article history

  • The Kotlin seal class evolved
  • Sealed classes in Kotlin are superior to labeled classes
  • What’s Kotlin Sealed? Why does Google use it
  • What does LeetCode learn from 0 to 200
  • What’s Kotlin Sealed? Why does Google use it
  • Android 12 behavior changes and their impact on applications
  • Multi-platform AndroidStudio tips (3)
  • Kotlin technique and principle analysis that few people know (1)
  • Kotlin technique and principle analysis that few people know (2)
  • The performance of Hilt and Koin was analyzed comprehensively
  • Jetpack + MVVM is a very simple way to use PokemonGo
  • Kotlin StateFlow search functionality in practice DB + NetWork
  • The end of the Kotlin plugin, the rise of ViewBinding
  • It’s surprisingly simple, DataBinding and ViewBinding