Object Oriented Programming in Java Introduction

Object Oriented Programming in Java

Introduction to Computer Science II I Java is Object-Oriented

I Not pure object oriented

Christopher M. Bourke I Differs from other languages in how it achieves and implements OOP [email protected] functionality

I OOP style programming requires practice

Objects in Java Objects in Java

Java is a class-based OOP language

Definition Contrast with proto-type based OOP languages

A class is a construct that is used as a blueprint to create instances of I Example: JavaScript itself. I No classes, only instances (of objects)

I Constructed from nothing (ex-nihilo)

I Objects are concepts; classes are Java’s realization of that concept I Inheritance through cloning of original prototype object

I Classes are a definition of all objects of a specific type (instances) I Interface is build-able, mutable at runtime

I Classes provide an explicit blueprint of its members and their visibility

I Instances of a class must be explicitly created

Objects in Java Objects in JavaI Paradigm: Singly-Rooted Hierarchy Object methods

1 //ignore: 2 protected Object clone(); 3 protected void finalize(); I All classes are subclasses of Object 4 Class getClass(); 5 I Object is a java object, not an OOP object 6 //multithreaded applications: I Makes garbage collection easier 7 public void notify(); 8 public void notifyAll(); I All instances have a type and that type can be determined 9 public void wait(); I Provides a common, universal minimum interface for objects 10 public void wait(long timeout); I Avoids complex lattice relations in other OOP languages: no multiple 11 public void wait(long timeout, int nanos); inheritance 12 13 //important ones: 14 public boolean equals(Object obj); 15 public int hashCode(); 16 public String toString(); Objects in JavaII Declaring Classes Object methods Syntax

I Classes must be defined in file of the same name ( .java )

I equals returns true/false whether or not obj is equal to this I Class names should be upper-camel case, singular form

I Default behavior: uses reference comparison 1 package foo.bar; I hashCode returns an integer hash of this object 2 3 /* imports here */ I Default behavior: typically the memory address of the object 4 I toString provides a human readable representation of the object 5 public class MyClass{ I Default behavior: qualified class name plus JVM memory address 6 7 /* static field declarations */ 8 /* member field declarations */ 9 /* member method declarations */ 10 11 }

Object Life CycleI Object Life CycleII

Instantiation Persistence I New objects created using the new operator: Student s= new Student(); I Instances persist until they are out of scope, no longer referenced, etc.

I All classes have a default constructor if no constructor is defined I Can be serialized (written to disk, database, or transmitted over a

I If non-default constructor defined, default constructor is not provided network)

I Can have multiple constructors I Serializable interface, using writeObject(java.io.ObjectOutputStream out) I Good practice: constructor variants should call other constructors when appropriate readObject(java.io.ObjectInputStream in)

I Example: this(...)

I If calling another constructor: must be done first!

Object Life CycleIII Inner Classes

Destruction

I Can set a reference to null: Integer a= 10;a= null; I Java allows you to declare a class within a class I When no reference to an object exists, eligible for garbage collection I Visibility: allowed to be public, private, protected

I No guarantee of when it gets destroyed I Static or not

I No destructors in Java I Static fields must be final

I Cannot rely on finalize() I No static methods allowed unless inner class is static

I Cannot rely on System.gc() I Example?

I Good practice: Do all cleanup manually in a finally block Anonymous ClassesI Anonymous ClassesII

1 List myNumbers= new ArrayList(); 2 ... I An anonymous class is a class declared and defined inline 3 Collections.sort(myNumbers, new Comparator(){ I Not bound to a (class) name or identifier 4 @Override 5 public int compare(Integer arg0, Integer arg1){ I Useful idiom: allows you to provide a component declared and 6 if(arg0 == null) return-1; defined inline as an argument 7 else if(arg1 == null) return1; I Not just a convenience: prevents reuse of an ad-hoc class 8 else return arg0.compareTo(arg1); 9 }}); I Example: providing a comparator to the collection’s sort method Note: Normally, the sort method cannot handle null values, here we do!

Abstract Classes Abstraction

I A class can be made abstract I All public methods and fields available to client code

I Such a class cannot be instantiated I Static methods/fields available without an instance

I Instances must be created from non-abstract subclasses I Interfaces (revisited)

I May contain abstract and non-abstract methods I Abstract classes (revisited) I final keyword: I Non-abstract methods provide a “default” behavior for subclasses I A final class cannot be subclassed Need to provide a default? Use an abstract class! Don’t or don’t want to? I A final method cannot be overridden in a subclass Use an interface! I A final field cannot be reassigned (does not imply immutable)

InterfacesI InterfacesII

An interface is an abstract type that defines method signatures that Syntax: must be implemented by a class 1 public interface InterfaceName{ 2 return-type methodName(); I Methods are always public (or default) and abstract 3 ... I May also define ( final static ) constants 4 }

I No default implementation can be defined 1 public class Foo implements InterfaceA, InterfaceB{ I A class can implements multiple interfaces 2 ... 3 } I Allows us to simulate multiple inheritance without being locked into a hierarchy Interface Example Advantages of an interfaceI

1 public interface Gradeable{ 2 public double getScore(); 3 public String getLabel(); 4 } Interfaces provide a means to: 5 ... 6 public class Exam implements Gradeable{ I Simulate multiple inheritance 7 ... 8 public double getScore(){ I Provide interface (an is-a relationship) without locking you into a 9 return this.numPoints/ this.totalPoints; hierarchy 10 } 11 public String getLabel(){ 12 return "Exam: "+ this.examNumber; 13 } 14 }

Advantages of an interfaceII Other interface items

Example:

I Collections framework: java.util.List , java.util.Set Person Payable I Note: an interface can extend other interfaces (sub/super interface)

I Example: java.util.List extends java.util.Collection

Intern Employee Supplier I Though not a class, still provides the is-a relation

I You can refer to an implementing class as its interface:

Hourly Salaried 1 List l= null; 2 ArrayList al= new ArrayList(); Figure : Inheritance through interfaces 3 l= al;

Encapsulation InheritanceI

I Encapsulation achieved through declaring member fields, methods

I Visibility provides protection I Java supports inheritance through subclassing I Common idiom: Mutators and Accessors (getters and setters) I Syntax: extends keyword public class MySubClass extends MySuperClass{ ...} Modifier Class Package Subclass World I Superclass methods and fields are inherited (provided they are not public Y Y Y Y private) protected Y Y Y N I Subclasses may override superclass methods none (default) Y Y N N private Y N N N I Good practice: use the @Override annotation

Table : Java Access Levels InheritanceII Composition

I Subclass methods can access super class methods and fields using I Java supports composition through the same mechanism as super encapsulation I Can be a pure substitution: no new methods introduced in a I A Java class can have classes as members subclass, or I What’s responsible for constructing it? I New methods may be declared in a subclass I May be completely internal, may be provided, etc. I Preventing subclassing: final (examples: java.lang.Integer , libraries) 1 public class Foo{ I Recall: all methods in Java are virtual by default 2 private Integer a; 3 private Graph g; I Note: a pure virtual method in java is an abstract method 4 protected List myList; 5 }

Polymorphism Automatic Type CastingI

I Many mechanisms for polymorphism

I Many different types of polymorphism supported I Numerical operators support mixed types ( int, double , etc.) I Some types not supported: I Simpler types are up-casted to compatible types and (may be) I Operator overloading not allowed 1 downcasted in the final result I Behavioral polymorphism I A form of coercion I Polymorphic behavior not always apparent

1A form is enforced in that super() must be called first in a constructor, ensuring an is-a relationship before anything else can be done

Automatic Type CastingII AutoboxingI

1 inta= 10; 2 doubleb= 20.5,= 10.5,f; I Autoboxing/unboxing: mixing primitive numeric types with Java 3 intd,e; wrapper classes 4 //d = a + b; <- compile error. 5 // requires explicit cast to int, works in C! I As needed, compiler replaces expressions with value methods 6 f=a+b; I May result in runtime NullPointerException 7 e=(int)(b+c); 8 System.out.println("f = "+f); I Need to be careful when mixing types with comparison operators 9 System.out.println("e = "+e); I Form of coercion AutoboxingII AutoboxingIII

From the Java documentation: So when should you use autoboxing and unboxing? Use them only when there is an impedance mismatch between reference 1 Integer a= new Integer(10); types and primitives, for example, when you have to put 2 Double pi= new Double(3.14); numerical values into a collection. It is not appropriate to use 3 intb= 20; autoboxing and unboxing for scientific computing, or other 4 doublec=a+b+ pi; 5 //becomes: performance-sensitive numerical code. An Integer is not a 6 //double c = a.doubleValue() + b + pi.doubleValue(); substitute for an int ; autoboxing and unboxing blur the distinction between primitive types and reference types, but they do not eliminate it.

Or: when null values are needed to distinguish between missing/invalid/unknown data (tri-valued logic)

String CastingI String CastingII

How this works:

I Rather than dynamic dispatch, Java replaces string concatenation I Plus operator ( + ) is overloaded code

I Could mean addition or (string) concatenation I For efficiency, compiler replaces + with StringBuilder instances

I Can mix Strings and any other Object I StringBuilder uses (overloaded) static String.valueOf() method Object public String toString() I Since has a method I Converts null instances to the string "null" , otherwise calls object’s toString() method

I A form of operator/method overloading and coercion

String CastingIII String CastingIV

Example 2: Example 1: 1 Integer a= null; 2 System.out.println("a = "+a); 1 String a= "hello "+ "world "+ "!"; 3 a= new Integer(10); 2 //would actually become: 4 System.out.println("a = "+a); 3 String a= new StringBuilder().append("hello ") 5 a= null; 4 .append("world ").append("!").toString(); 6 System.out.println("a = "+String.valueOf(a)); 7 System.out.println("a = "+a.toString()); String CastingV Upcasting

I Upcasting is when an instance is treated as its superclass

I Form of subtype polymorphism Result: 1 public class Dog extends Animal{ 1 a= null 2 .... 2 a= 10 3 3 a= null 4 public void doSomething(Animal a){ 4 Exception in thread "..." java.lang.NullPointerException 5 //a is treated as an animal here 6 ... 7 8 Dog d= new Dog(); 9 doSomething(d); 10 //or: 11 Animal a=d;

DowncastingI DowncastingII

I Downcasting works in the opposite direction

I An instance is explicitly cast to a subclass: 1 Animal a= ... Animal a; ... 2 ... Dog d=(Dog)a; 3 Dog d= null; 4 if(a instanceof Dog){ I A subclass always has an is-a relationship 5 d=(Dog)a; I Does not work in this case: may not be-a! 6 } I May be problematic if a is not a Dog : ClassCastException

I Useful tool: instanceof

I Useful tool: getClass() method, .class static element

DowncastingIII Method OverloadingI

1 Integer c= 10; 2 if(c instanceof java.lang.Number){ I A method’s signature depends on its name and parameters 3 System.out.println("Its a numeric: "+c.getClass()); I Java allows you to overload methods; that is: 4 } 5 if(c.getClass() == java.lang.Integer.class){ I Define methods with the same names but different (number or type) 6 ... parameters 7 } I Compiler uses dynamic dispatch to call the appropriate method 8 if(c.getClass().equals(java.lang.Integer.class)){ 9 ... I However: cannot define methods with same name, parameters, but 10 } different (covariant) return types (more later) Method OverloadingII Method OverridingI

1 public void foo(){} I In a subclass (non-private, non-final) methods can be overridden 2 public int foo(Integer a){return0;} I Implementation can be changed 3 public int foo(Integer a, Double b){return0;} I Method signature and return type cannot change 4 public String foo(Double a){return "0.0";} 5 //not allowed: I Visibility can be increased but not restricted further 6 //public double foo(Double a) {return 0.0;} I Good practice: use the @Override annotation

I Still have access to the superclass’s method ( super.methodName() )

Method OverridingII Method OverridingIII

1 public class Dog extends Animal{ 1 public class Animal{ 2 ... 2 ... 3 @Override 3 protected void eat(){ 4 public void eat(){ 4 System.out.println("Eating..."); 5 System.out.println("Eating a milkbone..."); 5 } 6 } 6 ... 7 ... 7 } 8 }

Method OverridingI Covariant Return TypesI toString method

1 public class Student{ 2 private int id; I In general, an overridden method must have the same return type 3 private String firstName; 4 private String lastName; I Since Java 1.5: allowed to return a covariant type 5 ... I Return type can be changed to another type as long as the new 6 public String toString(){ return type has an is-a relation to the original 7 return this.lastName+","+ this.firstName+ 8 " ("+ this.id+ ")"; I Cannot be an arbitrary type 9 } Covariant Return TypesII Parameterized PolymorphismI

1 public classA{ 2 public Animal getOrganism(){ I Generics introduced in Java 1.5 3 ... I Named parameter syntax: 4 } 5 } public class Foo{ ...} 6 I Multiple parameter types: 7 public classB extendsA 8 @Override I Usage: Foo mc= new Foo(); 9 public Dog getOrganism(){ I Explicit parameterized types relieve us of the need to do explicit 10 ... casting 11 } 12 } I Prevents incompatible type mixing (compile time check)

Parameterized PolymorphismII Parameterized PolymorphismIII

1 //no compile error, no run time error 1 ArrayList myList2= 2 ArrayList myList= new ArrayList(); 2 new ArrayList(); 3 myList.add(new Integer(10)); 3 myList2.add(new Integer(10)); 4 myList.add(new String("ten")); 4 //compile error: 5 5 myList2.add(new String("ten")); 6 //okay: 7 Integer a=(Integer) myList.get(0); I Not the same as C++ templates 8 I Generics can be applied to: classes, interfaces, methods (as 9 //runtime error: 10 Integer b=(Integer) myList.get(1); arguments, return types, or static methods)

Parameterized PolymorphismIV Parameterized PolymorphismV

1 //unparamterized list: 1 public staticT getMax(Collection items){ 2 ArrayList myList= new ArrayList(); 2 T max= items.iterator().next(); 3 //list parameterized as Integer: 3 for(T t: items){ 4 ArrayList myList2= new ArrayList(); 4 if([some criteria here]){ 5 .... 5 max=t; 6 //warning and possible runtime exceptions: 6 } 7 Integer a= getMax(myList); 7 } 8 //best way: 8 return max; 9 Integer b= getMax(myList2); 9 } 10 //compiler error: 11 String c= getMax(myList2); Bounded PolymorphismI Bounded PolymorphismII

I Upper bound: – matches T and any subtype of T

I Lower bound: – matches T and any super type of T I Revisit the getMax example: unable to establish a criterion for comparison I Named upper bounded: - matches a particular type T which must be a subclass of type Foo I No information other than was an Object I You can also do multiple lower bounds on named parameters (but not I Illustrates the need for bounded polymorphism wildcards): I By default, all named parameters are bounded by Object I Wildcard: , equivalent to (note: you cannot have multiple classes as there is no multiple inheritance!)

Bounded PolymorphismIII Bounded PolymorphismIV

I Cannot specify upper and lower bound on the same type (for either 1 public staticT getMax( named or wildcard) 2 Collection items){ 3 I Named lower bounds do not exist 4 T max= items.iterator().next(); I Hypothetically, would match a particular type which 5 for(T t: items){ is a superclass of Foo 6 if(t.doubleValue()> max.doubleValue()){ 7 max=t; I Not that useful though: it only provides a restriction that doesn’t guarantee an interface! 8 } 9 } I In contrast, lower bounds provide a restriction that guarantees a minimal interface 10 return max; 11 }

Bounded PolymorphismV More on Bounded ParameterizationI

Using the Comparable interface:

1 public static>T getMax( It can be somewhat confusing on when to use named bounded parameters 2 Collection items){ vs. wildcard bounded parameters. 3 4 T max= items.iterator().next(); In general, if the type is not referenced elsewhere in a method, you can 5 for(T t: items){ (and arguably should) use a wildcard. 6 if(t.compareTo(max)<0){ The argument is that using a wildcard “advertises” the fact that the type 7 max=t; 8 } is unused and unimportant. 9 } However, very little is “lost” if a named parameter is used (with a very few 10 return max; limited exceptions). 11 } More on Bounded ParameterizationII More on Bounded ParameterizationIII

The only thing you know about the stuff is that they are Object s: Same, but the parameter type is named and it can now be used:

1 public static void foo(List stuff){ 1 public static void bar(List stuff){ 2 Object o= stuff.get(0); 2 T item= stuff.get(0); 3 } 3 }

More on Bounded ParameterizationIV More on Bounded ParameterizationV

By providing a bound we know more about the type T : its a subclass of But we didn’t really use the type T , so we could have instead used a BankAccount and therefore is-a BankAccount wildcard, but still provide a bound on the argument, guaranteeing a minimal interface. 1 public static double baz( 1 public static double biz( 2 List accounts){ 2 List accounts){ 3 3 4 double total= 0.0; 4 double total= 0.0; 5 for(BankAccount acct: accounts){ 5 for(BankAccount acct: accounts){ 6 total += acct.getBalance(); 6 total += acct.getBalance(); 7 } 7 } 8 return total; 8 return total; 9 } 9 }

More on Bounded ParameterizationVI More on Bounded ParameterizationVII

Alternatively, we can use both named parameters and wildcards to make However, if we do need to reference the type in the method, then we must our code a bit more general (and thus flexible to those using it). Here we use a named parameter. have the same advantages as before, but now the list can be generalized 1 public staticT buz( to any super type of T (say, for example List ). 2 List accounts, T account){ 3 1 public staticT boz( 4 if(account.getBalance()>0){ 2 List accounts, T account){ 5 accounts.add(account); 3 6 return account; 4 if(account.getBalance()>0){ 7 } else{ 5 accounts.add(account); 8 return null; 6 return account; 9 } 7 } else{ 10 } 8 return null; 9 } 10 } More on Bounded ParameterizationVIII Type Erasure & Raw TypesI

More:

I Generics introduced in Java 1.5 I Good post: http://stackoverflow.com/questions/3486689/ java-bounded-wildcards-or-bounded-type-parameter I But Collections framework introduced in Java 1.2 I Object I PECS (Producer extends, Consumer super) principle: Old interfaces (and many libraries) involve the type http://stackoverflow.com/questions/2723397/ I Example: List.add(Object obj) java-generics-what-is-pecs I Upcasting eliminates any type-specific information

Type Erasure & Raw TypesII Type Erasure & Raw TypesIII

I Java designers made a choice: backwards compatibility over strict 1 List intList= new ArrayList(); typing 2 //becomes 3 List intList= new ArrayList(); I To support backwards compatibility, the Java compiler performs Type Erasure I You should not use Raw types yourself! I At compile time, generic type information is erased and treated as a I Raw types result in runtime exceptions for incompatible types (see Raw Type: an Object previous example)

Open Recursion Copy ConstructorsI

I Copy Constructors are preferred to using Object.clone() or the I Inside classes, we need a way to reference the object itself Cloneable interface; more info:

I Open recursion (recursive because the object is referencing itself) I http://www.artima.com/intv/bloch13.html I http://www.javapractices.com/topic/TopicAction.do?Id=71 I this. allows you to access member methods/variables I http://adtmag.com/articles/2000/01/18/ I this(...) allows you to call another constructor effective-javaeffective-cloning.aspx

I super. allows you to access member methods/variables of the I All state should be copied superclass I Immutable objects can be reference-copied I super(...) allows you to call a constructor of the superclass I Mutable objects should be deep copied

I Useful methods: Arrays.copyOf(...) DemonstrationI

Design a Student object and a Course object and illustrate usage of:

I A copy constructor and deep vs. shallow copy

I Bi-directional association (roster and/or schedule)

I Potential pitfalls of bi-directional association

I Bi-directional association through an intermediate class