ITEC120-ibarland (incl. office hrs)—info—lectures—labs—hws
int myFavoriteInt = 5; int yourFavoriteInt = 3*myFavoriteInt; myFavoriteInt = 7; Math.Sqrt(yourFavoriteInt); // Doesn't change the value of yourFavoriteInt. /* ...more code which never assigns to "yourFavoriteInt"... */ (yourFavoriteInt == 15) // Will be true. |
Dog myFavoriteDog = new Dog( "fido", 3 ); Dog yourFavoriteDog = myFavoriteDog; /* ...code which never *assigns* to "yourFavoriteDog", and moreover, never even *mentions* it. */ (myFavoriteDog == yourFavoriteDog) // Will be true. (yourFavoriteDog.getAge() == 3) // Might be false?!? |
There is still a parallel between the two examples above (m,n vs. my,yourFavoriteDog): The value of myFavoriteDog never changed -- it is still a reference to the same dog. Agreed, the state of the Dog has been modified over time, but it's still the same Dog!.
So: you can't change the value of a variable without assigning to it, whether its a primitive type or an object reference. But, the contents of an object might change, even if your variable which references the object isn't explicitly mentioned in the code.
Note that the code for the Library class might contain a reference to a book, even if that book has been checked out: they might have a field booksOnShelf, as well as a field booksCheckedOut.
Similarly, there might be only one Student object corresponding to you, but several different places of code might all refer to you. Your Dorm has a list of students which will include a reference to you; the Registrar has a list of all-students, as well as a list of honor-students and a list of students-with-outstanding-fines; you might be on all of these lists, or perhaps only one!
It turns out, that the library-program doesn't use the objects made by the Registrar's computer; I had to fill out a separate card (and re-list my name, phone-number, etc.). If I ever change my phone number, I'll need to tell both the library and the registrar to change it. This is poor data representation; there should be a single instance of (the object representing) me which all the different functions access.
On the other hand, for social reasons, perhaps it's good not to have a single central object with all the information:
The drawback of a lack of centralized database is that a criminal might be wanted by the police, yet still able to apply for parking permits and credit cards because there is no central database. (Or even, I might be wanted by the FBI, and yet when I'm pulled over by a local sherrif for speeding, the FBI information may not be shared with other systems, and I go free.) The costs and benefits of implementing the data the “correct” way (from a programmer's point of view) must be weighed with social realities.
(m == n) (someChar == 'a') (myFavoriteDog == yourFavoriteDog) |
myFavoriteDog = new Dog( "fifi", 3); yourFavoriteDog = new Dog( "fifi", 3); (myFavoriteDog == yourFavoriteDog) |
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 MyDate { /* 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 MyDate instance, to compare with this one. * @return true if these two Dates look alike. */ public boolean equals(MyDate otherDate) { // WARNING: after we talk about inheritance, // we'll see that this parameter should be of type Object, not MyDate. return ( (this.getYear() == otherDate.getYear()) // Same year? && (this.getMonth()).equals( otherDate.getMonth() ) // Same month? && (this.getDay() == otherDate.getDay()) // Same day-of-month? ); } } |
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.) */ public boolean equals(Dog otherDog) { // WARNING: after we talk about inheritance, // we'll see that this parameter should be of type Object, not Dog. return (this == otherDog); } } |
Notes on defining equals:
An object can be passed in, just like any other parameter.
class Kennel { Dog dog1; Dog dog2; /** * @param d The dog to replace the old dog1 with. */ void setDog1( Dog d ) { dog1 = d; } /** * @return The first dog in this kennel. */ Dog getDog1() { return dog1; } } |
Note that while the parameter itself cannot be changed, the fields of that parameter can be.
class Dog { // ...fields and other methods omitted... /** Have this and otherDog exchange their names. * A very useful method for sitcoms and Disney movies. * @param otherDog the dog who we'll swap names with. */ void swapName(Dog otherDog) { // ... WRITE THIS METHOD ... } } |
void addSevenTo( int n ) { n += 7; } int addSevenTo_v2( int n ) { n += 7; return n; } // Still bad practice. int zz = 5; addSevenTo(zz); // zz is still 5. addSevenTo(zz+3); // zz+3 is still 8. addSevenTo(19); // 19 is still 19. |
We can return objects as well:
class Dog { /** * @return a new dog which looks just like this one. */ public Dog clone() { // ... WRITE THIS METHOD ... } /** * @param partner the dog who is breeding with this. * @return a new puppy dog, whose age is 0 and whose name is a blend * of this's and partner's names. * For example: * (new Dog("rex",4)).breed( new Dog("fifi", 6) ) = new Dog( "refi", 0 ); */ public Dog breed( Dog partner ) { // ... WRITE THIS METHOD ... } } |
Btw, note that some people feel there are good reasons to avoid implementing clone, due to the danger of an object and its clone sharing state. For instance, if we clone a kennel, will the clone contain identically the same Dogs as the original? Or, will it contain clones of those Dogs?
1By the way, notice that Java variables work differently than spreadsheet cells: in a spreadsheet, if Y1 = 3 * M1, then any changes to M1 do cause Y1 to change. Java variables are not so sophisticated. But there are some programming languages for the web which do use such “reactive” variables. back
ITEC120-ibarland (incl. office hrs)—info—lectures—labs—hws
©2006, Ian Barland, Radford University Last modified 2006.Nov.02 (Thu) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |