Student: So what else is different between records and classes? You said there was more.
Prof: One other big difference is equality.
Student: Equality?
Prof: Like
== vs .equals(), and what those mean.Student: Oh, so objects with classes don’t have
.equals() or something?Prof: Well… they kind of do.
Student: Kind of?
Prof: There is a default
.equals() that every class gets, but it’s different from the one on records, and it just checks ==:Student: So the
.equals acts more like arrays’ equals method?Prof: That’s right, it’s the default. If you want, you can define your own.
Student: You mean like, write my own equals method?
Prof: That’s right:
Student: Huh, that’s interesting. But why would you ever want that? Won’t it always just compare the fields with either
== or .equals?Prof: Great question. Consider this program:
Prof: Now, are
r1 and r2 the same image?Student: Yeah, obviously.
Prof: And should they be
.equals()?Student: Well obviously they should be… Oh right but the fields are arrays. So the
record version won’t work.Prof: Indeed! So
Raster actually defines a .equals that provides this:@Override
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof Raster r)) return false;
if (this.width() != r.width() || this.height() != r.height()) return false;
for (int y = 0; y < this.height(); y++) {
if (!Arrays.equals(this.pixels[y], r.pixels[y])) return false;
}
return true;
}Prof: And that code is what compares the arrays in this example:
Student: I see. I feel like you’ve just brought up more questions though – what’s
Object, and what’s instanceof and whats the Raster in parentheses doing?Prof: Yeah, it’s a lot. Trust me, we’ll get there. For now, I just want you to see that we compare the pixels of the rasters in this equals method, and there wouldn’t be a way to define equals this way with a
class or a record without writing equals ourselves.Student: So we need
.equals() for any comparisons between classes to be more than ==, and sometimes we need it to check something more than just comparing field by field.Prof: Nice summary. It’s worth saying that our
.equals() is cheating a little bit by not using Object, but that’s a lie I’ll make you live with a little longer.Practice
Here is a class version of the image files from the search engine. Two ImageFiles should be equal when they have the same name and the same sizeKb. Fill in equals.
class ImageFile {
String name;
int sizeKb;
ImageFile(String name, int sizeKb) {
this.name = name;
this.sizeKb = sizeKb;
}
boolean equals(ImageFile other) {
return ;
}
}
ImageFile a = new ImageFile("cat.png", 300);
ImageFile b = new ImageFile("cat.png", 300);
boolean same = a.equals(b);
String name;
int sizeKb;
ImageFile(String name, int sizeKb) {
this.name = name;
this.sizeKb = sizeKb;
}
boolean equals(ImageFile other) {
return ;
}
}
ImageFile a = new ImageFile("cat.png", 300);
ImageFile b = new ImageFile("cat.png", 300);
boolean same = a.equals(b);
Why does
equals compare the names with .equals, but the sizes with ==?nameis aString, an object, andsizeKbis anintStrings are objects, so==would ask whether the two names are the same object, like the"trash panda"example from the memory chapter.ints are numbers, so==compares the numbers.nameis a field, andsizeKbisn’tBoth are fields. What matters is their types.==doesn’t compile onStrings==on twoStrings compiles fine. It just asks a different question: are they the same object?