Student: We talked about structural vs. reference equality – which one do records use?
Prof: Great question, how would you know?
Student: I guess I’d have to try
.equals() on an object I created from a record?Prof: That’s right, or
assertEquals.Student: OK let’s try both.
Student: Great! Easy.
Prof: OK, actually, I have some bad news. Let’s say these cars could have an array of ints representing the pressure of the 4 tires (it’ll always be 4 elements long). Just a quick tip, you can use
new int[]{ ... } to make an int array with specific contents as a value, without defining a new name.Student: Sure, let’s do it!
Student: Wait, what?
Prof: Right, so that test succeeded before, and now it fails. This is a real gotcha when working with arrays and equality in Java.
Student: What’s going on?
Prof: Well, we need to be precise about what the “structural equality” does on record instances in Java. It works by calling .equals() on all the pairs of fields that are reference types, and uses == on the ones that are primitives. So for Car it’s like the method does
boolean equals(Car other) {
return make.equals(other.make) && model.equals(other.model)
&& year == other.year && pressures.equals(other.pressures);
}Student: But that looks fine?
Prof: What did we learn about the
.equals() method on arrays?Student: Ohhhhhh! That does reference equality on the two arrays, not structural. It would need to be
Arrays.equals for that to work.Prof: That’s right. We’ll have a conversation in the future about how to write our own equals method. For now we just need to be careful and conscious of our equality comparisons. Sometimes we might want to use a field lookup to access arrays and compare them directly in a test, for example.
Student: Noted. Wow, Java makes us remember a lot about equality.
Prof: It’s true. Some of this is necessary complexity, in that most languages do expose both reference and structural equality (or even more). But some of it is also incidental complexity related to arrays in Java, which have pretty specific rules. We’ll see ways to manage both kinds of complexity going forward.
Practice
c1 and c2 have tire pressures with the same contents. Which line checks that in a test?void main() {
}
}
After
main runs, what is true of each pair?car1.pressures and car2.pressures: car1.pressures and car3.pressures: car2.pressures and car3.pressures: car1.equals(car2): car2.equals(car3):