Object-Oriented Design & Patterns Chapter Topics: The Java Object Model
Object-Oriented Design & Patterns Chapter Topics: The Java Object Model
Cay S. Horstmann
Chapter Topics
The Java Type System Type Inquiry The Object Class Shallow and Deep Copy Serialization Reflection The Java Beans Component Model
Types
Type: set of values and the operations that can be applied to the values Strongly typed language: compiler and run-time system check that no operation can execute that violates type system rules Compile-time check Employee e = new Employee(); e.clear(); // ERROR Run-time check: e = null; e.setSalary(20000); // ERROR
Java Types
Primitive types: int short long byte char float double boolean Class types Interface types Array types The null type Note: void is not a type
Java Values
value of primitive type reference to object of class type reference to array null Note: Can't have value of interface type
Subtype Relationship
S is a subtype of T if S and T are the same type S and T are both class types, and T is a direct or indirect superclass of S S is a class type, T is an interface type, and S or one of its superclasses implements T S and T are both interface types, and T is a direct or indirect superinterface of S S and T are both array types, and the component type of S is a subtype of the component type of T S is not a primitive type and T is the type Object S is an array type and T is Cloneable or Serializable S is the null type and T is not a primitive type
Subtype Examples
Container is a subtype of Component JButton is a subtype of Component FlowLayout is a subtype of LayoutManager ListIterator is a subtype of Iterator Rectangle[] is a subtype of Shape[] int[] is a subtype of Object int is not a subtype of long long is not a subtype of int int[] is not a subtype of Object[]
Subtype Examples
The ArrayStoreException
Rectangle[] is a subtype of Shape[] Can assign Rectangle[] value to Shape[] variable: Rectangle[] r = new Rectangle[10]; Shape[] s = r; Both r and s are references to the same array That array holds rectangles The assignment s[0] = new Polygon(); compiles Throws an ArrayStoreException at runtime Each array remembers its component type
Array References
Wrapper Classes
Primitive types aren't classes Use wrappers when objects are expected Wrapper for each type: Integer Short Long Byte Character Float Double Boolean Auto-boxing and auto-unboxing ArrayList<Integer> numbers = new ArrayList<Integer>(); numbers.add(13); // calls new Integer(13) int n = numbers.get(0); // calls intValue();
Enumerated Types
Finite set of values Example: enum Size { SMALL, MEDIUM, LARGE } Typical use: Size imageSize = Size.MEDIUM; if (imageSize == Size.SMALL) . . . Safer than integer constants public static final int SMALL = 1; public static final int MEDIUM = 2; public static final int LARGE = 3;
Typesafe Enumerations
enum equivalent to class with fixed number of instances public class Size { private /* ! */ Size() { } public static final Size SMALL = new Size(); public static final Size MEDIUM = new Size(); public static final Size LARGE = new Size(); } enum types are classes; can add methods, fields, constructors
Type Inquiry
Test whether e is a Shape: if (e instanceof Shape) . . . Common before casts: Shape s = (Shape) e; Don't know exact type of e Could be any class implementing Shape If e is null, test returns false (no exception)
Type Inquiry
Test whether e is a Rectangle: if (e.getClass() == Rectangle.class) . . . Ok to use == A unique Class object for every class Test fails for subclasses Use instanceof to test for subtypes: if (e instanceof Rectangle) . . .
Array Types
Can apply getClass to an array Returned object describes an array type double[] a = new double[10]; Class c = a.getClass(); if (c.isArray()) System.out.println(c.getComponentType()); // prints double getName produces strange names for array types [D for double[]) [[java.lang.String; for String[][]
Typical string Manager[name=Dolly Dollar,salary=100000][department=Finance] Note that superclass reports actual class name
The Object.equalsMethod
Object.equals tests for identity: public class Object { public boolean equals(Object obj) { return this == obj; } ... } Override equals if you don't want to inherit that behavior
Fixing Employee.equals
Violates two rules Add test for null: if (otherObject == null) return false What happens if otherObject not an Employee Should return false (because of symmetry) Common error: use of instanceof if (!(otherObject instanceof Employee)) return false; // don't do this for non-final classes Violates symmetry: Suppose e, m have same name, salary e.equals(m) is true (because m instanceof Employee) m.equals(e) is false (because e isn't an instance of Manager) Remedy: Test for class equality if (getClass() != otherObject.getClass()) return false;
Hashing
hashCode method used in HashMap, HashSet Computes an int from an object Example: hash code of String int h = 0; for (int i = 0; i < s.length(); i++) h = 31 * h + s.charAt(i); Hash code of "eat" is 100184 Hash code of "tea" is 114704
Hashing
Must be compatible with equals: if x.equals(y), then x.hashCode() == y.hashCode() Object.hashCode hashes memory address NOT compatible with redefined equals Remedy: Hash all fields and combine codes: public class Employee { public int hashCode() { return name.hashCode() + new Double(salary).hashCode(); } ... }
Cloning
Cloning
Object.clone makes new object and copies all fields Cloning is subtle Object.clone is protected Subclass must redefine clone to be public public class Employee { public Object clone() { return super.clone(); // not complete } ... }
Shallow Cloning
clone makes a shallow copy Instance fields aren't cloned
Deep Cloning
Why doesn't clone make a deep copy? Wouldn't work for cyclic data structures Not a problem for immutable fields You must clone mutable fields public class Employee implements Cloneable { public Object clone() { try { Employee cloned = (Employee)super.clone(); cloned.hireDate = (Date)hiredate.clone(); return cloned; } catch(CloneNotSupportedException e) { return null; // won't happen } } ...
Deep Cloning
Serialization
Save collection of objects to stream Employee[] staff = new Employee[2]; staff.add(new Employee(...)); staff.add(new Employee(...)); Construct ObjectOutputStream: ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("staff.dat")); Save the array and close the stream out.writeObject(staff); out.close();
Serialization
The array and all of its objects and their dependent objects are saved Employee doesn't have to define any method Needs to implement the Serializable interface Another tagging interface with no methods
Reflection
Ability of running program to find out about its objects and classes Class object reveals superclass interfaces package names and types of fields names, parameter types, return types of methods parameter types of constructors
Reflection
Class getSuperclass() Class[] getInterfaces() Package getPackage() Field[] getDeclaredFields() Constructor[] getDeclaredConstructors() Method[] getDeclaredMethods()
Enumerating Fields
Print the names of all static fields of the Math class: Field[] fields = Math.class.getDeclaredFields(); for (Field f : fields) if (Modifier.isStatic(f.getModifiers())) System.out.println(f.getName());
Enumerating Constructors
Print the names and parameter types of all Rectangle constructors: for (Constructor c : cons) { Class[] params = cc.getParameterTypes(); System.out.print("Rectangle("); boolean first = true; for (Class p : params) { if (first) first = false; else System.out.print(", "); System.out.print(p.getName()); } System.out.println(")"); } Yields Rectangle() Rectangle(java.awt.Rectangle) Rectangle(int, int, int, int) Rectangle(int, int)
Invoking a Method
Supply implicit parameter (null for static methods) Supply array of explicit parameter values Wrap primitive types Unwrap primitive return value Example: Call System.out.println("Hello, World") the hard way. Method m = PrintStream.class.getDeclaredMethod( "println", String.class); m.invoke(System.out, "Hello, World!"); invoke is a varargs method
Inspecting Objects
Can obtain object contents at runtime Useful for generic debugging tools Need to gain access to private fields Class c = obj.getClass(); Field f = c.getDeclaredField(name); f.setAccessible(true); Throws exception if security manager disallows access Access field value: Object value = f.get(obj); f.set(obj, value); Use wrappers for primitive types
Inspecting Objects
Example: Peek inside string tokenizer Ch7/code/reflect2/FieldTester.java Output int currentPosition=0 int newPosition=-1 int maxPosition=13 java.lang.String str=Hello, World! java.lang.String delimiters=, boolean retDelims=false boolean delimsChanged=false char maxDelimChar=, --int currentPosition=5 . . .
Generic Types
A generic type has one or more type variables Type variables are instantiated with class or interface types Cannot use primitive types, e.g. no ArrayList<int> When defining generic classes, use type variables in definition: public class ArrayList<E> { public E get(int i) { . . . } public E set(int i, E newValue) { . . . } . . . private E[] elementData; } NOTE: If S a subtyoe of T, ArrayList<S> is not a subtype of ArrayList<T>.
Generic Methods
Generic method = method with type parameter(s) public class Utils { public static <E> void fill(ArrayList<E> a, E value, int count) { for (int i = 0; i < count; i++) a.add(value); } } A generic method in an ordinary (non-generic) class Type parameters are inferred in call ArrayList<String> ids = new ArrayList<String>(); Utils.fill(ids, "default", 10); // calls Utils.<String>fill
Type Bounds
Type variables can be constrained with type bounds Constraints can make a method more useful The following method is limited: public static <E> void append(ArrayList<E> a, ArrayList<E> b, int co { for (int i = 0; i < count && i < b.size(); i++) a.add(b.get(i)); } Cannot append an ArrayList<Rectangle> to an ArrayList<Shape>
Type Bounds
Overcome limitation with type bound: public static <E, F extends E> void append( ArrayList<E> a, ArrayList<F> b, int count) { for (int i = 0; i < count && i < b.size(); i++) a.add(b.get(i)); } extends means "subtype", i.e. extends or implements Can specify multiple bounds: E extends Cloneable & Serializable
Wildcards
Definition of append never uses type F. Can simplify with wildcard: public static <E> void append( ArrayList<E> a, ArrayList<? extends E> b, int count) { for (int i = 0; i < count && i < b.size(); i++) a.add(b.get(i)); }
Wildcards
Wildcards restrict methods that can be called: ArrayList<? extendsE>.set method has the form ? extends E add(? extends E newElement) You cannot call this method! No value matches ? extends E because ? is unknown Ok to call get: ? extends E get(int i) Can assign return value to an element of type E
Wildcards
Wildcards can be bounded in opposite direction ? super F matches any supertype of F public static <F> void append( ArrayList<? super F> a, ArrayList<F> b, int count) { for (int i = 0; i < count && i < b.size(); i++) a.add(b.get(i)); } Safe to call ArrayList<? super F>.add: boolean add(? super F newElement) Can pass any element of type F (but not a supertype!)
Wildcards
Typical example--start with public static <E extends Comparable<E>> E getMax(ArrayList<E> a) { E max = a.get(0); for (int i = 1; i < a.size(); i++) if (a.get(i).compareTo(max) > 0) max = a.get(i); return max; } E extends Comparable<E> so that we can call compareTo Too restrictive--can't call with ArrayList<GregorianCalendar> GregorianCalendar does not implement Comparable<GregorianCalendar>, only Comparable<Calendar> Wildcards to the rescue: public static <E extends Comparable<? super E>> E getMax(ArrayList<E
Type Erasure
Virtual machine does not know about generic types Type variables are erased--replaced by type bound or Object if unbounded Ex. ArrayList<E> becomes public class ArrayList { public Object get(int i) { . . . } public Object set(int i, Object newValue) { . . . } . . . private Object[] elementData; } Ex. getmax becomes
Limitations of Generics
Cannot replace type variables with primitive types Cannot construct new objects of generic type a.add(new E()); // Error--would erase to new Object() Workaround: Use class literals public static <E> void fillWithDefaults(ArrayList<E>, Class<? extends E> cl, int count) throws InstantiationException, IllegalAccessException { for (int i = 0; i < count; i++) a.add(cl.newInstance()); } Call as fillWithDefaults(a, Rectangle.class, count)
public static Comparable getMax(ArrayList a) // E extends Comparable<? super E> erased to Comparable Erasure necessary to interoperate with legacy (pre-JDK 5.0) code
Limitations of Generics
Cannot form arrays of parameterized types Comparable<E>[] is illegal. Remedy: ArrayList<Comparable<E>> Cannot reference type parameters in a static context (static fields, methods, inner classes) Cannot throw or catch generic types Cannot have type clashes after erasure. Ex. GregorianCalendar cannot implement Comparable<GregorianCalendar> since it already implements Comparable<Calendar>, and both erase to Comparable
Components
More functionality than a single class Reuse and customize in multiple contexts "Plug components together" to form applications Successful model: Visual Basic controls calendar graph database link to robot or instrument Componens composed into program inside builder environment
A Builder Environment
Java Beans
Java component model Bean has methods (just like classes) properties events
Java Beans
A Calendar Bean
A Property Sheet
Edit properties with property sheet
Faade Class
Bean usually composed of multiple classes One class nominated as facade class Clients use only facade class methods
Faade Pattern
Context 1. A subsystem consists of multiple classes, making it complicated for clients to use 2. Implementor may want to change subsystem classes 3. Want to give a coherent entry point Solution 1. Define a facade class that exposes all capabilities of the subsystem as methods 2. The facade methods delegate requests to the subsystem classes 3. The subsystem classes do not know about the facade class
Faade Pattern
Faade Pattern
Name in Design Pattern Client Facade SubsystemClass Actual Name (Beans) Builder tool Main bean class with which the tool interacts Class used to implement bean functionality
Bean Properties
Property = value that you can get and/or set Most properties are get-and-set Can also have get-only and set-only Property not the same as instance field Setter can set fields, then call repaint Getter can query database
Property Syntax
Not Java :-( C#, JavaScript, Visual Basic b.propertyName = value calls setter variable = b.propertyName calls getter
Packaging a Bean
Compile bean classes Ch7/carbean/CarBean.java Create manifest file Ch7/carbean/CarBean.mf Run JAR tool: jar cvfm CarBean.jar CarBean.mf *.class Import JAR file into builder environment
Composing Beans
Make new frame Add car bean, slider to frame Edit stateChanged event of slider Add handler code carBean1.setX(jSlider1.getValue()); Compile and run Move slider: the car moves
Composing Beans