Java Objects

advertisement
Java Objects
Reed, CS340, Fall 2004
Examples and notes taken in large part from:
http://6170.lcs.mit.edu/www-archive/Old-Fall03/lectures/handout/lec02_semantics.pdf
Variables, References, Binding
What is output of code below?
1. String a = "zeeb";
2. String b = a.toUpperCase ();
3. System.out.println (b);
Output is ZEEB. a is a reference to the String with “zeeb” in it, and is not the object itself. As a
picture, this looks like the diagram at right above. Note that strings are immutable.
Now consider this code:
1. String a = "zeeb";
2. a.toUpperCase ();
3. System.out.println (a);
It prints “zeeb”, since line 2 returns a new String (an object) which is ignored. On the other hand
we could have:
String a = "zeeb";
a = a.toUpperCase ();
System.out.println (a);
Here a points to the new object.
Aliasing, Mutability, and Reference Equality
1. Vector v = new Vector ();
2. Vector k = v;
3. String a = "zeeb";
4. v.add (a);
5. k.add (a.toUpperCase());
6. System.out.println (v.lastElement ());
Note that the method add() in line 4 does not return an object, but rather mutates its receiver,
which is Vector v. The call to a.toUpperCase() in line 5 does return an object, since Strings are
immutable. v and k are references to the same object, which makes them aliases.
Testing for equality:
Vector v = new Vector ();
Vector k = v;
if (v == k)
System.out.println ("same");
else
System.out.println ("different");
The code above prints out “same”, since both references point to same object.
One problem with aliases is that they can cause “side-effects”, where a change done with one
version of an alias ends up reflected in another alias.
Vector v = new Vector ();
Vector k = new Vector ();
if (v == k)
System.out.println ("same");
else
System.out.println ("different");
Prints out “different”, since references point to different objects.
String a = "zeeb";
String b = "zeeb";
if (a == b)
System.out.println ("same");
else
System.out.println ("different");
Prints out “same”. This is unusual, and is a Java compiler performance optimization. Changing
the second line to String b = new String(a); makes them different, however.
Strings (and other immutable objects) should actually be compared with the equals method. It is
considered bad form to test reference equality for immutable objects (e.g. Strings).
String a = "zeeb";
String b = a.toUpperCase ();
if (b.equals ("ZEEB"))
System.out.println ("same characters");
else
System.out.println ("different characters");
This code prints: “same characters”.
 Would you expect that generally x = = y implies x.equals (y) ? Yes, it should.
 Immutable types arise because aliasing makes things complicated.
 If aliasing makes things complicated, then why have mutable types at all? Real-world
problems can be modeled more easily with mutable types. A transaction on a bank account
changes it (it is mutable); it doesn't produce a new bank account.
Null References
The code
String a = null;
System.out.println (a);
Prints out null, meaning there is no object to be printed. If we try to use a null object, however,
we can have problems:
1. String a = null;
2. String b = a.toUpperCase ();
3. System.out.println (b);
// Problem here
where the a.toUpperCase() tries to call a method on a null object, throwing a
NullPointerException on line 2. It is good to avoid building null references in the first place.
You would expect a.equals( b) to be equivalent to b.equals( a), however if a is null and b is not,
then the first would throw an exception and the second would not. We would expect these to be
the same, putting this issue of nulls aside.
User-defined Classes and Fields
Here is our own class for a bank transaction:
class Trans {
int amount;
Date date;
}
where amount is of a primitive type int, and date is of type Date. Primitives sometimes need to
be converted to classes, and visa-versa. To do this with an int we could use:
int_i = 5;
Integer obj_i = new Integer (i);
And to extract the int from the field of the Integer class object we could use
int i = obj_i.intValue();
We could create a Transaction using:
1. Trans t = new Trans ();
2. t.amount = 20;
3. t.date = new Date ();
This creates a fresh object and sets the fields, as shown at right above.
User-defined Constructors
In the example above we could have set the initial transaction date to be anything, including a
date in the future or past. To restrict this we would want to implement invariants to enforce
certain constraints. We can do this by providing our own constructors, which enforce the
conditions we would like, such as a non-zero transaction amount.
class Trans {
int amount;
Date date;
Trans (int a, Date d) { //constructor
amount = a;
date = d;
}
}
Creating our own constructor has the effect of making the default constructor go away, which is
the one used in line 1 in the sample code by the diagram immediately above. We can replace
those 3 lines of code with
Trans t = new Trans (20, new Date ());
Method Overloading
[http://www.cs.sunysb.edu/~cse219/lectures/5 ]



The proper method to execute is identified by its name and signature (i.e. its parameter
list) that matches the arguments sent
What if no perfect match exists? The most specific match is called.
Method m()1 is more specific than another method m2() if any legal call of m1() would
also be a legal call of m2() if more conversions were done.
What if there is no most specific match? Consider the following example:
public class Junk
{
public static void main(String[] args)
{
int x = 2;
comp(x, x);
// which method does this match?
}
static int comp(int a, long b) {}
static int comp(long a, int b) {}
static int comp(long a, long b) {}
}
This gives the following compiler error: reference to comp is ambiguous, both method
comp(int,long) in Junk and method comp(long,int) in Junk match comp(x, x);
Download