1. The class java.lang.Object 2. Equality and hash codes

Working With Objects

3. Cloning, converting to String, finalizing 4. Type conversions 5. Autoboxing

Miloslav Sredkov
National Academy for Software Development

The Object Class
• Base class for all classes

Class java.lang.Object

• Defines the minimal requirements for all reference types • Every java programmer should be familiar with them • Only scalar types don’t inherit it don’ don’t • However their wrapper classes do

Object Members
• protected Object clone() • public boolean equals(Object obj) • public int hashCode() • public String toString() • protected void finalize() • public Class<? extends Object> getClass()

Object Members
• void notify() • void notifyAll() • void wait() • void wait(long timeout) • void wait(long timeout, int nanos) nanos)

(c) 2006 National Academy for Software Development -


Equality vs. Identity
• Identity: – Operator ==

Equality and Hash Codes

– References point to the same object • Equality: – .equals(Object) method –Means that the objects represent the –Means same abstract object

Equality Example
• Example:
String a = "fish"; String b = "fish"; String c = b; a.equals(b); // equality - true; b == c; // identity - true a == b; // identity – may be true or false

Identity and Equality
Live Demo

• If you want to compare the objects use the .equals() • If you want to check if the references point to the same object use ==

equals() Method
• Should check whether the abstract objects represented by these objects are equal • Cannot be invoked on null objects • Reflexive: x.equals(x) • Symmetric: (x.equals(y)==y.equals(x)) (x.equals(y)==y.equals(x)) • Transitive: x.equals(y) && y.equals(z) => x.equals(z)

equals() Method
• Consistent : multiple invocations of x.equals(y) return the same if the objects are not modified • x.equals(null) should return false x.equals(null) x.equals(null)

(c) 2006 National Academy for Software Development -


hashCode() Method
• Should return number based on the properties of the abstract object represented by this object • Two equal objects should have the same hash code • a.equals(b) ? a.hashCode() == b.hashCode() • a.hashCode() == b.hashCode() ? a.equals(b) • collision: (!a.equals(b))&&a.hashCode()==b.hashC (!a.equals(b))&&a.hashCode()==b.hashC (!a.equals(b))&&a.hashCode()==b.hashC ode() • Collisions decrease performance

Default Implementations
• equals() – most discriminating possible
equivalence relation on objects – x.equals(y) if x == y

• hashCode()
– returns int value based on the address of the object when overriding, override both!

Overriding Equals and Hash Code – Example
public class Point { private int x; private int y; public boolean equals(Object obj) { // correct behavior on null if(obj instanceof Point) { Point o = (Point)obj; return x == o.x && y == o.y; } return false; } public int hashCode(){ return x * 20143 ^ y * 10169; } }

Overriding Equals and Hash Code
Live Demo

• Note that the following is not correct:
public boolean equals Point o){ return x == o.x && y == o.y; }

clone() Method
• Should return a new object copy of the current • Very useful when the exact type is not known

Cloning Objects
Cloneable interface and the clone() method

• Useless for immutable objects • Usually: – x.clone()!=x – x.clone().getClass()==x.getClass() – x.clone().equals(x) • Interface Cloneable must be implemented • Default implementation–shallow copy implementation– implementation–shallow

(c) 2006 National Academy for Software Development -


clone() Example
• Example:
public class Point implements Cloneable{ private int x; private int y; public Point(int x, int y){ this.x=x; this.y=y; } ... }

clone() Example
• Cloning manually:
public Point clone(){ return new Point(x,y); }

• It is also correct to change return type:
public Point clone(){ return new Point(x,y); }

clone() Example
• Or with Object.clone() :
public Object clone(){ try { return super.clone(); } catch (CloneNotSupportedExceptione){ // Should never reach here because // we implement Cloneable e.printStrackTrace(); return null; } }

Additional Methods
toString() toString() finalize()

toString() Method
• String representation of the object • May not contain the whole state information • Should be a concise but informative • Recommended that all classes override this method • Default implementation:
return getClass().getName() + '@' getClass().getName() + Integer.toHexString(hashCode());

toString() Example
• With concatenation:
public String toString(){ toString(){ return "Point("+x+","+y+")"; "Point("+x+","+y+")"; }

• With format(): format():
public String toString(){ return String.format( "Student(fn=%d, name=%s)", fn, name); }

(c) 2006 National Academy for Software Development -


finalize() Method
• Something like destructor in other languages • Java does not support destructors! • Called before the object is garbage collected • No guarantee as to when this will happen! • May not happen before the program exits! • May be used to free resources (open files, connections) • Should be combined with other method, such as close() or dispose()

finalize() Example
• Example:
class ResourceHolder{ private ImportantResource resource; ... public void close(){ if(resource.isOpen()){ resource.close(); } } public void finalize(){ close(); }

clone() and toString()
Live Demo

Comparing Objects
Comparable and Comparator interfaces

Comparable Interface
• This interface imposes a total ordering on the objects of each class that implements it • Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort) • Example:

Comparable Interface – Example
public class Student implements Comparable{ private String firstName; private String lastName; private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; }

(c) 2006 National Academy for Software Development -


Comparable Interface – Example
public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int compareTo(Object student) { If(!(student instanceof Student)){ throw new ClassCastException("A Student object expected."); } int studentAge = ((Student) student).getAge(); return this.age-studentAge; this.age} } }

Comparable Interface – Example
public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int compareTo(Object student) { if(!(student instanceof Student)){ throw new ClassCastException("A Student object expected."); } int studentAge = ((Student)student).getAge(); return this.age-studentAge; this.age}

Comparator Interface
• Objects are sometimes comparable in Objects many ways • In cases like this, create a Comparator that defines how to compare two objects • To make objects comparable in two ways, then you need two comparators

Comparator Interface – Example
public class LastNameComparator implements Comparator { public int compare(Object student1, Object student2) { String lastName1 = ((Student) student1).getLastName().toUpperCase(); String firstName1 = ((Student) student1).getFirstName().toUpperCase(); String lastName2 = ((Student) student2).getLastName().toUpperCase(); String firstName2 = ((Student) student2).getFirstName().toUpperCase(); if (!(lastName1.equals(lastName2))){ (!(lastName1.equals(lastName2))){ return lastName1.compareTo(lastName2); }else{ else{ return firstName1.compareTo(firstName2); } } }

Comparable and Comparator
Live Demo

Type conversions

(c) 2006 National Academy for Software Development -


Type Casting
• The (Type) operator • Cannot be redefined • May be used between primitive types • May be used to cast between subclass and superclass • Other usages are not allowed!

Primitive Types
• Automatic conversion is performed in the following order: byte -> short -> int -> long -> float -> double -> -> -> -> -> • Note that accuracy may be lost when converting to floating point types • char may be converted automatically to int, long, float, and double long, float, • The result of arithmetic operations with byte and short is int! int! • In all other cases explicit conversion is needed

Primitive Types Example
int i = 5; // float f = 5.5; error float f = 5.5f; //i = f; error i = (int) f; // ok, i = 5 f = i; //ok, f=5 byte b = 5; short s = 10; //b = b + b; error //b=(byte) b + b; still error b = (byte) (b + b); //ok //s=b+b;error

Primitive Types Example
s = (short) (b + b); //ok double d = f; //ok d = b; //ok char c = ’A’; s i i = = = c; //error c; //ok,i=65 c * c * c; //oki=274625

long l = i * i; //bad,l=-1890520703 //bad,l=long l2=(long) i * i; //l2=75418890625 float f2=l2; //f2=75418894336


To Superclass/Interface
• Automatic conversion is performed when object has to be used as some of its supertypes

Primitive Types
Live Demo

• You can assign every object to Object variable • You can pass everything as Object argument • Explicit casting is still allowed and may be used to improve readability or to invoke another overload of a method.

(c) 2006 National Academy for Software Development -


To Superclass/Interface
public class Point extends Object implements Cloneable,Comparable{ ... } public class Test { public static void main(String[] args) { main(String[] args) Point p= new Point(3, 2); Object o = p; Cloneable c = p; ArrayList list = new ArrayList(); list.add(o); // no casting list.add(p); // PointtoObject list.add(c); // CloneabletoObject } }

Casting to Subtype
• Casting to subtype must be done explicitly • It is dangerous but sometimes necessary • Has to be done when overriding some Object methods • If the object is not from the given subtype exception is thrown • If you perform too much conversions to subtype you should review the design • Generics reduce the number of necessary subtype conversions

Casting to Subtype
• It is also necessary when using not generic collections:
Point p= new Point(2, 5); ArrayList list = new ArrayList(); list.add(p); // Point q = list.get(0); // compile error Point q = (Point)list.get(0); Cloneable c = (Cloneable)list.get(0); String s = (String)list.get(0); //exception

Scalars vs. Objects Boxing, Autoboxing, Unboxing

Wrapper Classes
• For each scalar type there is a wrapper class • Wrapper classes are immutable • They provide lots of methods for manipulation of the corresponding scalar type • They provide useful constants such as Integer.MIN_VALUE,Integer.MAX_VALUE Integer.MIN_VALUE,Integer.MAX_VALUE Integer.MIN_VALUE,Integer.MAX_VALUE • They support interning with the valueOf() method

The Old Way of Boxing
• Primitive types (int, short, long...) are (int, short, long...) (int, not objects • They are not acceptable as Object parameters • To put int in collection you had to box it: list.add(new Integer(i)) list.add(new • To get int from a collection you had to unbox it: int x = (Integer)c.get(key).intValue(); Integer)c.get(key).intValue(); (Integer)c.get(key).intValue();

(c) 2006 National Academy for Software Development -


• Autoboxing is added in Java 5 • You can pass a primitive type as argument instead of its wrapper class or Object • You can assign primitive type to a variable of its wrapper class • Boxing is done behind the scene • Boxing decreases performance! (this is valid for both auto and manual boxing!)

• You can pass an object of the wrapper class as argument instead of its corresponding primitive type • You can assign an object of the wrapper class primitive type to a variable of its wrapper class • You can perform arithmetic operations with objects of the wrapper classes • Unboxing is done transparently

Boxing Map
Scalar byte short int long float double boolean char Class Byte Short Integer Long Float Double Boolean Character

Autoboxing Example
• Counting the word frequency:
public static void main(String[]args){ Map<String,Integer> m = new TreeMap<String,Integer>(); for (String word : args){ Integer freq = m.get(word); m.put(word, freq== null ? 1 : freq + 1); } System.out.println(m); }

Autoboxing Example
• List adapter for int array:
public static List<Integer> asList( final int[] a){ return new AbstractList<Integer>(){ public Integer get(int i){ return a[i]; } // Not working if val == null public Integer set( int i, Integer val){ Integer oldVal = a[i]; a[i] = val; return oldVal; } public int size(){ return a.length; } }; }}

• Override the appropriate Object methods depending on how your class will be used • Follow the recommendations strictly! • Think that the user of your objects may not know their type • If these methods are not enough implement additional like equalsIgnoreCase(), md5HashCode(), equalsIgnoreCase(), deepToString() deepToString()

(c) 2006 National Academy for Software Development -


Working With Objects

1. Comment the following equals and hashCode implementations:
hashCode() equals() default return this ==obj; return this ==obj; return true; true; return false; false; return x == obj.x;


return 5; return 0; default return 0; return 0; return x;

return x; return x == obj.x && y == obj.y; return x ^ y; return x == obj.x && y == obj.y;

2. When is the clone() method usable? 3. If you implement a collection class, how will you implement toString() 4. Will it be necessary for a collection class to override the finalize() method? 5. If you have classes CartesianPoint and PolarPoint which both inherit Point, how Point, will you make conversions between them?

6. Create a class which overrides the finalize() method to print a message to the standard output. Allocate some object and experiment with System.gc(). Try to System.gc(). finalize the objects without it. 7. Create a class representing a Customer (names and address only) and override all Object methods except the synchronization ones. 8. Try to store and access some of the objects in HashMap. HashMap. 9. Try to make your objects usable in TreeMap

(c) 2006 National Academy for Software Development -