0% found this document useful (0 votes)
9 views

Handout

Uploaded by

Mohamed Hamed
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Handout

Uploaded by

Mohamed Hamed
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

With thanks to Dr Robert Harle who

Object Oriented Programming


designed this course and wrote the
Dr Andrew Rice
material.
IA CST and NST (CS)
Michaelmas 2019/20

1 2

The OOP Course Practical work is on chime.cl.cam.ac.uk


 So far you have studied some procedural programming in Java  Selection of exercises roughly mapped to
and functional programming in ML
 Here we take your procedural Java and build on it to get lectures
object-oriented Java  I want to write more so let me know where
 You have practical work too
you see holes
 This course complements the practicals
 Some material appears only here  Attempt to get a bit closer to what you
 Some material appears only in the practicals would do in industry
 Some material appears in both: deliberately*!  Git version control system
 Automated testing

* Some material may be repeated unintentionally. If so I will claim it was deliberate.


3 4

Drop-in sessions Other ways to get help


 Thursday afternoons are drop-in help
sessions  Use the discussion forum on Moodle
 Intel Lab: 2-4pm  Do not post your code or give answers: you’ll spoil
 21st Nov, 28th Nov, 16th Jan, 23rd Jan the practical work for others
 If you need to include your code then please
 I will be there with some demonstrators include a link to chime instead
 Come talk to me about Java  Please answer your own question if you resolve it!
 Bring your laptop if you want some help  Your supervisor
with your code  They can see your work on chime (if they ask me)
 Please do not email me directly – I get a lot of
email

5 6
Assessment (1 of 2): Tripos exam Assessment (2 of 2): Take-home test
 There are two OOP questions in Paper 1
 You will need to choose one of them  9am on 21st April – 9am on 23rd April 2020
 Previous year’s questions for this course  Pass/fail – worth 2 ticks
are a good example of what you might be  I will aim for an exercise which will take about
asked this year 4 hours (but there is big variance on this)
 Only material that I lecture is examinable  Take-home test will be done through chime too
 But no automated tests
 I’ll provide a mock test for you to try

7 8

Outline Books and Resources I


 OOP Concepts
1.How to do a practical exercise
 Look for books for those learning to first program in an OOP
2.Types, Objects and Classes language (Java, C++, Python)
3. Designing Classes  Java: How to Program by Deitel & Deitel (also C++)
4. Pointers, References and Memory  Thinking in Java by Eckels
5. Inheritance  Java in a Nutshell (O' Reilly) if you already know another OOP
language
6. Polymorphism
 Java specification book: http://java.sun.com/docs/books/jls/
7. Lifecycle of an Object  Lots of good resources on the web
8. Error Handling  Design Patterns by Gamma et al.
9. Java Collections  My favourites
10. Object Comparison  Effective Java by Joshua Bloch
11. Design Patterns  Java Puzzlers by Joshua Bloch (this one is just for fun)
12. Design Pattern (cont.)

9 10

Books and Resources II


 Also check the course web page
 Updated notes (with annotations)
 Videos of the lectures (if I can make it work)
 Links to practical work
 Code from the lectures
 Sample tripos questions
 Suggested supervision work
Lecture 1:
How to do a practical exercise
hp://www.cl.cam.ac.uk/teaching/current/OOProg/
 And the Moodle site “Computer Science Paper 1 (1A)”
 Watch for course announcements

11 12
Objectives We’d like to use your code for research
 To understand the workflow and tools to  Research into teaching and learning is
complete a practical exercise important!
 We want your consent to use your code
and share it with others
 We will ‘anonymise’ it
 Consent is optional and it has no impact
on your grades or teaching if you do not

Demo: Log into chime and opt-in/opt-out


13 14

We use git over SSH for version control Practical exercises are linked online
 Same setup as github and  Go to the course webpages to find links to
gitlab.developers.cam.ac.uk the practical exercises
 Generate an SSH key  Follow the link and start the task
 Put the public part of the key on chime

Demo: starting a task

Demo: creating an SSH key and adding it


to chime

15 16

Software licensing and copyright Using an IDE is recommended!


 Complicated area…  I’ll use IntelliJ here but you can use
 The default is that if you write software you own whatever you like
the copyright and other people can’t copy it
 You only need the (free) ‘community
 We add licenses to make it clear what people can
edition’
and can’t do
 The initial code for the tasks is Apache 2  IntelliJ has built-in support for git but you
Licensed can use the command line or other tools if
 The system assumes your changes will be you prefer
licensed the same...but they don’t have to be  Sourcetree on Mac is really nice
 Apache 2 License lets you do almost anything
 Except remove or change the license
Demo: cloning your task into a new project
Demo: licenses on your code
17 18
Maven is a build system for Java Be careful about what you check in
 In the pre-arrival course you built your  Imagine you are working in a team on a
code manually shared code base
 This doesn’t scale well  Other engineers don’t want your IDE
 Use a build system! settings
 There are many build systems for Java  Or your temp files
 All of them have strengths and weaknesses  Or your class files
 We will use Maven in this course  Or personal information!!!
 We use .gitignore to tell git to ignore some
files
Demo: Maven pom file and build
19 20

IntelliJ can run tests and a debugger Git can be very simple
Demo: solve the task, run the tests, debug  Your local repository contains all
something information
 Local workflow: add files, then commit
them
 There’s another copy on chime
 You use this as a remote
 It’s default name is ‘origin’
 Full workflow: pull updates from remote,
add and commit files, push back to
remote
21 22

Git can be complicated Chime can run acceptance tests for you
 You can have as many remotes as you  These are designed to give you feedback on
like your solution and whether its right
 You can have branches and merge  These are hard to write so please help me
improve them
changes and and and…
 If your solution was wrong but passed the tests then
 Just remember to pull before you make let me know
any changes and push when you are done  And vice-versa
and you should avoid any complexity
Demo: run tests on chime
Demo: git with IntelliJ

23 24
You should be writing your own tests
 Some tasks will measure instruction
coverage
 In this course we’re interested in ‘unit tests’
 Test a single, small piece of functionality

Demo: running tests with coverage in Lecture 2:


IntelliJ, writing a test Types, Objects and Classes

25 26

Objectives Types of Languages


 Remember procedural Java  Declarative - specify what to do, not how
 Understand function overloading to do it. i.e.
 Know the difference between a class and  E.g. HTML describes what should appear on a web page,
and not how it should be drawn to the screen
an object  E.g. SQL statements such as “select * from table” tell a
 Know how to construct an object program to get information from a database, but not how to
do so

 Imperative – specify both what and how


 E.g. “triple x“ might be a declarative instruction that you
want the variable x tripled in value. Imperatively we would
have “x=x*3” or “x=x+x+x”

27 28

Top 20 Languages 2016 Top 20 Languages 2016 (Cont)

29 30
Top 20 Languages 2016 (Cont Cont) Top 20 Languages 2016 (Cont Cont Cont)

31 32

ML as a Functional Language Function Side Effects


 Functional languages are a subset of declarative  Functions in imperative languages can use or
languages alter larger system state → procedures
 ML is a functional language
 It may appear that you tell it how to do everything, but
you should think of it as providing an explicit example
of what should happen Maths:m(x,y) = xy
 The compiler may optimise i.e. replace your
ML: fun m(x,y) = x*y;
implementation with something entirely different but
100% equivalent. Java:
int y = 7; Side e(ect
let rec factorial n = int m(int x) {
match n with y=y+1;
return x*y;
| 0 -> 1
}
| 1 -> 1
| n -> n * (factorial (n – 1)); 33 34

void Procedures Control Flow: Looping


 A void procedure returns nothing:
for( inialisaon; terminaon; increment )

for (int i=0; i<8; i++) …


int count=0; int j=0; for(; j<8; j++) …
Void is not quite the
same as unit in ML for(int k=7;k>=0; j--) ...
void addToCount() { Demo: prin9ng the numbers
count=count+1; from 1 to 10
}
while( boolean_expression )

int i=0; while (i<8) { i++; …}


count+=1 count++ ++count
int j=7; while (j>=0) { j--; ...}

35 36
Control Flow: Looping Examples Control Flow: Branching I
 Branching statements interrupt the current control flow
 return
int arr[] = {1,2,3,4,5};  Used to return from a function at any point

for (int i=0; i<arr.length;i++) {


System.out.println(arr[i]);
} boolean linearSearch(int[] xs, int v) {
for (int i=0;i<xs.length; i++) {
if (xs[i]==v) return true;
int i=0;
}
while (i<arr.length) { return false;
System.out.println(arr[i]); }
i=i+1;
}

37 38

Control Flow: Branching II Control Flow: Branching III


 Branching statements interrupt the current control flow  Branching statements interrupt the current control flow
 break  continue
 Used to jump out of a loop  Used to skip the current iteration in a loop

boolean linearSearch(int[] xs, int v) { void printPositives(int[] xs) {


boolean found=false;
for (int i=0;i<xs.length; i++) { for (int i=0;i<xs.length; i++) {
if (xs[i]==v) { if (xs[i]<0) continue;
found=true; System.out.println(xs[i]);
break; // stop looping }
} }
}
return found;
}

39 40

Immutable to Mutable Data Types and Variables


ML  Java and C++ have limited forms of type inference
- val x=5; ML is a language of expressions
> val x = 5 : int
- x=7; Java is a language of statements and expressions var x = 512;
> val it = false : bool int y = 200;
- val x=9; int z = x+y;
> val x = 9 : int
 The high-level language has a series of primitive (built-in)
types that we use to signify what’s in the memory
 The compiler then knows what to do with them
Java
Evaluates to the value 7 with type int  E.g. An “int” is a primitive type in C, C++, Java and many
int x=5; languages. In Java it is a 32-bit signed integer.
x=7;
 A variable is a name used in the code to refer to a specific
int x=9; instance of a type
for(int i=0;i<10;i++) { Does not evaluate to a value and has no type  x,y,z are variables above
System.out.println(i);  They are all of type int
}
Demo: returning vs prin9ng 41 42
E.g. Primitive Types in Java Overloading Functions
 “Primi9ve” types are the built in ones.  Same function name
 They are building blocks for more complicated types that we will be
looking at soon.  Different arguments
 boolean – 1 bit (true, false)
 char – 16 bits  Possibly different return type
Widening
 byte – 8 bits as a signed integer (-128 to 127) Vs
 short – 16 bits as a signed integer Narrowing int myfun(int a, int b) {…}
 int – 32 bits as a signed integer Hoat myfun(Hoat a, Hoat b) {…}
 long – 64 bits as a signed integer double myfun(double a, double b) {...}
 Hoat – 32 bits as a Hoa9ng point number
 double – 64 bits as a Hoa9ng point number  But not just a different return type

int myfun(int a, int b) {…}


Hoat myfun(int a, int b) {…} x
Demo: int → byte overHow 43 44

Function Prototypes Custom Types


 Functions are made up of a prototype and
type 'a seq =
a body | Nil
 Prototype specifies the function name, | Cons of 'a * (unit -> 'a seq);
arguments and possibly return type
 Body is the actual function code

public class Vector3D {


fun myfun(a,b) = …; Hoat x;
Hoat y;
int myfun(int a, int b) {...} Hoat z;
}

45 46

State and Behaviour State and Behaviour


type 'a seq = type 'a seq =
| Nil | Nil
| Cons of 'a * (unit -> 'a seq); | Cons of 'a * (unit -> 'a seq);

fun hd (Cons(x,_)) = x; fun hd (Cons(x,_)) = x;

public class Vector3D {


Hoat x;
Hoat y; STATE
Hoat z;

void add(Hoat vx, Hoat vy, Hoat vz) {


x=x+vx;
y=y+vy;
BEHAVIOUR
z=z+vz;
}
47 } 48
Loose Terminology (again!) Classes, Instances and Objects
 Classes can be seen as templates for representing
various concepts
 We create instances of classes in a similar way.
State Behaviour e.g.
Fields Func9ons MyCoolClass m = new MyCoolClass();
Instance Variables Methods MyCoolClass n = new MyCoolClass();

Proper9es Procedures makes two instances of class MyCoolClass.


Variables  An instance of a class is called an object
Members

49 50

Defining a Class Constructors


MyObject m = new MyObject();

public class Vector3D {  You will have noticed that the RHS looks rather like a function
Hoat x; call, and that's exactly what it is.
Hoat y;
Hoat z;  It's a method that gets called when the object is constructed,
and it goes by the name of a constructor (it's not rocket
void add(Hoat vx, Hoat vy, Hoat vz) {
science). It maps to the datatype constructors you saw in ML.
x=x+vx;
y=y+vy;
z=z+vz;  We use constructors to initialise the state of the class in a
} convenient way
}  A constructor has the same name as the class
 A constructor has no return type

51 52

Constructors with Arguments Overloaded Constructors


public class Vector3D { public class Vector3D {
Hoat x; Hoat x;
Hoat y; Hoat y;
Hoat z; Hoat z;

Vector3D(oat xi, oat yi, oat zi) { Vector3D(oat xi, oat yi, oat zi) {
x=xi; x=xi;
y=yi; y=yi;
z=zi; You can use ‘this’ to disambiguate names z=zi;
} if needed: e.g. this.x = xi; }

Vector3D() {
// ... x=0.f;
} y=0.f;
z=0.f;
}
Vector3D v = new Vector3D(1.f,0.f,2.f); Vector3D v = new Vector3D(1.f,0.f,2.f);
// ...
53 }
Vector3D v2 = new Vector3D(); 54
Default Constructor
public class Vector3D {
Hoat x;
Hoat y;
Hoat z;
} If you don’t ini9alise a Zeld it
gets set to the ‘zero’ value for
Vector3D v = new Vector3D(); that type (don’t do this)

If you provide any constructor


then the default will not be Lecture 3:
generated
Designing Classes

 No constructor provided
 So blank one generated with
no arguments

ya3ni lw maish
constructor he7ot 55 56
kol el data types fe
el default bta3ha
num =>0 str=>null

Objectives Class-Level Data and Functionality I


 A static field is created only once in the program's execution,
 Understand the static keyword despite being declared as part of a class
 Be able to identify what should be an
object One of these created every
public class ShopItem {
 Start thinking about why OOP helps with Hoat mVATRate; 9me a new ShopItem is
modularity sta9c Hoat sVATRate; instan9ated. Nothing keeps
.... them all in sync.
 Know what encapsulation means }
 Know what the access modifiers mean
Only one of these created ever. Every
 Be able to make an immutable object ShopItem object references it.
 Understanding of simple generics
sta9c => associated with the class
instance => associated with the object

57 58

Class-Level Data and Functionality II Why use Static Methods?


0.2  Easier to debug (only depends on static state)
0.2  Shared between  Self documenting

0.2
instances  Groups related methods in a Class without requiring an object

 Space efficient
17.5
0.2 17.5

instance Zeld sta9c Zeld public class Math { public class Math {
sta9c Zelds are good for public Hoat sqrt(Hoat x) {…} public sta9c Hoat sqrt(Hoat x) {…}
(one per object) (one per class) constants. otherwise use public double sin(Hoat x) {…} public sta9c Hoat sin(Hoat x) {…}
 Also static methods: with care. public double cos(Hoat x) {…} public sta9c Hoat cos(Hoat x) {…}
} }
vs
public class Whatever { … …
Math mathobject = new Math(); Math.sqrt(9.0);
public sta9c void main(String[] args) {
mathobject.sqrt(9.0); ...
... ...
}
}
function to be used inside the class
59 60
What Not to Do Identifying Classes
 Your ML has doubtless been one big file where  We want our class to be a grouping of conceptually-
you threw together all the functions and value related state and behaviour
declarations  One popular way to group is using grammar
 Lots of C programs look like this :-(  Noun → Object
 We could emulate this in OOP by having one  Verb → Method
class and throwing everything into it

“A quiz program that asks questions


 We can do (much) better
and checks the answers are correct”

61 62

UML: Representing a Class Graphically The has-a Association


Quiz 1 0...* Ques9on

Ques9on

- prompt : String State  Arrow going left to right says “a Quiz has zero or more
- solu9on: String questions”
“-” means
private access + ask() : void  Arrow going right to left says “a Question has exactly 1 Quiz”
+ check(answer : String) : boolean Behaviour  What it means in real terms is that the Quiz class will contain
a variable that somehow links to a set of Question objects,
and a Question will have a variable that references a Quiz
“+” means object.
public access  Note that we are only linking classes: we don't start drawing
arrows to primitive types.

Demo: implement quiz


63 64

Anatomy of an OOP Program (Java) OOP Concepts


Class name
Access modiZer  OOP provides the programmer with a
public class MyFancyClass {
Class state (proper9es that an number of important concepts:
public int someNumber; object has such as colour or size)
public String someText;
 Modularity
public void someMethod() { Class behaviour (ac9ons an
object can do)  Code Re-Use
}
'Magic' start point for
 Encapsulation
public sta9c void main(String[] args) { the program (named  Inheritance (lecture 5)
MyFancyClass c = new main by conven9on)
MyFancyClass();  Polymorphism (lecture 6)
}

}  Let's look at these more closely...


Create a reference to a Create an object of type
MyFancyClass object and call MyFancyClass in memory
it c 65 66
Modularity and Code Re-Use Encapsulation I
 You've long been taught to break down complex class Student {
problems into more tractable sub-problems. int age;
 Each class represents a sub-unit of code that (if };
written well) can be developed, tested and updated
independently from the rest of the code. void main() {
 Indeed, two classes that achieve the same thing Student s = new Student();
(but perhaps do it in different ways) can be swapped s.age = 21;
in the code
Student s2 = new Student();
 Properly developed classes can be used in other
s2.age=-1;
programs without modification.
Student s3 = new Student();
s3.age=10055;
}
67 68

Encapsulation II Encapsulation III


class Student {
private int age; class Loca9on { class Loca9on {
private Hoat x;
boolean setAge(int a) { private Hoat y; private Vector2D v;
if (a>=0 && a<130) {
Hoat getX() {return x;} Hoat getX() {return v.getX();}
age=a; Hoat getY() {return v.getY();}
Hoat getY() {return y;}
return true;
} void setX(Hoat nx) {v.setX(nx);}
void setX(Hoat nx) {x=nx;}
return false; void setY(Hoat ny) {y=ny;} void setY(Hoat ny) {v.setY(ny);}
} } }

int getAge() {return age;}


}
Encapsula9on =
1) hiding internal state
void main() { 2) bundling methods with state
Student s = new Student();
s.setAge(21);
} 69 1-set all properties to private 70
2-add get and set to each property

Access Modifiers Immutability


 Everything in ML was immutable (ignoring the
Everyone Subclass Same Same reference stuff). Immutability has a number of
package Class advantages:
(Java)
 Easier to construct, test and use
private X  Can be used in concurrent contexts
 Allows lazy instantiation
package X X  We can use our access modifiers to create
(Java) Surprising!
immutable classes
protected X X X  If you mark a variable or field as ‘final’ then it can’t
be changed after initalisation
public X X X X Immutable classes are classes whose objects cannot be modified after
they are created
Demo: NotImmutable
71 72
subclasses are some classes that inherit the super class
so the protected will be appeared for them
Parameterised Classes Creating Parameterised Types
 ML's polymorphism allowed us to specify functions that could  These just require a placeholder type
be applied to multiple types

> fun self(x)=x; Fun fact: iden9ty is the only class Vector3D<T> {
val self = fn : 'a -> 'a func9on in ML with type ‘a → ‘a
private T x;
private T y;
 In Java, we can achieve something similar through Generics;
C++ through templates T getX() {return x;}
T getY() {return y;}
 Classes are defined with placeholders (see later lectures)
 We fill them in when we create objects using them void setX(T nx) {x=nx;}
void setY(T ny) {y=ny;}
LinkedList<Integer> = new LinkedList<Integer>() }

LinkedList<Double> = new LinkedList<Double>()

73 74

Generics use type-erasure


class Vector3D<T> { class Vector3D {
private T x; private Object x;
private T y; private Object y;

T getX() {return x;} Object getX() {return x;}


T getY() {return y;} Object getY() {return y;}

void setX(T nx) {x=nx;} a_er type void setX(Object nx) {x=nx;}
void setY(T ny) {y=ny;} checking void setY(Object ny) {y=ny;} Lecture 4:
this
} }
compiles Pointers, References and Memory
to
------>
Vector3D<Integer> v = Vector3D v = new Vector3D();
new Vector3D<>(); Integer x = (Integer)v.getX();
Integer x = v.getX(); v.setX((Object)4);
v.setX(4);

75 76

Objectives
>> 1 static int sum() {
2 int s = sum(3);
 Know what a call-stack and a heap are 3 return s;
4 }
 Understand the difference between 5
6 static int sum(int n) {
pointers and Java references 7 if (n == 0) {
8 return 0;
9 }
10 int m = sum(n - 1);
11 int r = m + n;
12 return r;
13 }

77
>> 1 static int sum() { sum() 1 static int sum() { sum()
s >> 2 s
2 int s = sum(3); int s = sum(3);
3 return s; 3 return s;
4 } 4 }
5 5
6 static int sum(int n) { 6 static int sum(int n) {
7 if (n == 0) { 7 if (n == 0) {
8 return 0; 8 return 0;
9 } 9 }
10 int m = sum(n - 1); 10 int m = sum(n - 1);
11 int r = m + n; 11 int r = m + n;
12 return r; 12 return r;
13 } 13 }

1 static int sum() { sum() 1 static int sum() { sum()


>> 2 s s
int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 arg1 4 } 3 n
5 5 m
6 static int sum(int n) { >> 6 static int sum(int n) { r
7 if (n == 0) { 7 if (n == 0) {
8 return 0; 8 return 0;
9 } 9 }
10 int m = sum(n - 1); 10 int m = sum(n - 1);
11 int r = m + n; 11 int r = m + n;
12 return r; 12 return r;
13 } 13 }

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
>> 7 if (n == 0) { 7 if (n == 0) {
8 return 0; 8 return 0;
9 } 9 }
10 int m = sum(n - 1); >> 10 int m = sum(n - 1);
11 int r = m + n; 11 int r = m + n;
12 return r; 12 return r;
13 } 13 }
1 static int sum() { sum() 1 static int sum() { sum()
s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r >> 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 arg1 8 return 0; 2 n
9 } 9 } m
>> 10 int m = sum(n - 1); 10 int m = sum(n - 1); r
11 int r = m + n; 11 int r = m + n;
12 return r; 12 return r;
13 } 13 }

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
>> 7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } m 9 } m
10 int m = sum(n - 1); r >> 10 int m = sum(n - 1); r
11 int r = m + n; 11 int r = m + n;
12 return r; 12 return r;
13 } 13 }

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r >> 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } m 9 } m
>> 10 int m = sum(n - 1); r 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return 11 int r = m + n; sum(1) 10 return
12 return r; 1 arg1 12 return r; 1 n
13 } 13 } m
r
1 static int sum() { sum() 1 static int sum() { sum()
s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
>> 7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } m 9 } m
10 int m = sum(n - 1); r >> 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return 11 int r = m + n; sum(1) 10 return
12 return r; 1 n 12 return r; 1 n
13 } m 13 } m
r r

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r >> 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } m 9 } m
>> 10 int m = sum(n - 1); r 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return 11 int r = m + n; sum(1) 10 return
12 return r; 1 n 12 return r; 1 n
13 } m 13 } m
r r
sum(0) 10 return sum(0) 10 return
0 arg1 0 n
m
r

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
>> 7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n >> 8 return 0; 2 n
9 } m 9 } m
10 int m = sum(n - 1); r 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return 11 int r = m + n; sum(1) 10 return
12 return r; 1 n 12 return r; 1 n
13 } m 13 } m
r r
sum(0) 10 return sum(0) 10 return
0 n 0 n
m m
r r
1 static int sum() { sum() 1 static int sum() { sum()
s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
>> 8 return 0; 2 n >> 8 return 0; 2 n
9 } m 9 } m
10 int m = sum(n - 1); r 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return 11 int r = m + n; sum(1) 10 return
12 return r; 1 n 12 return r; 1 n
13 } m 13 } m
r r
sum(0) 10 return sum(0) 10 return
0 n Return the value 0 and then 0 n
m execute instruc9on 10 m
r r

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } m 9 } m
>> 10 int m = sum(n - 1); r 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return >> 11 int r = m + n; sum(1) 10 return
12 return r; 1 n 12 return r; 1 n
13 } 0 m 13 } 0 m
r 1 r

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } m 9 } 1 m
10 int m = sum(n - 1); r >> 10 int m = sum(n - 1); r
11 int r = m + n; sum(1) 10 return 11 int r = m + n;
>> 12 return r; 1 n 12 return r;
13 } 0 m 13 }
1 r

Return the value 1 and then


execute instruc9on 10
1 static int sum() { sum() 1 static int sum() { sum()
s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 m 5 m
6 static int sum(int n) { r 6 static int sum(int n) { r
7 if (n == 0) { sum(2) 10 return 7 if (n == 0) { sum(2) 10 return
8 return 0; 2 n 8 return 0; 2 n
9 } 1 m 9 } 1 m
10 int m = sum(n - 1); 3 r 10 int m = sum(n - 1); 3 r
>> 11 int r = m + n; 11 int r = m + n;
12 return r; >> 12 return r;
13 } 13 }

Return the value 3 and then


execute instruc9on 10

1 static int sum() { sum() 1 static int sum() { sum()


s s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s; sum(3) 2 return
4 } 3 n 4 } 3 n
5 3 m 5 3 m
6 static int sum(int n) { r 6 static int sum(int n) { 6 r
7 if (n == 0) { 7 if (n == 0) {
8 return 0; 8 return 0;
9 } 9 }
>> 10 int m = sum(n - 1); 10 int m = sum(n - 1);
11 int r = m + n; >> 11 int r = m + n;
12 return r; 12 return r;
13 } 13 }

1 static int sum() { sum() 1 static int sum() { sum()


s >> 6 s
2 int s = sum(3); 2 int s = sum(3);
3 return s; sum(3) 2 return 3 return s;
4 } 3 n 4 }
5 3 m 5
6 static int sum(int n) { 6 r 6 static int sum(int n) {
7 if (n == 0) { 7 if (n == 0) {
8 return 0; 8 return 0;
9 } 9 }
10 int m = sum(n - 1); 10 int m = sum(n - 1);
11 int r = m + n; 11 int r = m + n;
>> 12 return r; 12 return r;
13 } 13 }

Return the value 6 and then


execute instruc9on 2
Distinguishing References and Pointers
1 static int sum() { sum()
6 s
2 int s = sum(3);
>> 3 return s; Pointers References
4 } in Java
5
6 static int sum(int n) { Can be unassigned Yes Yes
7 if (n == 0) { (null)
8 return 0;
9 } Can be assigned to Yes Yes
10 int m = sum(n - 1); established object
11 int r = m + n;
Can be assigned to an Yes No
12 return r;
arbitrary chunk of
13 }
memory
Can be tested for validity No Yes
Return the value 6 and then
execute whatever called us
Can perform arithmetic Yes No

110

References in Java
 Declaring unassigned
SomeClass ref = null; // explicit

SomeClass ref2; // implicit

 Defining/assigning
// Assign
SomeClass ref = new ClassRef(); Lecture 5: Inheritance

// Reassign to alias something else


ref = new ClassRef();

// Reference the same thing as another reference


SomeClass ref2 = ref;
111 112

Objectives Argument Passing


 Pass-by-value. Copy the value into a new one in
the stack
 Understand what pass-by-value means in void test(int x) {...}
Java int y=3;
test(y);
 Know the difference between code and
void test(Object o) {…}
type inheritance Object p = new Object();
test(p);
 Can apply narrowing and widening to
subtyping relations The value passed here is the
reference to the object.
 Appreciate how fields are inherited and
shadowed When run the test method’s
argument o is copy of the reference
 Know how to override a method p that points to the same object

113 114
Passing Procedure Arguments In Java Inheritance I
class Student {  There is a lot of duplication here
the value here is an int
class Reference { private int age;
private String name;
 Conceptually there is a hierarchy that we're
public sta9c void update(int i, int[] array) { private int grade; not really representing
i++; ...  Both Lecturers and Students are people
array[0]++; the value here is a reference to an int array }
(no, really).
}
class Lecturer {  We can view each as a kind of
private int age;
public sta9c void main(String[] args) {
private String name; specialisation of a general person
int test_i = 1;
int[] test_array = {1};
private int salary;  They have all the properties of a person
prints 1 …
update(test_i, test_array);
}  But they also have some extra stuff
System.out.println(test_i);
System.out.println(test_array[0]);
specific to them
prints 2
}

}
Demo: expression evaluator

Demo: reference aliasing 115 116

Inheritance II Liskov Substitution Principle


class Person {  We create a base class (Person)  If S is a subtype of T then objects of type T
protected int age; and add a new notion: classes can
protected String name;
inherit properties from it may be replaced with objects of type S
...
}  Both state, functionality and type  Student is a subtype of Person so
class Student extends Person {  We say: anywhere I can have a Person I can have
private int grade;
...
 Person is the superclass of a Student instead
} Lecturer and Student
 Lecturer and Student subclass
class Lecturer extends Person {
private int salary; Person
...
} ‘extends’ in Java gives you both code- and type-inheritance

Note: Java is a nomina*ve type language (rather than a structurally


typed one)

If you mark a class ‘Znal’ then it can’t be extended and ‘Znal’ methods
can’t be overridden
117 118

Representing Inheritance Graphically Casting


Person Also known as an “is-a” rela9on  Many languages support type casting
name As in “Student is-a Person” between numeric types
age

int i = 7;
Hoat f = (Hoat) i; // f==7.0
double d = 3.2;
Specialise

int i2 = (int) d; // i2==3


Generalise

Student Lecturer
 With inheritance it is reasonable to type
exam_score
salary
cast an object to any of the types above it
in the inheritance tree...
name and age
inherited if not
private
119 120
Widening Narrowing
Person  Student is-a Person Person  Narrowing conversions move down
 Hence we can use a Student object the tree (more specific)
anywhere we want a Person object  Need to take care...
 Can perform widening conversions
Student (up the tree) Student
OK because underlying object
really is a Student

Student s = new Student() public void print(Person p) {...} Person p = new Person(); public void print(Person p) {
Student s = (Student) p;
Person p = s; Student s = new Student(); Student s = (Student) p; }
print(s);
Student s = new Student();
FAILS at run9me. Not enough info
print(s);
In the real object to represent
Implicit widening 121 a Student 122

Fields and Inheritance Fields and Inheritance: Shadowing


class A { public int x; }

class B extends A {
class Person { Student inherits this as a public public int x; ‘this’ is a reference to the current object
public String name; variable and so can access it }
protected int age; ‘super’ is a reference to the parent object
private double height; class C extends B {
public int x; all classes extend Object (capital O)
} Student inherits this as a
protected variable and so can public void ac9on() {
if you write ‘class A {}’ you actually get
class Student extends Person { // Ways to set the x in C
access it ‘class extends Object {}’
x = 10;
public void do_something() {
this.x = 10;
name=”Bob”; Object a = new A(); // subs9tu9on principle
age=70; Student inherits this but as a // Ways to set the x in B
height=1.70; private variable and so cannot super.x = 10;
} access it directly ((B)this).x = 10; Don’t write code like this. No-one will
This line doesn’t compile understand you!
} // Ways to set the x in A
((A)this.x = 10;
}
123 } 124

Methods and Inheritance: Overriding Abstract Methods


 We might want to require that every Person can dance. But the way  Sometimes we want to force a class to implement a method
a Lecturer dances is not likely to be the same as the way a Student but there isn't a convenient default behaviour
dances...
 An abstract method is used in a base class to do this
Know the di(erence: overriding vs overloading
 It has no implementation whatsoever
class Person {
Person deZnes an
public void dance() { original implementa9on class abstract Person {
jiggle_a_bit(); of dance() public abstract void dance();
} }
}
class Student extends Person {
class Student extends Person { public void dance() {
Student overrides the body_pop();
public void dance() { }
original
body_pop(); }
}
} class Lecturer extends Person {
public void dance() {
Lecturer overloads the Lecturer inherits the
jiggle_a_bit();
inherited dance() class Lecturer extends Person { original implementa9on }
method public void dance(int dura9on) {...} and jiggles }
} 125 126
Abstract Classes Representing Abstract Classes
 Note that I had to declare the class abstract too. This is Person
because it has a method without an implementation so
we can't directly instantiate a Person. + dance()
Italics indicate the class
or method is abstract

public abstract class Person {


public abstract void dance();
}

 All state and non-abstract methods are inherited as Student Lecturer


normal by children of our abstract class
 Interestingly, Java allows a class to be declared abstract + dance() + dance()
even if it contains no abstract methods!

127 128

Objectives
 Dynamic and static polymorphism
 Problems that arise from multiple code
inheritance
 Java interfaces provide multiple type
inheritance
Lecture 6:
Polymorphism and Multiple Inheritance

129 130

Polymorphic Methods Polymorphic Concepts I

Student s = new Student();  Assuming Person has a  Static polymorphism


Person p = (Person)s; dance() method, what should  Decide at compile-time
p.dance(); happen here?
 Since we don't know what the true type of the
object will be, we just run the method based on
its static type
Demo: revisit expressions from last 9me

 General problem: when we refer to an object via a parent


type and both types implement a particular method: which
method should it run? Student s = new Student();  Compiler says “p is of type Person”
Person p = (Person)s;  So p.dance() should do the default
Polymorphism: values and variables can have more than one type p.dance(); dance() ac9on in Person

int eval(Expression e) {
C++ can do this. Java cannot
can be Literal, Mult or Plus
} 131 132
Polymorphic Concepts II The Canonical Example I
 Dynamic polymorphism  A drawing program that can draw circles,
squares, ovals and stars
 Run the method in the child
 It would presumably keep a list of all the
 Must be done at run-time since that's when we drawing objects
know the child's type  Option 1
 Also known as ‘dynamic dispatch’ Circle  Keep a list of Circle objects, a list of
+ draw()
Square objects,...
Square  Iterate over each list drawing each
+ draw() object in turn
 What has to change if we want to add
Student s = new Student();  Compiler looks in memory and Znds Oval a new shape?
Person p = (Person)s; that the object is really a Student + draw()

p.dance();  So p.dance() runs the dance() ac9on


in Student Star
+ draw()

C++ can do this when you choose, Java does it always


133 134
Demo

The Canonical Example II The Canonical Example III


Shape  Option 2 Shape
 Option 3 (Polymorphic)
 Keep a single list of Shape references - x_posi9on: int  Keep a single list of Shape references
- y_posi9on: int
 Figure out what each object really is,  Let the compiler figure out what to do
+ draw()
narrow the reference and then draw() with each Shape reference
Circle
for every Shape s in myShapeList Circle
+ draw()
if (s is really a Circle) + draw()
Circle c = (Circle)s; For every Shape s in myShapeList
Square
c.draw(); Square s.draw();
+ draw()
else if (s is really a Square) + draw()
Square sq = (Square)s;
Oval
sq.draw();
 What if we want to add a new shape?
+ draw()
Oval
else if... + draw()

Star  What if we want to add a new shape? Star


+ draw()
+ draw()

135
Demo 136
Demo

Implementations Harder Problems


 Java  Given a class Fish and a class DrawableEntity, how do we
 All methods are dynamic polymorphic. make a BlobFish class that is a drawable fish?
 Python
DrawableEn9ty
 All methods are dynamic polymorphic.
0..1 0..1
 C++ DrawableEn9ty BlobFish Fish
 Only functions marked virtual are dynamic polymorphic
Fish

X Conceptually wrong
 Polymorphism in OOP is an extremely important concept
that you need to make sure you understand...
BlobFish

X Dependency
between two
independent
concepts
137 138
Multiple Inheritance Multiple Inheritance Problems
Fish DrawableEn9ty  If we multiple inherit, we capture Fish DrawableEn9ty  What happens here? Which of
the concept we want the move() methods is inherited?
+ swim() + draw()
 BlobFish inherits from both and + move() + move()  Have to add some grammar to
is-a Fish and is-a DrawableEntity make it explicit
 C++:  C++:
class Fish {…} BlobFish *bf = new BlobFish();
class DrawableEn9ty {…} bf->Fish::move();
bf->DrawableEn9ty::move();
class BlobFish : public Fish,
public DrawableEn9ty {...}  Yuk.
BlobFish  But... BlobFish
This is like Zeld shadowing e.g.
+ swim() ????
+ draw() class A { class B extends A {
int x; int x;
} }
139 140

Multiple Inheritance Problems The diamond problem


CountableEn9ty CountableEn9ty  What happens if Fish and CountableEn9ty CountableEn9ty CountableEn9ty

DrawableEntity extend the same


+ freq: int + freq: int
class? + freq: int + freq: int + freq: int

 Do I get two copies?

Fish DrawableEn9ty Fish DrawableEn9ty DrawableEn9ty


Fish

+ move() + move() + move() + move() + move() + move()


or

BlobFish BlobFish BlobFish

???? ???? ????


141 142

Fixing with Abstraction Java's Take on it: Interfaces


 Classes can have at most one parent. Period.
Fish DrawableEnty  Actually, this problem  But special 'classes' that are totally abstract can do
+ move() + move() goes away if one or more multiple inheritance – call these interfaces
of the conflicting interface Drivable { adjec9ve
methods is abstract <<interface>> <<interface>> public void turn();
Drivable Iden&able public void brake();
} This is type
+ turn() + getIden&er() inheritance
+ brake() interface Iden9Zable { (not code
public void getIden9Zer();
inheritance)
}

class Bicycle implements Drivable {


BlobFish public void turn() {...}
public void brake() {… }
Bicycle Car }
+ move() + turn()
+ turn() class Car implements Drivable, Iden9Zable {
+ brake() + brake()
+ getIden9Zer() public void turn() {...}
public void brake() {… }
public void getIden9Zer() {...}
143 }
144
Interfaces have a load of implicit modifiers Interfaces can have default methods

interface Foo { interface Foo {


int x = 1; int x = 1;
int y(); int y();
} default int yPlusOne() {
return y() + 1;
}
means
}

interface Foo {  Allows you to add new functionality without


public static final int x = 1; breaking old code
public int y();  If you implement conflicting default methods
} you have to provide your own
145 146

Objectives
 Know the procedure for object initialisation
 Difference between destructors and
finalisers
 RAII and TWR
 High level idea of a garbage collector
Lecture 7:
Lifecycle of an Object

147 148

Creating Objects in Java Initialisation Example


new MyObject() 1. Blah loaded
public class Blah {
Load private int mX = 7; 2. sX created
MyObject.class public sta9c int sX = 9; 3. sX set to 9
No Is MyObject already loaded 4. sX set to 3
in memory? {
Create mX=5; 5. Blah object allocated
java.lang.Class Yes } 6. mX set to 7
object
Allocate memory 7. mX set to 5
for object
sta9c {
sX=3; 8. Constructor runs (mX=1, sX=9)
} 9. b set to point to object
Allocate any
sta9c Zelds and run
sta9c ini9aliser Run non-sta9c public Blah() {
blocks ini9aliser blocks mX=1; 10. Blah object allocated
sX=9; 11. mX set to 7
}
}
12. mX set to 5
Run constructor 13. Constructor runs (mX=1, sX=9)
demo ObjectConstruc9on
sta9c ini9alisa9on is done demo InheritedConstruc9on 14. b2 set to point to object
Blah b = new Blah();
in textual order Blah b2 = new Blah();

149 150
Constructor Chaining Chaining without Default Constructors
 When you construct an object of a type with parent  What if your classes have explicit constructors that take
classes, we call the constructors of all of the parents arguments? You need to explicitly chain
in sequence  Use super in Java:

Student s = new Student(); public Person (String name) {


Person
mName=name;
-mName : String
Animal +Person(String name) }
1. Call Animal()

Person
2. Call Person() Student
public Student () {
+Student()
super(“Bob”);
}
Student 3. Call Student()
Demo: NoDefaultConstructor
151 152

Deterministic Destruction Destructors


 Objects are created, used and (eventually) destroyed. Destruction is very language-  Most OO languages have a notion of a destructor too
specific
 Deterministic destuction is what you would expect
 Gets run when the object is destroyed
 Objects are deleted at predictable times  Allows us to release any resources (open files, etc) or memory
 Perhaps manually deleted (C++): that we might have created especially for the object

void UseRawPointer()
{
MyClass *mc = new MyClass(); class FileReader { int main(int argc, char ** argv) {
// ...use mc... public:
delete mc; FileReader f;
} // Constructor
 Or auto-deleted when out of scope (C++): FileReader() { // Use object here
In C++ this means f = fopen(“myZle”,”r”); ...
create a new instance C++ }
void UseSmartPointer() } // object destructor called here
{ of MyClass on the stack // Destructor
MyClass mc; using the default ~FileReader() {
// ...use mc... constructor fclose(f);
} // mc deleted here }

private :
This is called RAII = Resource Acquisi9on Is Ini9alisa9on
FILE *Zle;
153 }
154

Non-Deterministic Destruction What about Destructors?


Deterministic destruction is easy to understand and seems simple

enough. But it turns out we humans are rubbish of keeping track of  Conventional destructors don’t make
what needs deleting when sense in non-deterministic systems
 We either forget to delete (→ memory leak) or we delete multiple
times (→ crash)  When will they run?
 We can instead leave it to the system to figure out when to delete  Will they run at all??
 “Garbage Collection”
 The system somehow figures out when to delete and does it for us  Instead we have finalisers: same concept
 In reality it needs to be cautious and sure it can delete. This leads
to us not being able to predict exactly when something will be
but they only run when the system deletes
deleted!! the object (which may be never!)
 This is the Java approach!!
 Java provides try-with-resources as an
alternative to RAII

Demo: Finalizer Demo: TryWithResources


155 156
Garbage Collection Mark and sweep
 So how exactly does garbage collection work? How can a  Start with a list of all references you can get to
system know that something can be deleted?  Follow all references recursively, marking each object
 The garbage collector is a separate process that is constantly
 Delete all objects that were not marked
monitoring your program, looking for things to delete
 Running the garbage collector is obviously not free. If your
program creates a lot objects, you will soon notice the collector object
object
running x
 Can give noticeable pauses to your program! y object
 But minimises memory leaks (it does not prevent them…) z
 Keywords:
 ‘Stop the world’ - pause the program when collecting garbage object
object
 ‘incremental’ - collect in multiple phases and let the program
run in the gaps Genera9onal garbage collec9on: split
objects into short-lived and long-lived and
 ‘concurrent’ - no pauses in the program object
collect short-lived more frequently
Unreachable
Demo: Leak so deleted
157 158

Objectives
 Understand boxing and unboxing
 A general idea about Java collections: Set,
List, Queue and Map
 Fail-fast iterators

Lecture 8:
Java Collections and Object Comparison

159 160

Java Class Library Boxing and unboxing


 Java the platform contains around 4,000 classes/interfaces  Boxing: turn an int into an Integer
 Data Structures
 Networking, Files lots of this in 1B
 Unboxing: turn an Integer into an int
 Graphical User Interfaces Further Java  Java will do auto-boxing and unboxing
 Security and Encryption
 Image Processing public void something(Integer I) {
 Multimedia authoring/playback ...
}
 And more... auto-boxing
int i = 4;
 All neatly(ish) arranged into packages (see API docs) something(i);
public void other(int i) {

}
auto-unboxing
(and a NPE) Integer i = null;
other(i);

161 162
Java's Collections Framework Sets
<<interface>>  Important chunk of the class library <<interface>> Set
Collecon
Iterable
 A collection of elements with no duplicates that
 A collection is some sort of grouping of things represents the mathematical notion of a set B
A
(objects)  TreeSet: objects stored in order C

<<interface>>  Usually when we have some grouping we want  HashSet: objects in unpredictable order but fast
Collecon to operate on (see Algorithms course)
to go through it (“iterate over it”) Iterable

Set<Integer> ts = new TreeSet<>(); Collec9on


 The Collections framework has two main ts.add(15);
interfaces: Iterable and Collection. They define ts.add(12); Set
a set of operations that all classes in the ts.contains(7); // false
SortedSet LinkedHashSet
ts.contains(12); // true HashSet
Collections framework support
ts.Zrst(); // 12 (sorted)
 add(Object o), clear(), isEmpty(), etc. TreeSet

A form of type inference


Some9mes an opera9on doesn’t make sense – throw UnsupportedOpera9onError
163 164

Lists Queues
<<interface>> List <<interface>> Queue
C A
 An ordered collection of elements that may contain  An ordered collection of elements that may contain
duplicates duplicates and supports removal of elements from the head
of the queue
 LinkedLIst: linked list of elements
B B  offer() to add to the back and poll() to take from the front
 ArrayList: array of elements (efficient access) C
 LinkedList: supports the necessary functionality
 Vector: Legacy, as ArrayList but threadsafe Iterable  PriorityQueue: adds a notion of priority to the queue so more A
important stuff bubbles to the top

Collec9on B
List<Double> ll = new ArrayList<>();
ll.add(1.0); List
B
ll.add(0.5); Queue<Double> ll = new LinkedList<>();
ll.add(3.7); LinkedList ArrayList Vector ll.o(er(1.0);
ll.add(0.5); ll.o(er(0.5);
ll.get(1); // get element 2 (==3.7) ll.poll(); // 1.0
ll.poll(); // 0.5
legacy
good default
choice
165 166

Maps
Resizable Hash Table +
Hash Table Array Balanced Tree Linked List Linked List

<<interface>> Map Set


List
HashSet
ArrayList
TreeSet
LinkedList
LinkedHashSet

 Like dictionaries in ML Deque ArrayDeque LinkedList


K1 Map HashMap TreeMap LinkedHashMap

 Maps key objects to value objects A


iterator.

 Keys must be unique K3 K2 get add contains next remove(0) remove


B ArrayList O(1) O(1) O(n) O(1) O(n) O(n)

 Values can be duplicated and B


LinkedList O(n) O(1) O(n) O(1) O(1) O(1)

(sometimes) null. add contains next


HashSet O(1) O(1) O(h/n)
 TreeMap: keys kept in order TreeSet O(log n) O(log n) O(log n)
LinkedHashSet O(1) O(1) O(1)
 HashMap: Keys not in order, efficient
(see Algorithms) HashMap
get
O(1)
containsKey
O(1)
next
O(h/n)
LinkedHashMap O(1) O(1) O(1)
TreeMap O(log n) O(log n) O(log n)
Map<String, Integer> tm = new TreeMap<String,Integer>();
peek offer poll size
tm.put(“A”,1); LinkedList O(1) O(log n) O(log n) O(1)
tm.put(“B”,2); ArrayDeque O(1) O(1) O(1) O(1)
PriorityQueue O(1) O(log n) O(log n) O(1)
tm.get(“A”); // returns 1
tm.get(“C”); // returns null Source: https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html
Source: Java Generics and Collections (pages: 188, 211, 222, 240)
tm.contains(“G”); // false
Don’t just memorise these – think about how the datastructure works
167 168
Specific return type and general argument Iteration
 Should your method take a Set, a  for loop
SortedSet or a TreeSet? LinkedList<Integer> list = new LinkedList<Integer>();
 General rule of thumb: ...
for (int i=0; i<list.size(); i++) {
 use the most general type possible for Integer next = list.get(i);
parameters }

 use the most specific type possible for return


values (without over committing your  foreach loop (Java 5.0+)
implementation)
LinkedList list = new LinkedList();
...
for (Integer i : list) {
...
}
169 170

Iterators Comparing Objects


 What if our loop changes the structure?  You often want to impose orderings on your
for (int i=0; i<list.size(); i++) { data collections
If (i==3) list.remove(i);  For TreeSet and TreeMap this is automatic
}
TreeMap<String, Person> tm = ...
 Java introduced the Iterator class
 For other collections you may need to explicitly
Iterator<Integer> it = list.iterator(); sort
while(it.hasNext()) {Integer i = it.next();}
LinkedList<Person> list = new LinkedList<Person>();
//...
for (; it.hasNext(); ) {Integer i = it.next();}
Collec9ons.sort(list);
 Safe to modify structure  For numeric types, no problem, but how do you
while(it.hasNext()) {
tell Java how to sort Person objects, or any
it.remove(); other custom class?
}
171
Demo: Fast fail behaviour 172

Objectives
 Comparing and Comparable
 Error handling approaches
 How to define your own exceptions
 Pros and cons of exceptions
Lecture 9:
Error Handling Revisited

173 174
Comparing Primitives Reference Equality
> Greater Than  r1==r2, r1!=r2
>= Greater than or equal to  These test reference equality
== Equal to  i.e. do the two references point ot the same chunk of
!= Not equal to memory?
< Less than Person p1 = new Person(“Bob”);
<= Less than or equal to Person p2 = new Person(“Bob”);
False (references di(er)
(p1==p2);
 Clearly compare the value of a primitive
 But what does (ref1==ref2) do??
(p1!=p2); True (references di(er)

 Test whether they point to the same object?


(p1==p1);
 Test whether the objects they point to have the same
True
state?
175 176

Value Equality Java Quirk: hashCode()


 Use the equals() method in Object  Object also gives classes hashCode()
 Default implementation just uses reference equality (==)
so we have to override the method  Code assumes that if equals(a,b) returns
true, then a.hashCode() is the same as
public EqualsTest {
public int x = 8;
b.hashCode()
@Override
Learn the ‘equals’ contract  So you should override hashCode() at the
public boolean equals(Object o) {
EqualsTest e = (EqualsTest)o;
same time as equals()
return (this.x==e.x);
}

public sta9c void main(String args[]) {


EqualsTest t1 = new EqualsTest(); Learn the ‘hashcode’ contract
EqualsTest t2 = new EqualsTest();
System.out.println(t1==t2);
System.out.println(t1.equals(t2));
}
}
177
Demo: What’s wrong with equals 178

Comparable<T> Interface I Comparable<T> Interface II


int compareTo(T obj); public class Point implements Comparable<Point> {
private Znal int mX;
private Znal int mY;
public Point (int, int y) { mX=x; mY=y; } implemen9ng Comparable
 Part of the Collections Framework deZnes a natural ordering
// sort by y, then x for your class
 Doesn't just tell us true or false, but smaller, same, or public int compareTo(Point p) {
larger: useful for sorting. if ( mY>p.mY) return 1; ideally this should be
else if (mY<p.mY) return -1;
 Returns an integer, r: else {
consistent with equals i.e.
x.compareTo(y) == 0 <=> x.equals(y)
 r<0 This object is less than obj if (mX>p.mX) return 1;
 r==0 This object is equal to obj else if (mX<p.mX) return -1; must deZne a total order
 r>0 This object is greater than obj else return 0.
}
}
}

// This will be sorted automa9cally by y, then x


Set<Point> list = new TreeSet<Point>();
179 Demo 180
Comparator<T> Interface I Comparator<T> Interface II
int compare(T obj1, T obj2) public class Person implements Comparable<Person> {
private String mSurname;
private int mAge;
public int compareTo(Person p) {
 Also part of the Collections framework and allows us return mSurname.compareTo(p.mSurname);
delegate to the Zeld’s
compareTo method
to specify a specific ordering for a particular job }
}
 E.g. a Person might have natural ordering that sorts
by surname. A Comparator could be written to sort public class AgeComparator implements Comparator<Person> {
by age instead... public int compare(Person p1, Person p2) {
return (p1.mAge-p2.mAge);
}
}


ArrayList<Person> plist = …;

Collec9ons.sort(plist); // sorts by surname
Collec9ons.sort(plist, new AgeComparator()); // sorts by age

181 182

Operator Overloading Return Codes


 Some languages have a neat feature that allows  The traditional imperative way to handle errors is to
you to overload the comparison operators. e.g. in return a value that indicates success/failure/error
C++
public int divide(double a, double b) {
people argue about if (b==0.0) return -1; // error Go – returns a pair res, err
class Person { whether this is good double result = a/b; Haskell – Maybe type
public: or bad. return 0; // success
Int mAge }
bool operator==(Person &p) { (Java won’t let you do it)

return (p.mAge==mAge);
}; if ( divide(x,y)<0) System.out.println(“Failure!!”);
}
 Problems:
 Could ignore the return value
 Have to keep checking what the return values are meant to
Person a, b; signify, etc.
b == a; // Test value equality
 The actual result often can't be returned in the same way
 Error handling code is mixed in with normal execution
183 184

Deferred Error Handling Exceptions


 A similar idea (with the same issues) is to set some state in  An exception is an object that can be thrown or raised by a
the system that needs to be checked for errors. method when an error occurs and caught or handled by the
 C++ does this for streams: calling code
 Example usage:

ifstream Zle( "test.txt" );


try {
if ( Zle.good() ) double z = divide(x,y);
{ }
cout << "An error occurred opening the Zle" << endl; catch(DivideByZeroExcep9on d) {
} // Handle error here
}

185 186
Flow Control During Exceptions Throwing Exceptions
 When an exception is thrown, any code left to run in the try  An exception is an object that has Exception as an
block is skipped ancestor
 So you need to create it (with new) before throwing
double z=0.0;
boolean failed=false;
try {
z = divide(5,0);
double divide(double x, double y) throws DivideByZeroExcep9on {
z = 1.0;
if (y==0.0) throw new DivideByZeroExcep9on();
}
else return x/y;
catch(DivideByZeroExcep9on d) {
}
failed=true;
}
z=3.0;
System.out.println(z+” “+failed);

187 188

Multiple Handlers finally


 A try block can result in a range of different exceptions. We  With resources we often want to ensure
test them in sequence
that they are closed whatever happens
try {
try { fr,read();
FileReader fr = new FileReader(“someZle”); fr.close();
Int r = fr.read(); }
} catch(IOExcep9on ioe) {
catch(FileNoteFound fnf) { // read() failed but we must s9ll close the FileReader
// handle Zle not found with FileReader fr.close();
} }
catch(IOExcep9on d) {
// handle read() failed
}

189 190

finally II Creating Exceptions


 The finally block is added and will always  Just extend Exception (or RuntimeException if you need it to
be unchecked). Good form to add a detail message in the
run (after any handler) constructor but not required.

try { public class DivideByZero extends Excep9on {}


fr.read();
} public class Computa9onFailed extends Excep9on {
catch(IOExcep9on ioe) { public Computa9onFailed(String msg) {
// read() failed super(msg);
} If your excep9on is caused
} by another then chain
Znally { }
fr.close(); them - demo
}
 You can also add more data to the exception class to provide
Remember try-with-resources more info on what happened (e.g. store the numerator and
denominator of a failed division)
Keyword: excep9on chaining
191 192
Exception Hierarchies Checked vs Unchecked Exceptions
 You can use inheritance hierarchies  Checked: must be handled or passed up.
 Used for recoverable errors
public class MathExcep9on extends Excep9on {...}  Java requires you to declare checked exceptions that your
public class InZniteResult extends MathExcep9on {…} method throws
public class DivByZero extends MathExcep9on {…}  Java requires you to catch the exception when you call the
function
 And catch parent classes
try { double somefunc() throws SomeExcep*on {}

}  Unchecked: not expected to be handled. Used for
catch(InZniteResult ir) { programming errors
// handle an inZnite result  Extends RuntimeException
}  Good example is NullPointerException
catch(MathExcep9on me) {
// handle any MathExcep9on or DivByZero
}
193 194

No acceptance tests for take-home test Evil I: Exceptions for Flow Control
 Get in the habit of writing good tests  At some level, throwing an exception is like a GOTO
 Tempting to exploit this
 There will be no acceptance tests for the try {
take-home test – you have to get it right on for (int i=0; ; i++) {
System.out.println(myarray[i]);
your own! }
}
catch (ArrayOutOfBoundsExcep9on ae) {
// This is expected
}

 This is not good. Exceptions are for exceptional circumstances


only
 Harder to read
 May prevent optimisations

195 196

Evil II: Blank Handlers Advantages of Exceptions


 Checked exceptions must be handled  Advantages:
 Constantly having to use try...catch blocks to do this can be  Class name can be descriptive (no need to look up error
annoying and the temptation is to just gaffer-tape it for now codes)
 Doesn't interrupt the natural flow of the code by requiring
constant tests
try {  The exception object itself can contain state that gives lots of
FileReader fr = new FileReader(Zlename); detail on the error that caused the exception
}
 Can't be ignored, only handled
catch (FileNotFound fnf) { If it can’t happen then throw
}  Disadvantages:
a chained Run9meExcep9on
 Surprising control flow – exceptions can be thrown from
anywhere
 ...but we never remember to fix it and we could easily be missing  Lends itself to single threads of execution
serious errors that manifest as bugs later on that are extremely  Unrolls control flow, doesn’t unroll state changes
hard to track down

197 198
Objectives
 Substitutability: covariance and
contravariance
 Inner classes
 Lambda!
 Functional interfaces
Lecture 10:
Copying Objects

199 200

Remember the substitution principle? Covariant return types are substitutable


 If A extends B then I should be able to use  Overriding methods are covariant in their
B everywhere I expect an A return types

class A { class B extends A { class A { class B extends A {

Polygon getShape() { Polygon getShape() { Polygon getShape() { Triangle getShape() {


return new Polygon(…); return … return new Polygon(…); return …
} } } }

} } } } o.getShape() returns
a Triangle but Triangle
is a subtype of Polygon
void process(A o) { void process(A o) { and so by subs9tutability
drawShape(o.getShape()); drawShape(o.getShape()); we can pass it to
} } drawShape
process(new B()); process(new B());
201 202

Contravariant parameters also substitute Java arrays are covariant


 Overriding methods can be contravariant  If B is a subtype of A then B[] is a subtype
in their parameters of A[]

String[] s = new String[] { “v1”, “v2” };


class A { class B extends A {
Object[] t = s; Compiles – arrays are covariant
void setShape(Triangle o) { void setShape(Polygon o) { Works – t[0] is actually a String
… … Object v = t[0];
but we can assign that to Object
} }
t[1] = new Integer(4); Fails (at run9me) – t[] is actually
} } o.setShape() wants a an array of Strings, you can’t
Polygon and by put an Integer in it
You can’t actually subs9tutability its ok
do this in Java! The void process(A o) { to pass it a Triangle
two setShapes are o.setShape(new Triangle());
overloads not }
overrides process(new B());
203 204
Imagine if Arrays were a generic class Generics in Java are not covariant
 if B is a subtype of A then T<B> is not a
subtype of T<A>
class Array<Object> { class Array<String> {
List<String> s = List.of(“v1”, “v2”);
// Object x = array[i] // String x = array[i]
Object get(int index) { String get(int index) {
List<Object> t = s; Does not compile
… Covariant return type – all is good!
} } Would be safe – we can
Object v = t.get(0);
assign String to Object
// array[i] = value // array[i] = value
t.set(1,new Integer(4)); Is not safe
void set(int index, void set(int index,
Object value) { String value) {
… Covariant parameter type – bad news
} }
} }

205 206

Wildcards let us capture this Inner classes


 if B is a subtype of A then T<B> is a class Outer {
Inner classes may not have sta9c
members
subtype of T<? extends A>
private static void f();
private int x = 4;
List<String> s = List.of(“v1”, “v2”); Sta9c inner classes are a member
static class StaticInner { of the outer class and so can
List<? extends Object> t = s; Compiles access private members
void g() {
Works: ‘? extends Object’ f();
Object v = t.get(0);
is assignable to Object new Outer().x = 3;
t.set(1,new Integer(4)); }
}

Does not compile – the compiler knows it needs class InstanceInner { Instance inner classes are a member
something that extends object but it doesn’t int g() { of the outer object and so can access
know what it is! return x + 1; outer instance variables:
}
} Outer o = new Outer();
InstanceInner i = o.new InstanceInner()
207 } 208

Method-local classes Anonymous inner classes

class Outer { class Outer { x here is ‘e(ec9vely Znal’ - compile


Method-local classes in error if you try to change it
int y = 6; int y = 6;
instance methods can access
instance variables of the class
void f() { Object f() { o is a new class. It extends
int x = 5; int x = 5; Object but it has no name.
class Foo { Object o = new Object() { It can access all local and
int g() { Method-local classes can public String toString() { instance variables.
return x + y + 1; access local variables (and return String.valueOf(x+y+1);
} so are never sta9c classes). }
} };
Foo foo = new Foo(); return o;
}
} } Note: here we return o to the caller and it can be
used anywhere in the program even though it refers
} to y and x.

209 210
Lambda Need a Functional Interface to use them

Consumer<String> c1 = s -> System.out.println(s);


 A functional interface has only one method
c1.accept(“hello”); in it
expression lambda
 (this is so the compiler knows which one to
BiFunction<Integer,Integer,Boolean> c2 = (i,j) -> i+j > 5;
boolean a = c2.apply(3,1); map the lambda on to)
Predicate<Integer> b4 = v -> {  That’s it
if (v > 0) {
return isPrime(v);
}
else { statement lambda
return isPrime(v*v);
}
}
boolean a = b4.test(43431);

211 212

Objectives
 Simple use of streams
 What is a design pattern
 Open-closed principle
 Some example patterns
Lecture 11/12:
Design patterns

213 214

Streams Design Patterns


 Collections can be made into streams  A Design Pattern is a general reusable solution to a
commonly occurring problem in software design
(sequences)
 Coined by Erich Gamma in his 1991 Ph.D. thesis
 These can be filtered or mapped!  Originally 23 patterns, now many more. Useful to look at
because they illustrate some of the power of OOP (and
also some of the pitfalls)
 We will only consider a subset
List<Integer> list = ...
 It’s not a competition to see how many you can use in a
list.stream().map(x->x+10).collect(Collectors.toList()); project!

list.stream().Zlter(x->x>5).collect(Collectors.toList());

create element-wise aggrega9on


stream opera9ons
Demo:streams
215 216
The Open-Closed Principle Decorator
Classes should be open for extension Abstract problem: How can we add state
but closed for modification or methods at runtime?

 i.e. we would like to be able to modify the


behaviour without touching its source code
 This rule-of-thumb leads to more reliable Example problem: How can we efficiently
large software and will help us to evaluate support gift-wrapped books in an online
the various design patterns bookstore?

Demo: Readers
217 218

Decorator in General Singleton


 The decorator
Reader
pattern adds Abstract problem: How can we ensure
state and/or functionality to
an object dynamically only one instance of an object is created
by developers using our code?
Bu(eredReader

Example problem: You have a class that


FileReader encapsulates accessing a database over a
network. When instantiated, the object will
create a connection and send the query.
Unfortunately you are only allowed one
connection at a time.
219 220
demo: SingletonConnec9on

Singleton in General State


 The singleton pattern ensures Abstract problem: How can we let an
a class has only one instance
and provides global access to object alter its behaviour when its internal
it state changes?

Example problem: Representing


academics as they progress through the
rank

Demo: FanSpeed 221 222


State in General Strategy
 The state pattern allows an Abstract problem: How can we select an
object to cleanly alter its
behaviour when internal algorithm implementation at runtime?
state changes

Example problem: We have many possible


change-making implementations. How do
we cleanly change between them?

Demo: ComparatorStrategy
223 224

Strategy in General Composite


 The strategy pattern allows us to cleanly interchange Abstract problem: How can we treat a
between algorithm implementations
group of objects as a single object?

Example problem: Representing a DVD


box-set as well as the individual films
without duplicating info and with a 10%
discount

225 Demo: DVDs 226

Composite in General Observer


 The composite pattern lets Abstract problem: When an object
us treat objects and groups
of objects uniformly changes state, how can any interested
parties know?

Example problem: How can we write


phone apps that react to accelerator
events?

Demo: Ac9onListener
227 228
Observer in General End of course
 The observer pattern allows an object to have multiple  Don’t forget to keep practising with the
dependents and propagates updates to the dependents
automatically. practical exercises
 You will receive email about the take-
home test organisation closer to the time
 Thanks for listening!

229 230

You might also like