0% found this document useful (0 votes)
73 views23 pages

Object-Oriented Design & Patterns Chapter Topics: The Java Object Model

This chapter discusses types and objects in Java. It covers the Java type system including primitive, class, interface, and array types. It describes values in Java including references to objects and arrays. It explains subtype relationships and provides examples. It also discusses type inquiry using instanceof and Class objects. Finally, it covers the Object class and methods like equals, hashCode, clone, and toString that are commonly overridden in subclasses.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
73 views23 pages

Object-Oriented Design & Patterns Chapter Topics: The Java Object Model

This chapter discusses types and objects in Java. It covers the Java type system including primitive, class, interface, and array types. It describes values in Java including references to objects and arrays. It explains subtype relationships and provides examples. It also discusses type inquiry using instanceof and Class objects. Finally, it covers the Object class and methods like equals, hashCode, clone, and toString that are commonly overridden in subclasses.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Object-Oriented Design & Patterns

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

Chapter 7 The Java Object 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

Exercise: What kind of type?


int Rectangle Shape String[] double[][]

Java Values
value of primitive type reference to object of class type reference to array null Note: Can't have value of interface type

Exercise: What kind of value?


13 new Rectangle(5, 10, 20, 30); "Hello" new int[] { 2, 3, 5, 7, 11, 13 } null

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)

The Class Class


getClass method gets class of any object Returns object of type Class Class object describes a type Object e = new Rectangle(); Class c = e.getClass(); System.out.println(c.getName()); // prints java.awt.Rectangle Class.forName method yields Class object: Class c = Class.forName("java.awt.Rectangle"); .class suffix yields Class object: Class c = Rectangle.class; // java.awt prefix not needed Class is a misnomer: int.class, void.class,Shape.class

An Employee Object vs. the Employee.class Object

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[][]

Object: The Cosmic Superclass


All classes extend Object Most useful methods: String toString() boolean equals(Object otherObject) Object clone() int hashCode()

The toString Method


Returns a string representation of the object Useful for debugging Example: Rectangle.toString returns something like java.awt.Rectangle[x=5,y=10,width=20,height=30] toString used by concatenation operator aString + anObject means aString + anObject.toString() Object.toString prints class name and object address System.out.println(System.out) yields java.io.PrintStream@d2460bf Implementor of PrintStream didn't override toString:

Overriding the toString Method


Format all fields: public class Employee { public String toString() { return getClass().getName() + "[name=" + name + ",salary=" + salary + "]"; } ... } Typical string: Employee[name=Harry Hacker,salary=35000]

Overriding toString in Subclass


Format superclass first public class Manager extends Employee { public String toString() { return super.toString() + "[department=" + department + "]"; } ... }

The equals Method


equals tests for equal contents == tests for equal location Used in many standard library methods Example: ArrayList.indexOf /** Searches for the first occurrence of the given argument, testing for equality using the equals method. @param elem an object. @return the index of the first occurrence of the argument in this list; returns -1 if the object is not found. */ public int indexOf(Object elem) { if (elem == null) { for (int i = 0; i < size; i++) if (elementData[i] == null) return i; } else {

Typical string Manager[name=Dolly Dollar,salary=100000][department=Finance] Note that superclass reports actual class name

for (int i = 0; i < size; i++) if (elem.equals(elementData[i])) return i; } return -1; }

Overriding the equals Method


Notion of equality depends on class Common definition: compare all fields public class Employee { public boolean equals(Object otherObject) // not complete--see below { Employee other = (Employee)otherObject; return name.equals(other.name) && salary == other.salary; } ... } Must cast the Object parameter to subclass Use == for primitive types, equals for object fields

Overriding equals in Subclass


Call equals on superclass public class Manager { public boolean equals(Object otherObject) { Manager other = (Manager)otherObject; return super.equals(other) && department.equals(other.department); } }

Not all equals Methods are Simple


Two sets are equal if they have the same elements in some order public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Set)) return false; Collection c = (Collection) o; if (c.size() != size()) return false; return containsAll(c); }

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

Requirements for equals Method


reflexive: x.equals(x) symmetric: x.equals(y) if and only if y.equals(x) transitive: if x.equals(y) and y.equals(z), then x.equals(z) x.equals(null) must return false

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;

The Perfect equals Method


Start with these three tests: public boolean equals(Object otherObject) { if (this == otherObject) return true; if (otherObject == null) return false; if (getClass() != otherObject.getClass()) return false; ... } First test is an optimization

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(); } ... }

Shallow and Deep Copy


Assignment (copy = e) makes shallow copy Clone to make deep copy Employee cloned = (Employee)e.clone();

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 } ... }

The Cloneable Interface


Object.clone is nervous about cloning Will only clone objects that implement Cloneable interface public interface Cloneable { } Interface has no methods! Tagging interface--used in test if x implements Cloneable Object.clone throws CloneNotSupportedException A checked exception

The clone Method


public class Employee implements Cloneable { public Object clone() { try { return super.clone(); } catch(CloneNotSupportedException e) { return null; // won't happen } } ... }

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

Cloning and Inheritance


Object.clone is paranoid clone is protected clone only clones Cloneable objects clone throws checked exception You don't have that luxury Manager.clone must be defined if Manager adds mutable fields Rule of thumb: if you extend a class that defines clone, redefine clone Lesson to learn: Tagging interfaces are inherited. Use them only to tag properties that inherit

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

How Serialization Works


Each newly encountered object is saved Each object gets a serial number in the stream No object is saved twice Reference to already encountered object saved as "reference to #"

How Serialization Works

Serialing Unserializable Classes


Some classes are not serializable Security? Anonymous classes? Programmer cluelessness? Example: Ellipse2D.Double How can we serialize Car? Suppress default serialization to avoid exception Mark with transient: private transient Ellipse2D frontTire; Supply private (!) methods private void writeObject(ObjectOutputStream out) private void readObject(ObjectInputStream in) In these methods Call writeDefaultObject/readDefaultObject Manually save other data Ch7/serial/Car.java

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)

Rectangle(java.awt.Point, java.awt.Dimension) Rectangle(java.awt.Point) Rectangle(java.awt.Dimension)

Getting A Single Method Descriptor


Supply method name Supply array of parameter types Example: Get Rectangle.contains(int, int): Method m = Rectangle.class.getDeclaredMethod( "contains", int.class, int.class); Example: Get default Rectangle constructor: Constructor c = Rectangle.class.getDeclaredConstructor(); getDeclaredMethod, getDeclaredConstructor are varargs methods

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 . . .

Inspecting Array Elements


Use static methods of Array class Object value = Array.get(a, i); Array.set(a, i, value); int n = Array.getLength(a); Construct new array: Object a = Array.newInstance(type, length);

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

Java Naming Conventions


property = pair of methods public X getPropertyName() public void setPropertyName(X newValue) Replace propertyName with actual name (e.g. getColor/setColor) Exception for boolean properties: public boolean isPropertyName() Decapitalization hokus-pokus: getColor -> color getURL -> URL

Editing Beans in a Builder Tool


Use wizard to make empty frame

Editing Beans in a Builder Tool


Add button to frame Edit button with property sheet

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

You might also like