Interface vs. Class 9-4-2013jsearlem/cs242/fa13/lectures/05.interfaces.pdfMethods common to all...
Transcript of Interface vs. Class 9-4-2013jsearlem/cs242/fa13/lectures/05.interfaces.pdfMethods common to all...
Interface vs. Class
9-4-2013
Methods common to all classes: toString(), equals(), hashCode()
Interface vs. Class
Comparable Interface: compareTo()
Arrays
Reading assignment:
Effective Java 2
Ch. 3: Items 8, 9, 10, 12
Ch. 4: Items 13, 14, 18, 19
Java Tutorial:
Learning the Java Language trail: arrays, interfaces
HW#1 due today, 9/4/13
Item 7: equals()
- override Object.equals() for “value” classes
Item 8: hashCode()
- always override Object.hashCode() when you override equals()
Item 9: always override toString()
Note:
equals(), hashCode() & toString() are methods in class Object
public class X {
// assume fields f1 (float), f2 (object), …, fk
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof X))
return false;
X other = (X) o;
return ( (this.f1 == other.f1) &&
( (this.f2).equals(other.f2) &&
… );
} /* use == for primitive fields,
use equals() for objects */
public class Circle { public boolean equals(Circle c) { // return true if same center point & radius }
public class FilledCircle extends Circle { public boolean equals(FilledCircle fc) { return super.equals(fc) && (this.fillColor).equals(fc.getColor()) ); } } flaw: doesn’t override Object.equals()!!
Object method: public boolean equals(Object o)
Circle method: public boolean equals(Circle c) // overloads equals() method
FilledCircle method: public boolean equals(FilledCircle c) // overloads equals() method
consider a list of containing a variety of shapes (circles, lines, squares, arrows)
ArrayList shapeList = …. ; /* list of shapes */
FilledCircle fc1 = … ; /* a given circle */
Object aShape;
Search the list for circle fc1: traverse the list with aShape & compare each element to fc1
if (fc1.equals(aShape)) …
starting in the FilledCircle class, look for method w/ signature equals(Object)
FilledCircle Object
if (fc1.equals(aShape)) starting in the FilledCircle class, look for method w/ signature equals(Object)
FilledCircle Object
public boolean equals(FilledCircle c) doesn’t match FilledCircle
Circle public boolean equals(Circle c)
doesn’t match
Object public boolean equals(Object o)
matches, so this code is executed
but the equals() method in Object tests for equivalence, not equality!
Object method: public boolean equals(Object o)
Circle method: public boolean equals(Object o) // overrides equals() method
FilledCircle method: public boolean equals(Object o) // overrides equals() method
if (fc1.equals(aShape))
if (fc1.equals(fc2)) …
It’s OK to both overload and override a method, if it makes sense to do so
starting in the FilledCircle class, look for method w/ signature equals(Object) FilledCircle Object
public boolean equals(Object c) matches, so invoke this code FilledCircle
FilledCircle FilledCircle
still matches, because every FilledCircle is an Object, so invoke FilledCircle.equals()
“equal” objects should have equal hashcodes
“unequal” objects don’t necessarily have different hashcodes (although hash tables will be more efficient if they do)
if you don’t override hashCode in this case then collections will not work properly for your class
hashCode() must be consistent: i.e. it always returns the same integer whenever it is invoked on the same object
if 2 objects are “equal” according to the equals(Object) method, then they must have the same hashcode: i.e. hashCode() returns the same integer for each of them
if 2 objects are not equal, hashCode() is not required to return different integer hashcodes for them (but it may be more efficient to do so)
Bad idea, why?
public class Circle {
public int hashCode()
{
return 42;
}
}
1. Start with a nonzero value, say 17
int result = 17;
2. For each “significant” field f in your object, compute a hash value c for it.
How to do this depends on whether the field is a primitive or an object
3. Combine the results
result = 37*result + c;
/* hashCode for a circle */
public class Circle {
public int hashCode()
{
int result = 17;
result = 37*result +
Float.floatToIntBits(radius);
result = 37* result + center.hashCode();
return result;
}
}
Suppose you are the class designer for a new class T
T has 3 fields: field1 is a primitive type A, field2 is of type B but won’t be used to compare equality, and field3 is an object type C
Let’s suppose that A is float
public int hashCode()
{
int result = 17;
result = 37*result +
Float.floatToIntBits(field1);
result = 37* result + field3.hashCode();
return result;
}
}
see Effective Java, p. 38 for how to compute hash codes for other primitive values and for arrays
why 37? It’s an odd prime why 17? Arbitrary, but should be relatively prime to 37
public class X { // assume fields f1 (float), f2 (object), …, fk public int hashCode() { int result = 17; result = 37*result + Float.floatToIntBits(f1); result = 37*result + f2.hashCode(); … result = 37*result + …; // cf. pp 38-39 return result; }
Item 7: equals() - override Object.equals() for “value” classes Item 8: hashCode() - always override Object.hashCode() when you
override equals() Item 9: always override toString() Item 11: consider implementing Comparable
Note:
equals(), hashCode() & toString() are methods in class Object
compareTo() is not a method in class Object; it is a method in the Comparable interface
What is an Interface?
How does an Interface differ from a Class?
Head First Java 2, Chapter 8, pp. 219 – 226
Java Tutorial, interfaces
In the java.lang package:
public interface Comparable {
public int compareTo( Object o );
}
How to use an Interface within a Class:
public class Weapon implements Comparable {
/* Must provide code for compareTo */
public int compareTo( Object o ) {
// code for how to compare two weapons
} }
Adventure game:
public interface Moveable {
public void move(double x, double y);
}
public interface Powered extends Moveable {
public String powerSource();
}
public class Weapon implements Comparable, Moveable { /* Must provide code for compareTo */
public int compareTo( Object o ) { … } /* Must provide code for move */
public void move(double toX, double toY ) { … }
“specification of an interface or protocol for a class (may be implemented in unrelated classes)”
may not contain instance variables or any code, but may contain (static final) constants
when a class states that it implements an interface, it MUST implement ALL methods in the interface
a class can implement more than one interface
all methods in an interface are abstract and public, with or without the modifiers “public” and/or “abstract”
an interface can be empty, in which case it is a marker for a special property (e.g. Cloneable, Serializable)
an interface can be used to implement “callbacks”
interfaces can extend other interfaces
cannot instantiate an interface
can declare a reference to one
public interface Comparable {
public int compareTo( Object o );
}
for x, y objects of the same class
x.compareTo(y) < 0 means “x < y”
x.compareTo(y) > 0 means “x > y”
otherwise, “x is neither < nor > y”
recommended that compareTo() is consistent with equals()
if y cannot be cast to the same class as x, then generates a ClassCast Exception
Circle
Date
String
<<interface>>
Comparable
implements
Die
implements
implements
Circle
FilledCircle
Point HAS-A
IS-A
(composition)
(inheritance)
1
Object
IS-A IS-A
<<interface>>
Comparable
implements implements
public class Student { private String name; private int stdID;
public int compareTo( Object o )
{ Student other = (Student) o; if (this.name < other.name) return -1; if (this.name > other.name) return 1; return 0; }
This doesn’t implement the Comparable interface String is an object – cannot use < or > to compare
severely flawed
public class Student implements Comparable {
private String name;
private int stdID;
public int compareTo( Object o ) {
Student other = (Student) o;
return ((this.name).compareTo(other.name));
}
} use < & > to compare primitives invoke compareTo() method to compare objects remember to have “implements Comparable” on the class header
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
x.compareTo(y) > 0 && y.compareTo(z) > 0 implies x.compareTo(z) > 0
x.compareTo(y) == 0 implies that for all z, sgn(x.compareTo(z)) == sgn(y.compareTo(z))
strongly recommended that
(x.compareTo(y) == 0) == (x.equals(y))
i.e. consistent with equals
public class X implements Comparable {
// assume fields f1 (float), f2 (object), …, fk
/* version 1: base on primitive field f1 only */
public int compareTo( Object o ) {
X other = (X) o;
if ( (this.f1) < (other.f1) ) return -1;
if ( (this.f1) > (other.f1) ) return 1; return 0; }
Important:
use <,> to compare primitive fields,
use compareTo() for object fields
public class X implements Comparable {
// assume fields f1 (float), f2 (object), …, fk
/* version 2: base on object field f2 only */
public int compareTo( Object o ) {
X other = (X) o; return ( (this.f2).compareTo(other.f2) ); }
Exercise:
Implement compareTo() for the Student class as follows:
First compare the name field, if < or >, return -1 or +1, respectively
If the name fields are equal, then return the result of comparing the student ID fields
int[] sides; // reference, currently null
// int sides[]; is also OK
sides = new int[6]; // 6 slots in array
sides = new int[numSides]; // also OK
int[6] sides; // ERROR (int sides[6] also error)
for (int i = 0; i < sides.length; i++)
sides[i] = i + 1;
int[] sides = {1, 2, 3, 4, 5, 6};
No longer the preferred idiom to iterate over an array:
for (int i = 0; i < a.length; i++)
doSomething( a[i] );
A new feature of Java 1.5 is a concise version of an iterator, the for-each.
Example:
for (Die d : diceArray)
System.out.println(d);
The preferred idiom for iterating over collections & arrays
Shape[] drawing = { /* initialize with some circles, lines,
triangles, etc. */ };
for (Shape s : drawing) {
System.out.println ( s );
}
int[] sides = {1, 2, 3, 4, 5, 6};
for (int x : sides) {
System.out.println ( x );
}
for (Element e : elements)
doSomething(e);
provides class methods for sorting & searching in arrays
final int SIZE = 12;
double[ ] weights = new double[ SIZE ];
for (double element : weights)
element = Math.random();
Arrays.sort(weights);
/* note: quicksort is used to sort doubles */
Circle[] hoops = new Circle[3];
for (int i = 0; i < hoops.length; i++)
hoops[i].draw();
There aren’t any actual circles in the array yet
ERROR… why?
Circle[] hoops = new Circle[3];
hoops[0] = new Circle(1.0f, 1, 1);
hoops[1] = new Circle(2.0f, 2, 2);
hoops[2] = new Circle(3.0f, 3, 3);
for (int i = 0; i < hoops.length; i++)
hoops[i].draw(); // draws the 3 circles
Circle[] hoops = {
new Circle(1.0f, 1, 1),
new Circle(2.0f, 2, 2),
new Circle(3.0f, 3, 3)
};
for (Circle c : hoops)
c.draw(); // draws the 3 circles