## Object-Oriented Design & Patterns

#### Cay S. Horstmann

### Chapter 7

### The Java Object Model

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

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

- Example: `ArrayList
  `

      ArrayList numbers = new ArrayList();
      numbers.add(new Integer(13));
      int n = ((Integer)numbers.get(0)).intValue();

## Enumerated Types

- Finite set of values
- Example: { SMALL, MEDIUM, LARGE }
- Java has no syntax for enumerated types
- Can fake them with integer constants
  public static final int SMALL = 1;
  public static final int MEDIUM = 2;
  public static final int LARGE = 3;
- Not typesafe
  int size = LARGE;
  size++;

## Typesafe Enumerations

- Class with fixed number of instances
  public class Size
  {
  private Size(String name) { this.name = name; }
  private String name;
  public static final Size SMALL = new Size("SMALL");
  public static final Size MEDIUM = new Size("MEDIUM");
  public static final Size LARGE = new Size("LARGE");
  }
- Private constructor!
- String field not necessary (but convenient for toString, serialization)
- Typical use:
  Size imageSize = Size.MEDIUM;
  if (imageSize == Size.SMALL) . . .

## 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 (x 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 + "]";
         }
         ...
      }

- Typical string

      Manager[name=Dolly Dollar,salary=100000][department=Finance]

- Note that superclass reports actual class name

## 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
         {
            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.equals`Method

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

- `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 (int i = 0; i < fields.length; i++)
         if (Modifier.isStatic(fields[i].getModifiers()))
            System.out.println(fields[i].getName());

## Enumerating Constructors

- Print the names and parameter types of all `Rectangle`
  constructors:

      for (int i = 0; i < cons.length; i++)
      {
         Class[] params = cons[i].getParameterTypes();
         System.out.print("Rectangle(");
         for (int j = 0; j < params.length; j++)
         {
            if (j > 0) System.out.print(", ");
            System.out.print(params[j].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",
         new Class[] { int.class, int.class });

- Example: Get default `Rectangle` constructor:

      Constructor c = Rectangle.class.getDeclaredConstructor(
         new Class[] {});

## 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",
         new Class[] { String.class } );
      m.invoke(System.out,
         new Object[] { "Hello, World!" });

## 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/FieldTest.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);

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

## Facade Class

- Bean usually composed of multiple classes
- One class nominated as facade class
- Clients use only facade class methods

## Facade 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

## Facade Pattern

Name in Design Pattern | Actual Name (Beans)
Client | Builder tool
Facade | Main bean class with which the tool interacts
SubsystemClass | 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/carbean1/CarBean.java
- Create manifest file
  Ch7/carbean1/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

## Bean Information

- Builder environment loads beans
- Looks for `get/set` methods in facade class
- Can discover spurious properties
  `JButton: Object getTreeLock()`
- Alternate mechanism: BeanInfo class
- Must have name `FacadeClassNameBeanInfo`
- E.g. `HouseBeanBeanInfo`

## The BeanInfo Interface

    Image getIcon(int iconKind)
    BeanDescriptor getBeanDescriptor()
    MethodDescriptor[] getMethodDescriptors()
    PropertyDescriptor[] getPropertyDescriptors()
    EventSetDescriptor[] getEventSetDescriptors()
    int getDefaultEventIndex()
    int getDefaultPropertyIndex()
    BeanInfo[] getAdditionalBeanInfo()

## Removing Spurious Properties

    class MyBeanBeanInfo extends SimpleBeanInfo
    {
       public PropertyDescriptor[] getPropertyDescriptors()
       {
          try
          {
             return new PropertyDescriptor[]
             {
                new PropertyDescriptor("x", CarBean.class);
                new PropertyDescriptor("y", CarBean.class);
             };
          }
          catch (IntrospectionException exception)
          { return null; }
       }
    }

## Property Editors

- Property sheet enumerates properties
- Allows user to edit property values
- How can one edit values of arbitrary types?
- Built-in editors for `String`, `Color`, etc
- Supply custom editor for your own types

## Custom Property Editors

- Three kinds of editors

- Text

- Finite set of choices
- Arbitrary painting and editing

- Implement `PropertyEditor` interface
- Or extend `PropertyEditorSupport` class

## Editing Text Properties

- Convert between your type and `String`
- Define two methods

      public String getAsText()
      public void setAsText(String s)

- Property sheet uses text field

## Editing Choice Properties

- Your type has finite set of string choices
- E.g. `DrawMode.DRAW`, `DrawMode.FILL`
- `String[] getTags()` returns array of choices
- Also need to define `getAsText/setAsText`
- Property sheet uses combo box

## Editing Arbitrary Properties

- Your type isn't easily editable as string
- E.g. `Color`
- Property editor pops up your edit dialog

- `boolean supportsCustomEditor()` must return `true`
- `Component` `getCustomEditor()` returns dialog

- Property editor can paint current value of your type

- `boolean isPaintable()` must return `true`
- `void paintValue(Graphics g, Rectangle bounds)` paints

## Registering Property Editors

- Global setting

      PropertyEditorManager.registerEditor(valueClass, editorClass)

- Per-bean setting
  In bean info class:

      PropertyDescriptor dimensionProperty = new PropertyDescriptor(
         "dimension", CarBean.class);
      dimensionProperty.setPropertyEditorClass(DimensionEditor.class);

## Example: CarBean

- Ch7/carbean2/CarBean.java
- Ch7/carbean2/CarBeanBeanInfo.java
- Ch7/carbean2/DimensionEditor.java
- Ch7/carbean2/DrawMode.java
- Ch7/carbean2/DrawModeEditor.java
- Ch7/carbean2/CustomColorEditor.java

## Example: CarBean

## Implementing a Property Sheet

- Used for graph framework in chapter 8
- Form shows property names on left, editors on right

## Implementing a Property Sheet

- Get bean info for class
- Get properties from bean info
- Obtain property getter/setter methods from property descriptor
- Use these methods to read and write property values
- Each editor is text field, combo box, or button with painted icon
- Clicking on button brings up dialog
- Ch7/propedit/PropertySheet.java
- Ch7/propedit/PropertySheetTest.java