Title: CS242 Advanced Programming Concepts in Java
1CS242Advanced Programming Concepts in Java
- 9/06/07
- references casting
- equals()
Prof. Searleman jets_at_clarkson.edu
2Outline
- Inheritance in Java
- - upcasting downcasting
- - polymorphic variables substitution
- Effective Java methods common to all objects
- obey the contract for equals()
- always override hashCode() when you override
equals - Arrays in Java
- Comparable interface compareTo()
- Sorting an array
- Read OODP, Ch. 7pp.261-280 Effective Java, Ch.
3pp 25-44 - HW2, due Tuesday, 9/18/07, will be posted soon
3UML class diagram
IS-A
IS-A
1
HAS-A
(composition)
IS-A
(inheritance)
4- Overloading
- multiple versions of a method, distinguished by
their signatures - (name and argument list)
- Overriding
- when a subclass completely replaces a method that
it inherits from its superclass (same signature)
5methods toString(), equals(), getClass(),
methods constructors, get/setCenter(),
get/setRadius(), computeArea() toString()
methods constructors, get/setColor() toString()
6Overriding Specialization
- can override an inherited method completely
- can specialize an inherited method
- Its common to do both
7Upcasting downcasting
- double z 2.75
- int k (int) z
- float x (float) k
- double w 5
// downcast,
ks value is 2
// upcast,
xs value is 2.0f
// OK the int is automatically cast to a double
8- Polymorphic variables
- FilledCircle fc1
- new FilledCircle(1.5f, 10, 20, Color.red)
- Circle c1
- c1 fc1
- FilledCircle fc2
- fc2 c1
- fc2 (FilledCircle) c1
9- Circle c2 new Circle(1.5f, 10, 20)
- fc2 (FilledCircle) c2
- Objects always know their type
- can check w/ instanceof operator
- if (c3 instanceof FilledCircle)
- fc2 (FilledCircle) c3
10method getCenter()
method getColor()
- Circle c1
- new FilledCircle(2.5f, 100, 200, Color.red)
- c1.getCenter()
- c1.getColor()
- ((FilledCircle) c1).getColor()
// OK
// OK
// error c1s type is Circle (no getColor)
// OK the cast works
11- polymorphic variable
- T ref1 new S()
- // OK as long as every S is a T
- principle of substitutability
- basic idea the type declared for a variable does
not have to match exactly the type of what it
refers to, as long as its a substitutable type - Circle c1 new FilledCircle()
- Object obj new Circle()
12- instances of a subclass must possess all data
fields associated with the parent class (may have
more, of course) - instances of a subclass must implement (either by
overriding or inheriting) all functionality
defined for the parent class (can add
functionality) - so, an instance of a subclass can mimic the
behavior of the superclass, and should be
indistinguishable from an instance of the
superclass if substituted in a similar situation
13Static binding
OK
OK
14Static binding
OK
NOT OK !
OK
15Current State
TVremote.rewind() // not OK (compile-time) ((TV-V
CRremote)TVremote).rewind() // OK // the type
matches at compile-time the // method works at
run-time
16OK
Current State
OK
TVremote.rewind() // not OK ((TV-VCRremote)TVremo
te).rewind() // not OK // the type matches at
compile-time, but the // cast fails at run-time
17OK
OK
OK
18NOT OK !
OK
OK
19NOT OK !
NOT OK !
OK
20Assume that a separate toString() is implemented
for Circle FilledCircle
Object x1 new Circle() System.out.println( x1
) // will call Circle.toString(), even though
the // type of reference x1 is Object // uses
dynamic method binding! // dynamic at run-time
21Testing for equality
- Every class needs its own toString() method, but
not every class needs its own equals() - - example Random RNG
- - the equals() inherited from your superclass
already tests what you want - - the class is private (or package-private) and
you are certain that equals() will never be
invoked in that case, an accidental call to
equals() should be an error (more on exceptions
later)
22Testing for equality
- Override Object.equals() when objects in your
class can be equal in value in some sense,
different from equivalent - - circles, lines,
- - dice?
- - ?
- value classes
- Bloch, Effective Java, p. 26
23Common problems w/ equals()
doesnt override Object.equals()
flawed
- public class Circle
-
- public Boolean equals(Circle o)
- return (this.radius o.radius)
- (this.center o.center)
-
to override a method, must have the same
signature return type
24Common problems w/ equals()
- public class Circle
-
- public boolean equals(Object o)
-
- return (this.radius o.radius)
- (this.center o.center)
-
flawed
radius center are private, its OK here, but
may need accessor functions to avoid breaking
encapsulation of other classes
center is a Point cant test for equality w/
25Item 7 Obey the general contract when overriding
equals()
- public class Circle
- public boolean equals(Object o)
-
- return ( this.radius o.radius )
- ( (this.center).equals(o.center) )
-
flawed
what if o is null? get a NullPointerException
what if object o refers to something other than a
circle, like a die for instance?
26Rules for equality
- reflexive x.equals(x) is true
- symmetric x.equals(y) iff y.equals(x)
- transitive
- x.equals(y) y.equals(z) gt x.equals(z)
- consistent
- multiple calls to x.equals(y) all give the
same result - cautious x.equals(null) is false
27- public class Circle
-
- public boolean equals(Object o)
-
- if (o null)
- return false
- if (o this)
- return true
- if (!(o instanceof Circle))
- return false
- Circle other (Circle) o
- return (this.radius other.radius)
- (this.center).equals(other.center) )
-
// required, but will be detected by // the
instanceof operator anyway
// not strictly required, but efficient
// this cast cannot fail
28- public boolean equals(Object o)
-
- if (this o)
- return true
- if (!(o instanceof Circle))
- return false
- Circle other (Circle) o
- return (this.radius other.radius)
- ( (this.center).equals(other.center) )
-
// include this performance optimization // when
the equals test is complex
// see Effective Java pp. 33-34 for float, double
arrays
29Template for an equals() method
- Suppose you are the class designer for a new
class T - T has 3 fields field1, field2, field3 of types
A, B and C respectively (can generalize to n
fields). - A field1 suppose that A is a primitive type
(like int) - B field2 suppose that you will ignore this when
testing for equality - C field3 suppose that C is an object
30class T equals() method
- public boolean equals(Object o)
- // compares fields 1 and 3 for equality
- if (!(o instanceof T))
- return false
- T other (T) o
- return ( (this.field1 other.field1)
- (this.field3).equals(other.field3) )
-
31Testing for Equality in Subclasses
- 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 doesnt override Object.equals()!!
32method public boolean equals(Object o)
method public boolean equals(Circle c) //
overloads equals() method
method public boolean equals(FilledCircle c)
// overloads equals() method
33- 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)
34starting in the FilledCircle class, look for
method w/ signature equals(Object)
but the equals() method in Object tests for
equivalence, not equality!
35method public boolean equals(Object o)
method public boolean equals(Object c) //
overrides equals() method
method public boolean equals(Object c) //
overrides equals() method
36- if (fc1.equals(aShape))
- if (fc1.equals(fc2))
- Its 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)
public boolean equals(Object c) matches, so
invoke this code
still matches, because every FilledCircle is an
Object, so invoke FilledCircle.equals()
37- public class Circle
- public boolean equals(Object o)
- // return true if same center point
radius -
- public class FilledCircle extends Circle
- public boolean equals(Object o)
- if (!(o instanceof FilledCircle)) return false
- FilledCircle other (FilledCircle) o
- return super.equals(other)
- (this.fillColor).equals(other.getColor()) )
-
flaw can violate symmetry
38- When a subclass adds one aspect to its superclass
theres a fundamental problem with symmetry - Circle c1 new Circle(1.5f, 100, 200)
- FilledCircle fc2
- new FilledCircle(1.5f, 100, 200, Color.blue)
- System.out.println( c1.equals(fc2) )
- System.out.println( fc2.equals(c1) )
prints true (calls Circle.equals() which
ignores color) false (calls FilledCircle.equals
(), and c1 is not
an instance of a FilledCircle)
39Effective use of inheritance
- Item 14 Favor composition over inheritance
- we will look at this issue later
40Item 8 always override hashCode when you
override equals
- equal objects should have equal hashcodes
- unequal objects dont necessarily have
different hashcodes (although hash tables will be
more efficient if they do) - if you dont override hashCode in this case then
collections will not work properly for your class
41hashCode contract
- 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)
42- Bad idea, why?
- public class Circle
- public int hashCode()
-
- return 42
-
43How to write a good hash function
- 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 37result c
44- / if 2 circles are equal only if they have the
same radius and center point / - public class Circle
- public int hashCode()
-
- int result 17
- result 37result Float.floatToIntBits(radius
) - result 37 result center.hashCode()
- return result
-
45Template for a hashcode() method
- 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 wont be used to compare
equality, and field3 is an object type C - Lets suppose that A is float
46class T hashcode() method
- public int hashCode()
-
- int result 17
- result 37result
- 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? Its an odd prime why 17? Arbitrary, but
should be relatively prime to 37
47Arrays in Java
- int sides // reference, currently null
- // int sides is also OK
- sides new int6 // 6 slots in array
- sides new intnumSides // also OK
- int6 sides // ERROR (int sides6 also error)
- for (int i 0 i lt sides.length i)
- sidesi i 1
- int sides 1, 2, 3, 4, 5, 6
48java.util.Arrays
- provides class methods for sorting searching in
arrays - int sides new intnumSides
- / initialize the array with random ints /
- Arrays.sort(sides) // quicksort used
- // for array of int
49array of Objects
- Circle hoops new Circle3
- for (int i 0 i lt hoops.length i)
- hoopsi.draw()
- There arent any actual circles in the array yet
ERROR why?
50- Circle hoops new Circle3
- hoops0 new Circle(1.0f, 1, 1)
- hoops1 new Circle(2.0f, 2, 2)
- hoops2 new Circle(3.0f, 3, 3)
- for (int i 0 i lt hoops.length i)
- hoopsi.draw() // draws the 3 circles
51- Circle hoops
- new Circle(1.0f, 1, 1),
- new Circle(2.0f, 2, 2),
- new Circle(3.0f, 3, 3)
- for (int i 0 i lt hoops.length i)
- hoopsi.draw() // draws the 3 circles
52- problem want more circles in the array
- Circle temp new Circle hoops.length 2
- System.arrayCopy( hoops, 0, temp, 0,
hoops.length) - hoops temp
53Sorting
- problem would like to sort the array of
circles, but - how to compare two circles?
- java.util.Arrays has overloaded sorting methods
- public static void sort( Object a )
- is a modified merge sort which needs to compare
object a1 with object a2, so - elements must implement Comparable interface
54Item 11 Consider implementing Comparable
- cf. Interfaces, Chapter 6, pp. 277-291
- public interface Comparable
-
- public int compareTo( Object o )
-
- Any class that implements the Comparable
interface MUST have this compareTo() method
55public int compareTo(Object o)
- returns
- -1 if this object lt other object
- 0 if this object equals other
- 1 if this object gt other object
- in some sense of a natural ordering
56implements
implements
implements
57- public class Circle implements Comparable
-
- public int compareTo( Object o )
-
- // compares radii only
- Circle other (Circle) o
- if (this.radius lt other.radius)
- return -1
- if (this.radius gt other.radius)
- return 1
- return 0
-
use lt gt to compare primitives invoke
compareTo() method to compare objects
58- public class Circle implements Comparable
-
- public int compareTo( Object o )
-
- // compares center points only
- // (assumes Point implements Comparable)
- Circle other (Circle) o
- return
- (this.center).compareTo(other.center)
-
exercise compare 2 circles using radius first,
then center point
59- public static void main(String args)
-
- Circle hoops new Circle(),
- Arrays.sort(hoops) // sorts the array
60Contract for compareTo()
- sgn(x.compareTo(y)) -sgn(y.compareTo(x))
- x.compareTo(y) gt 0 y.compareTo(z) gt 0 implies
x.compareTo(z) gt 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
61Summary
- Item 9 Always override toString()
- Item 7 Obey the contract when overriding
equals() - Item 8 Always override hashCode() when you
override equals() - Item 11 Consider implementing the Comparable
interface write compareTo() - Be sure that an array of Objects is initialized
to actual objects before doing anything with them - Make effective use of the Arrays class in
java.util