|
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
(m == n) (someChar == 'a') (myFavoriteDog == yourFavoriteDog) |
myFavoriteDog = new Dog( "arf", 3); yourFavoriteDog = new Dog( "arf", 3); (myFavoriteDog == yourFavoriteDog) |
The meaning of == for object-references: When given two object-references, == determines whether both references are referring to the exact same object. (So, two different objects won't be ==, even if they have the same values in every field.)
Often, when our java objects correspond to physical objects in the world, we have a distinction between two objects which look alike but are different. The mantra “one new, one instance” gets you through that. Sometimes, though, it's not what we want. Consider:
import java.math.BigInteger; BigInteger num1 = new BigInteger("7"); BigInteger num2 = new BigInteger("7"); (num1.add(num2)).toString(); // Returns "14", as expected. (num1 == num2) // False?! num1.toString() // "7" num2.toString() // "7" // Can we compare BigIntegers by sneakily/hackily comparing their String versions? (num1.toString() == num2.toString()) // Nope, still false! |
Just as the authors of the BigInteger class provided useful methods like add, it turns out they also provide a handy method so that you can compare one BigInteger to another:
num1.equals(num2) // Aha, finally, true! |
myFavoriteDog.equals(yourFavoriteDog) // true. myFavoriteDog.equals( new Dog("fido", 4) ) // False, even though they look alike?! |
class Date { /* Gregorian calendar */ int year; /* AD */ String month; /* 3-letter abbrev: e.g. "Mar", "Oct". int day; /* The day-of-month, always in 1..31. */ // ...other methods omitted... /** @param otherDate Another Date instance, to compare with this one. * @return true if these two Dates look alike. */ boolean equals(Date otherDate) { return ( (this.getYear() == otherDate.getYear()) // Same year? && (this.getMonth()).equals( otherDate.getMonth() ) // Same month? && (this.getDay() == otherDate.getDay()) // Same day-of-month? ); // WARNING: We'll learn later: if we name this method "equals", we should // declare it as "public" and its parameter should be of type "Object". } } |
class Dog { // ...other fields and methods omitted... /** @param otherDog Another Dog instance, to compare with this one. * @return true if these two Dogs are identically the same * (This is the default version of equals which Java provides, * if we don't write our own version for Dogs.) */ boolean equals(Dog otherDog) { return (this == otherDog); // WARNING: We'll learn later: if we name this method "equals", we should // declare it as "public" and its parameter should be of type "Object". } } |
Be aware: When comparing Strings, you almost always want to use equals rather than ==. We've already talked about equalsIgnoreCase (an equality-testing function that is unique to Strings).
Optional topic: Notes on defining your own equals:
Rule of thumb: if you decide a class warrants its own equals method, then the fields of that class should also be immutable (that is, don't provide any setter methods); once the object is created, its fields will never change. (This is the case with the Java classes String, Integer, Date, etc..)
null is a dirty word in this class, and you should never use it. … However, you'll see it in other code and in books, so we'll talk about what it does, and also give some strategies on how to avoid it.
First, let's back up, to ints: What does the following code do?
int zz; |
The purpose of a constructor is to make sure all the fields are initialized.
Here's a dirty little secret: If you don't initialize a field, Java secretly initializes it for you. The int zz actually starts off with the value 0. But just because Java does that, don't rely on it: If you want a value initialized to zero, then do this yourself. That way, other people reading your code (like the grader!) don't have to stop and wonder whether there might be some bug involving an uninitialized field.
Okay, now that we've seen that talked about int, what happens with objects?
Treasure tt; |
This is dangerous. Consider:
Treasure someFunction() { Treasure tt; //... tt.getWeight(); //... } |
Thorough testing is important:
Treasure someFunction() { Treasure tt; if ( /* some condition */ ) tt = new Treasure( /*... */); tt.getWeight(); //... } |
Treasure someFunction() { Treasure tt; if ( /* some condition */ ) tt = new Treasure( /*... */); return tt; } |
Make sure you initialize your fields and variables to non-null values!
If you ever see one of your objects with a field containing null, you probably forgot to initialize that field in the constructor — tsk tsk!
Now, what if people want to represent a reference to nothing at all? For example: Consider Explorers who have two Treasure fields (one for each pocket). Initially, an explorer starts with no treasures. So, you might be inclined to say that those fields should be null. But a better solution — which is required no the homework — is to have an actual Treasure which somehow corresponds to “a nothingness treasure” — in our case, lint.
What difference does it make, if we use null or a nothingness-treasure? There are some pros and cons:
There are still situations where the “dummy-nothingness-instance” doesn't work nicely. For example, consider a function which takes in a list of Treasures, and return any of the heavy Treasures contained therein. But, what if the list was empty -- then there is no heaviest Treasure at all. What should the function return in this case? Returning a lint (which wasn't even in the list to start with) is not a good solution! People often use null as a “sentinel value”, indicating that the search was unsuccessful.
Of course, this necessitates that whenever the search function is called, the caller explicitly checks for a result of null. One clever way to alleviate this is to have an optional extra-input to the search function: a special result which gets returned, if there no result is found. (This can default to null, using overloading.)
1You'll often see in documentation, comments like “this method must be passed a non-null argument…”. ↩
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
©2008, Ian Barland, Radford University Last modified 2008.Mar.03 (Mon) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |