Download as pdf or txt
Download as pdf or txt
You are on page 1of 102

Week 8

Mergesort
Mergesort

We now study a sorting algorithm called Mergesort that performs much better than
selection sort
To sort the array below

5 7 9 1 8

we split it into two (approximately) equal parts

5 7 9 1 8

3 Foundations of Computer Science – A. Luchetta 2021-2022


Mergesort
If the two parts of the array are already sorted, as in our case, it is easy to build a
sorted array, moving the smallest element from either parts to a new array
This process is 5 7 9 1 8 1
called merging
5 7 9 1 8 1 5

5 7 9 1 8 1 5 7

5 7 9 1 8 1 5 7 8

5 7 9 1 8 1 5 7 8 9
4 Foundations of Computer Science – A. Luchetta 2021-2022
Mergesort

In the general case, the two parts of the array are not already sorted
However, we can sort each part by repeating the process
we divide the array into two (approximately) equal parts
We suppose they are both sorted
So we can recombine the two parts in the way we have just seen
this phase is called merge
By continuing like this, we will certainly arrive at a situation where the two parts of the
array are really sorted
when they contain only one element!

5 Foundations of Computer Science – A. Luchetta 2021-2022


Mergesort

We can therefore outline a recursive algorithm to sort an array called MergeSort



if the array contains less than two elements, it is already sorted (base case)

otherwise

We divide the array into two (approximately) equal parts

We order the first part using MergeSort (recursive step)

We order the second part using MergeSort (recursive step)

the two sorted parts are merged using the merge algorithm

6 Foundations of Computer Science – A. Luchetta 2021-2022


public class ArrayAlgorithms // usual class
{
public static void mergeSort(int[] a)
{ // base case
if (a.length < 2) return;

// we split the array in two halves


int mid = a.length / 2;

int[] left = new int[mid]; // left part


int[] right = new int[a.length – mid]; // right part
System.arraycopy(a, 0, left, 0, left.length);
System.arraycopy(a, mid, right, 0, right.length);

// recursive steps – double recursion


mergeSort(left); // sorts the left array
mergeSort(right); // sorts the right array

// merge
merge(a, left, right); // the work is left to merge method
}

7 Foundations of Computer Science – A. Luchetta 2021-2022
public class ArrayAlgorithms
{ private static void merge(int[] a, int[] b, int[] c)
{ int ia = 0, ib = 0, ic = 0;
// until arrays b and c have elements to move
while (ib < b.length && ic < c.length)
if (b[ib] < c[ic])
a[ia++] = b[ib++];
else
a[ia++] = c[ic++];

// here one of the two arrays has reached the end


while (ib < b.length)
a[ia++] = b[ib++];
while (ic < c.length)
a[ia++] = c[ic++];
}
...
}
8 Foundations of Computer Science – A. Luchetta 2021-2022
Note on the increment statements
In the increment/decrement statements (++ or --), when the notation is postfixed (++ after
the variable as in ia++), the execution is as below:
a[ia] = b[ib];
a[ia++] = b[ib++]; ib = ib + 1;
ia = ia + 1;
In other words, the assignment statement is executed first and then the indexes are
incremented/decremented.
The index increment/decrement can also be prefixed (++ in front of the variable as in ++ia)
If it is prefixed, the execution takes place as follows:
ib = ib + 1;
a[++ia] = b[++ib]; ia = ia + 1;
a[ia] = b[ib];
9 Foundations of Computer Science – A. Luchetta 2021-2022
Mergesort performance

Experimental performance measurements show that sorting with MergeSort is much


more efficient than sorting with selection sort
We now want to make a theoretical performance evaluation, counting as usual the
number of accesses to individual elements of the array executed in the algorithm
We call T(n), the time complexity, that is the number of accesses needed to sort an
array of n elements

10 Foundations of Computer Science – A. Luchetta 2021-2022


Mergesort performance
The two executions of System.arraycopy require a total of 2n accesses

all n elements must be read and written
The two recursive invocations require T(n/2) each
Merging requires
n accesses to write the n elements to the sorted array
each element to be written requires the reading of two elements, one from each of the
two arrays to be merged, for a total of 2n accesses
Adding all the contributions we get
T(n) = 2T (n/2) + 5n

11 Foundations of Computer Science – A. Luchetta 2021-2022


Mergesort performance
T (n) = 2T (n / 2) + 5n
The solution of this functional equation to obtain T(n) as a function of n is not simple
and goes beyond the scope of this course
However, we can easily verify, by substitution, that the solution is
T (n) = n + 5n * log2n
 T(n) = n + 5n*log2n, if we substitute below
T(n) = 2T(n/2) + 5n
= 2[n/2 + 5n/2*log2(n/2)] + 5n
= n + 5n*log2(n/2) + 5n
= n + 5n*(log2n - log22) + 5n
= n + 5n*(log2n - 1) + 5n
= n + 5n*log2n - 5n + 5n = n + 5n*log2n

12 Foundations of Computer Science – A. Luchetta 2021-2022


Mergesort performance
The table below helps to understand how the solution is built (although not a formal
proof)

T(n) / n = 1 + 5log2(n) ⇒ T(n) = n + 5nlog2(n)


13 Foundations of Computer Science – A. Luchetta 2021-2022
Mergesort performance
T (n) = n + 5n * log2n
To determine the big-O notation, we observe that
term 5n * log2n grows faster than term
the factor 5 is irrelevant, like all constant multiplying factors
The big-O notation is therefore T(n) ∈ O(n log n)
the base of the logarithms is not indicated, because the logarithm in one base can be
transformed into the logarithm in another base with a multiplicative factor, which
can be ignored
Thus, the performance of the MergeSort sort has a trend O(n log n)
that is therefore better than O(n2)
14 Foundations of Computer Science – A. Luchetta 2021-2022
Insertion sort
Insertion sort

The insertion sort algorithm


begins by observing that the unit-length subarray consisting of the first cell of the
array is sorted (being of unit length)
9 8 5 7 6
a[0] a[1] a[2] a[3] a[4]
proceeds by extending the sorted part to the right, including the first element to its
right in the sorted subarray
to do this, the new element is moved to the left until it is in its correct position, by
moving the intermediate elements to the right

16 Foundations of Computer Science – A. Luchetta 2021-2022


Insertion sort

9 8 5 7 6 8 9 5 7 6

8 9 5 7 6 5 8 9 7 6

5 8 9 7 6 5 7 8 9 6

5 7 8 9 6 5 6 7 8 9

17 Foundations of Computer Science – A. Luchetta 2021-2022


public static void insertionSort(int[] a)
{ // the loop starts from index 1 because the first element
// does not require attention
for (int i = 1; i < a.length; i++) // outer loop
{ // sorted insertion of current element
int cur = a[i]; // current element is at index i
int j = i – 1;
// all elements on the left of the current one
// and greater than it are moved to the right
// going from right to left
while (j >= 0 && cur < a[j]) // inner loop
{
a[j+1] = a[j];
j--;
}
// the current element is inserted in the right position
a[j+1] = cur; // write position for the current element
}
} // Goodrich-Tamassia version
18 Foundations of Computer Science – A. Luchetta 2021-2022
Performance of insertion sort

When we sort an array of n elements by insertion sort


The outer loop performs n-1 iterations
at each iteration the algorithm executes
2 accesses (1 before the inner loop and 1 after)
The inner loop performs 3 accesses for each iteration
but how many iterations does it perform?
it depends on how the data is distributed!

19 Foundations of Computer Science – A. Luchetta 2021-2022


Performance of insertion sort – best case

Best case: the data is already sorted


The inner loop never iterates
requires only 1 access for the loop condition verification
The outer loop performs n-1 iterations
at each iteration the algorithm executes
2 accesses (one before the inner loop and one after)
1 access (to check the termination condition of the inner loop)
Tb (n) = 3 * (n-1) ∈ O (n)

20 Foundations of Computer Science – A. Luchetta 2021-2022


Performance of insertion sort – worst case

Worst case: the data is sorted backwards


Each new element inserted requires moving all elements to its left, because it must
be inserted in position 0
Tw (n) = (2 + 3 * 1) + (2 + 3 * 2) + (2 + 3 * 3) + ... + (2 + 3 * (n-1))
= 2 (n-1) + 3 [1 + 2 + ... + (n-1)] = 2 (n-1) + 3n (n-1) / 2 = 3n2/2 – n - 1

Tw(n)∈ O (n2)

21 Foundations of Computer Science – A. Luchetta 2021-2022


Average case: the data is in random sequence
Each new element inserted requires on average to move half of the elements to its
left
Ta(n) = (2 + 3 * 1/2) + (2 + 3 * 2/2) + (2 + 3 * 3/2) + ... + (2 + 3 * (n-1) / 2)
= 2 (n-1) + 3 [1 + 2 + ... + (n-1)] / 2 = 2 (n-1) + 3 [n (n-1) / 2] / 2 = 3n2/4 + n/4 - 2

Ta(n)∈ O(n2)

22 Foundations of Computer Science – A. Luchetta 2021-2022


Performance summary of sorting algorithms

If we know that the array is "almost" sorted, it is better to use insertion sort
Notable example: an array that is kept sorted for searching, inserting a new element
every so often and then sorted again

Best case Average case Worst case


Selection sort O(n2)
Merge sort O(n log n)
Insertion sort O(n) O(n2) O(n2)

23 Foundations of Computer Science – A. Luchetta 2021-2022


Below you can find some numbers to compare the asymptotic trends of functions
f(n) = n, f(n) = n2 and f(n) = n log2 n.

n n2 n log n n2 / n log n
10 100 33 3
100 10.000 664 15
1.000 1.000.000 9.966 100
10.000 100.000.000 132.877 753
100.000 10.000.000.000 1.660.964 6.021
1.000.000 1.000.000.000.000 19.931.569 50.172
10.000.000 100.000.000.000.000 232.534.967 430.043

24 Foundations of Computer Science – A. Luchetta 2021-2022


Packages
Packages

A java program consists of a collection of classes


So far, our programs only include one or two classes stored in the same directory
When a program has many classes, we need a mechanism to organize them: this
mechanism is provided in Java by packages
A package includes related classes
To assign a class to a package, we have to insert the statement below as first
statement of the class source file

package packageName;

26 Foundations of Computer Science – A. Luchetta 2021-2022


How to organize our classes in package
The packages of the Java platform API (standard library) have names made up of dot-
separated tokens, as for example java.lang, javax.swing, org.omg.CORBA
To use a class belonging to a package we have to use the statement we already know
import packageName.className;
The organization of classes in packages creates a hierarchy that allows to use the same
name for different classes belonging to different packages
import java.util.Timer;
Import javax.swing.Timer

java.util.Timer tu = new java.util.Timer();
javax.swing.Timer ts = new javax.swing.Timer();
27 Foundations of Computer Science – A. Luchetta 2021-2022
How to organize classes in packages
There is a special package, called the default package, which is unnamed.
If we don't explicitly use a package statement in a source file, the class is placed in the default
package
The default package extends to classes whose source code is in the same directory
The java.lang package is always imported automatically
The package name must be unique, how to guarantee it?
for example inverting the names of the web domains which are unique:
dei.unipd.it it.unipd.dei (Department of Information Engineering)
If we do not have a domain, we can reverse our e-mail address (unique!)
adriano.luchetta@unipd.it it.unipd.luchetta.adriano
The java Platform API has
28 cases
Foundations of this
of Computer type
Science as for example package org.omg.CORBA
– A. Luchetta 2021-2022
How to locate packages
If we only use the standard library classes, we don't have to worry about the location of
the files. A package is located in a directory that matches the package name
the parts of the name separated by periods correspond to nested directories
it.unipd.luchetta.adriano it / unipd / luchetta / adriano
If only a program uses the package, the package is nested inside the directory
lab6 / it / unipd / luchetta / adriano
If we want to use it with many programs, we create a specific directory:
/ usr / home / lib / it / unipd / luchetta / adriano
We can add the path to the CLASSPATH environment variable
$ export CLASSPATH = $ CLASSPATH: / usr / home / lib :. or > set CLASSPATH =% CLASSPATH%; c: \ home \ lib ;.
Linux bash MS Windows shell
29 Foundations of Computer Science – A. Luchetta 2021-2022
Tips
Store each lab programming files in a dedicated directory as lab1, lab2, …
$ mkdir lab6
This way you can have different classes with the same name in different labs
Choose a base directory: $ home/al123456/
$ mkdir home/al123456/lab6
Store your lab file in the corresponding directory:
home/al123456/lab6/MyTriangle2DTester.java
Compile the source files from the base directory ( Note that the compiler uses file names)
$ cd home\al123456
$ javac lab6\MyTriangle.java
30 Foundations of Computer Science – A. Luchetta 2021-2022
Tips
Insert the package statement in the source file
package lab6;
Run the program from the base directory
$ cd home/al123456
$ java lab6.MyTriangle2DTester
Note that the compiler uses class names and therefore the separator is the dot
If you do not use the package statement, you have to run in the working directory
$ cd home/al123456/lab6
$ javac MyTriangle2DTester

31 Foundations of Computer Science – A. Luchetta 2021-2022


Generation of random numbers
Sequence of random numbers are very useful in programming tests and in
computational algorithms (for example Monte Carlo)
How can we generate a random number on the computer?
we know that a computer always does exactly what it is told to do through a
program, that is, it behaves in a deterministic way, and not random!
There are complex mathematical theories that provide algorithms capable of
generating sequences of pseudo-random (i.e. almost random) numbers, which are
an excellent approximation of sequences of random numbers

33 Foundations of Computer Science – A. Luchetta 2021-2022


Random numbers

The java.lang.Math class provides the random() method to generate sequences of


pseudo-random numbers
Each invocation of the method returns a pseudo-random real number in the interval
[0, 1 [
double x = Math.random();

To obtain, for example, random integers included in the interval [a, b], we have to do
some calculations ...
int n = (int)(a + (1 + b – a) * Math.random());

34 Foundations of Computer Science – A. Luchetta 2021-2022


Example: casting the dice
public class AverageDice1
{ public static void main(String[] args)
{ final int TRIALS = 100000;
int sum = 0;
for (int i = 0; i < TRIALS; i++)
{ // nuovo lancio del dado
int d = (int)(1 + 6 * Math.random());
sum = sum + d;
}
double avg = ((double)sum) / TRIALS;
System.out.println("Average: " + avg);
}
}

35 Foundations of Computer Science – A. Luchetta 2021-2022


Random numbers

There is also a standard library class: java.util.Random


import java.util.Random
public class MyRandomNumberClass
{
public void myRandomNumberMethod()
{
//if we need random numbers
Random rand = new Random(); // any integer
int n = rand.nextInt();
double d = rand.nextDouble();// real in interval[0,1[
long l = rand.nextLong(); // any long

}
36 Foundations of Computer Science – A. Luchetta 2021-2022
Random numbers

The nextInt() method defined in the java.util.Random class is overloaded, as below:

int nextInt () returns a pseudo-random integer in the range


[Integer.MIN_VALUE, Integer.MAX_VALUE].

int nextInt (int k) returns a pseudo-random integer in the interval [0, k [.

37 Foundations of Computer Science – A. Luchetta 2021-2022


Example: casting the dice
import java.util.Random;
public class AverageDice2
{ public static void main(String[] args)
{ final int TRIALS = 100000;
Random rand = new Random();
int sum = 0;
for (int i = 0; i < TRIALS; i++)
{ int d = 1 + rand.nextInt(6); // new cast
sum = sum + d;
}
double avg = ((double)sum) / TRIALS;
System.out.println("Average: " + avg);
}
}
38 Foundations of Computer Science – A. Luchetta 2021-2022
If we run the AverageDice program several times, we get a different average value
each time.
This outcome is because the random number sequence generated vary with each
execution, as it should be
We can observe that the average value obtained is always quite close to 3.5
The "theory of large numbers" states that the value 3.5 is reached exactly with an
infinite number of rolls of the die
from a practical point of view, a number of launches of a few million is sufficient ...
(but is it true?)
Possible dice cast results: 1 2 3 4 5 6 number of casts = 6
average cast = sum of possible cast results / number of casts = 21 / 6 = 3.5
39 Foundations of Computer Science – A. Luchetta 2021-2022
Regular expressions - just a quick mention
Regular expressions

Suppose we want to solve the following problem:


acquire the names of some cities contained in a string and separated by the
character /
Example: "Buenos Aires / Los Angeles / La Paz"
String line = “Buenos Aires/Los Angeles/La Paz”;
Scanner st = new Scanner(line);
while (st.hasNext())
System.out.println(st.next());
// IT DOES NOT WORK! Buenos
Aires/Los
Angeles/La
Paz
41 Foundations of Computer Science – A. Luchetta 2021-2022
Regular expressions

This code snippet does not work because the object of Scanner type uses as default
delimiter characters the whitespaces character set that does not contain the '/'
character
String line = “Buenos Aires/Los Angeles/La Paz”;
Scanner st = new Scanner(line);
st.useDelimiter(“[/]+”); // specifies the delimiters
while (st.hasNext())
System.out.println(st.next());
// NOW IT WORKS!
Buenos Aires Los
Angeles
La Paz

42 Foundations of Computer Science – A. Luchetta 2021-2022


Regular expressions
The useDelimiter(String pattern)method allows us to choose a new set of delimiter
The method argument is a string containing a regular expression
The new delimiter characters are listed within a pair of square brackets
for example [abc] means character ‘a’ OR character ‘b’ OR character ‘c’

The character ‘+’ after the bracket pair means one or more occurrences since the
delimiters can also be repeated
Example: if we want to select as delimiters the characters ‘@’ ‘$’ and ‘#’, we must write
Scanner st = new Scanner();
st.useDelimiter(“[@$#]+”);
The two lines above are often merged in a single one
Scanner st = new Scanner()useDelimiter(“[@$#]+”);
43 Foundations of Computer Science – A. Luchetta 2021-2022
Regular expressions

Regular expression are used in service programs such as the Linux grep command
For example, to list all lines containing numbers in the MyClass.java file, we can
write
$ grep [0-9]+ grep MyClass.java
[0-9] indicates any character between ‘0’ and ‘9’, that is all numeric characters
If we want to exclude the lines where characters precede numbers, we can wright
$ grep [^A-Za-z][0-9]+ grep MyClass.java
[^A-Za-z] indicates any character except (^) those in the range [rom ‘A’ to ‘Z’]and
[from ‘a’ to ‘z’

44 Foundations of Computer Science – A. Luchetta 2021-2022


Inheritance
Inheritance
Inheritance is one of the basic principles of object-oriented programming together
with encapsulation and polymorphism
Inheritance is the paradigm that allows code reuse
We use the inheritance when we want to write a class and another class is already
available which represents a more general concept
Suppose we want to write a SavingsAccount class to represent a savings bank
account, with an annual interest rate fixed at the time of opening and an
addInterest() method to credit the interest on the account
a savings bank account has all the same characteristics as a bank account, plus a few
other characteristics that are unique to it
In this case, we reuse the code already written for the BankAccount class
46 Foundations of Computer Science – A. Luchetta 2021-2022
Inheritance
public class BankAccount
Let’s just remind the { public BankAccount()
BankAccount class code { balance = 0;
}
public void deposit(double amount)
{ balance = balance + amount;
}
public void withdraw(double amount)
{ balance = balance - amount;
}
public double getBalance()
{ return balance;
}
private double balance;
}
47 Foundations of Computer Science – A. Luchetta 2021-2022
Inheritance - Savings Account
public class SavingsAccount
{ public SavingsAccount(double rate)
If we have the { balance = 0;
source code of the interestRate = rate;
}
BankAccount class, public void addInterest()
we could write by { deposit(getBalance() * interestRate / 100);
}
using “cut & paste” private double interestRate;
as on the right, public void deposit(double amount)
{ balance = balance + amount;
where we have }
highlighted the public void withdraw(double amount)
{ balance = balance - amount;
unique features of }
public double getBalance()
Savings Account { return balance;
}
private double balance;
}
48 Foundations of Computer Science – A. Luchetta 2021-2022
Inheritance - Savings Account

As we expected, we simply copied much of the code written for BankAccount into
the definition of the SavingsAccount class
we added an instance variable interestRate
we renamed and changed the constructor
we added a new method addInterest()

49 Foundations of Computer Science – A. Luchetta 2021-2022


Inheritance
Copying the code is already a time saver, but it is not enough
What happens if we change BankAccount?
for example, we modify the withdraw() method to prevent the balance from going
negative
We must also change SavingsAccount accordingly
→ very uncomfortable and source of errors ...
And what about, if we don't have the source code available, but we have only the
class bytecode? We cannot copy the BankAccount class ...
and therefore we have to completely rewrite SavingsAccount!
Inheritance solves these problems
50 Foundations of Computer Science – A. Luchetta 2021-2022
Inheritance
public class SavingsAccount extends BankAccount
{ public SavingsAccount(double rate)
{ interestRate = rate;
}
public void addInterest()
{ deposit(getBalance() * interestRate / 100);
}
private double interestRate;
}
We declare that SavingsAccount derives from BankAccount (or extends it)
SavingsAccount inherits all BankAccount’s characteristics
instance variables static variables public and private methods
we have to specify only the peculiarities of SavingsAccount
51 Foundations of Computer Science – A. Luchetta 2021-2022
Inheritance SavingsAccount
SavingsAccount sAcct = balance 0
new SavingsAccount(10);
BankAccount()
deposit(...)
withdraw(...)
variabiles and method
inherited from BankAccount getBalance()

interestRate 10
variabiles and method SavingsAccount(...)
Defined in SavingsAccount
addInterest()

52 Foundations of Computer Science – A. Luchetta 2021-2022


How to use the extended class

We can use the objects of the SavingsAccount extended class as if they were
BankAccount objects, with a few more properties
SavingsAccount acct = new SavingsAccount(10);
acct.deposit(500);
acct.withdraw(200);
acct.addInterest();
System.out.println(acct.getBalance());

330
The derived class (SavingsAccount) is called a subclass, while the class that is
extended (BankAccount) is called a superclass

53 Foundations of Computer Science – A. Luchetta 2021-2022


The root class of Java class hierarchy

In Java, any class that does not explicitly derive from another class derives implicitly
from the root superclass of the class hierarchy, which is called Object
Hence, SavingsAccount derives from BankAccount, which in turn derives implicitly
from the java.lang.Object class
Object class has some methods, which we will see later (including toString()), which
are then inherited by all classes in Java
inheritance also occurs on multiple levels, so SavingsAccount also inherits the
properties of Object

54 Foundations of Computer Science – A. Luchetta 2021-2022


Inheritance
Syntax:
class SubclassName extends SuperClassName
{ costructors
new methods
new variables
}

Purpose: to define the SubclassName class that derives from the SuperclassName
class, defining new methods and / or new variables, as well as its constructors
Note: if the a superclass is not explicitly indicated, the compiler implicitly uses
java.lang.Object

55 Foundations of Computer Science – A. Luchetta 2021-2022


Confusing term subclass with superclass

Since objects of type SavingsAccount are an extension of BankAccount type objects


“larger” than BankAccount type objects, because
they have additional instance variables
They are more “skilled” than BankAccount type objects, because they have one more method
why do we call SavingsAccount a subclass instead of a superclass?
it's easy to get confused
perhaps it would be natural to use the names backwards ...

56 Foundations of Computer Science – A. Luchetta 2021-2022


Confusing term subclass with superclass

The terms superclass and subclass derive from set theory


The set of objects of type SavingsAccount are a subset of the set of all objects of type
BankAccount

BankAccount set SavingsAccount set

57 Foundations of Computer Science – A. Luchetta 2021-2022


UML representation of inheritance relationship

Unified Modeling Language is notation for object- Object


oriented analysis and design (already presented for
the class dependency diagram)
A class is represented with a rectangle containing
the name of the class BankAccount
The inheritance relationship between classes is
indicated with a segment ending with an arrow
The hollow triangle arrow points to the superclass
SavingsAccount

58 Foundations of Computer Science – A. Luchetta 2021-2022


Inherited methods

When we define a subclass, three things can happen regarding its methods
1. in the subclass a method is defined that does not exist in the superclass:
in our example addInterest()
2, the subclass inherits a method from the superclass
in our example deposit(), withdraw(), getBalance()
3. a method of the sublass overrides the method in the superclass

59 Foundations of Computer Science – A. Luchetta 2021-2022


Overiding methods

The ability to override a method of the superclass, modifying its behavior when
used for the subclass, is one of the most powerful features of the object oriented
programming
To override a method, a method with the same signature as the one defined in the
superclass must be defined in the subclass
this method overrides that of the superclass when it is invoked with an reference to
an object of the subclass

60 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding methods

We want to modify the SavingsAccount class so that each deposit transaction has a
(fixed) FEE cost, which is automatically debited from the account

public class SavingsAccount extends BankAccount


{ ...
private final static double FEE = 2.58;
}

Note that SavingAccount uses the deposit method inherited from BankAccount for
the deposit transaction, a method on which we have no control

61 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding methods
However, we can override the deposit() method, redefining it in SavingsAccount
public class SavingsAccount extends BankAccount
{ ...
public void deposit(double amount) // same signature
// as in BankAccount
{ withdraw(FEE);
... // add amount to balance
}
}
This way, when deposit() is invoked with an reference to an object of type
SavingsAccount, the interpreter actually runs the deposit method defined in the
SavingsAccount class instead of that in BankAccount
nothing changes for BankAccount objects, of course
62 Foundations of Computer Science – A. Luchetta 2021-2022
Overriding methods
To complete the method, we have to pay amount into the account, that is, add it to
balance
we cannot directly modify balance, because it is a private variable in BankAccount
we also know that the only way to add amount to to balance is by calling deposit ()
public class SavingsAccount extends BankAccount
{ ...
public void deposit(double amount)
{ withdraw(FEE);
deposit(amount); // IT DOES NOT WORK!
}
}
But this doesn't work, because the method becomes recursive with endless recursion !
(the base case is missing)
63 Foundations of Computer Science – A. Luchetta 2021-2022
Overriding methods

What we need to do is invoke the BankAccount's deposit() method


We can do this using the super implicit reference, which the compiler uses to
automatically access elements inherited from the superclass
public class SavingsAccount extends BankAccount
{ ...
public void deposit(double amount)
{ withdraw(FEE);
super.deposit(amount);// calls deposit of the superclass
}
}

64 Foundations of Computer Science – A. Luchetta 2021-2022


Calling superclass methods

Syntax:
super.methodName(arguments)

Purpose: to call the methodName method of the superclass instead of the method
with the same name (overridden) in the current class

65 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding the toString method

We have already seen that the java.lang.Object class is the root superclass, that is,
all classes defined in Java implicitly inherit its methods, including
public String toString ()
The invocation of this method for any object returns the so-called standard text
description
BankAccount@111f71

the name of the class followed by the @ character and the address of the object in
memory

66 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding the toString method

The fact that all classes derive (even indirectly) from Object and that Object defines
the toString() method allows the println() method of java.io.PrintStream to work
passing a reference to objects of any type to System.out.println(), we get the display
of the standard text description of the object referred to
how does println() work?
println() simply calls the object's toString() metod, and invocation is always possible
because all classes have the toString () method, possibly inherited from Object

67 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding the toString method

If all classes already have the toString () method, inheriting it from Object, why
should we override it, redefine it?

BankAccount account = new BankAccount();


System.out.println(account);

BankAccount@111f71

Because, in general, the standard text description is not particularly useful

68 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding the toString method
It would be much more convenient, for example to verify the correct functioning of
the program, to obtain a text description of BankAccount containing the value of the
balance
this functionality cannot be performed by the toString() method of Object, because
whoever defined Object in the standard library had no knowledge of the
BankAccount structure
We need to override toString() in BankAccount
public String toString()
{ return "BankAccount[balance=" + balance + "]”;
}
BankAccount[balance=1500]
69 Foundations of Computer Science – A. Luchetta 2021-2022
Overriding the toString method

The compiler implicitly invokes the toString() method of a class when concatenating
an object of the class with a string
BankAccount acct = new BankAccount();
String s = "Account " + acct;

This concatenation is syntactically correct, as we had already seen for numeric data
types, and the compiler interprets the concatenation as if it were written like this

BankAccount acct = new BankAccount();


String s = "Conto " + acct.toString();

70 Foundations of Computer Science – A. Luchetta 2021-2022


Overriding the toString method

Overriding the toString() method in all the classes we define


is considered a great programming style

The toString() method of a class should provide a string containing all the status
information of the object, that is
the value of all its instance variables
the value of any (non-constant) static variables of the class
This programming style is very useful for debugging and is used in the standard
library

71 Foundations of Computer Science – A. Luchetta 2021-2022


Constructors of subclasses
Let's try to define a new constructor in SavingsAccount, to initialize a savings account
with non-zero starting balance: similarly to BankAccount, which has two constructors
public class SavingsAccount extends BankAccount
{ public SavingsAccount(double rate)
{ interestRate = rate;
}
public SavingsAccount(double rate,
double initialAmount)
{ interestRate = rate;
balance = initialAmount; // IT DOES NOT WORK
}
...
}
72 Foundations of Computer Science – A. Luchetta 2021-2022
Constructors of subclasses
You could solve the problem by simulating a first deposit, by invoking deposit()
This is allowed, but it is not a very good solution, because it introduces potential
side effects
for example, the payment operations could have a cost, automatically deducted
from the balance, while the "account opening" payment could be free

public SavingsAccount(double rate, double initialAmount)


{ interestRate = rate;
deposit(initialAmount); // NOT VERY ELEGANT!
}

73 Foundations of Computer Science – A. Luchetta 2021-2022


Constructors of subclasses

Since the balance variable is managed by the BankAccount class, it is necessary to


delegate to this class the task of initializing it
The BankAccount class already has a constructor created specifically to manage the
opening of an account with a non-zero balance
we invoke this constructor from within the SavingsAccount constructor, using the
super(...) syntax
public SavingsAccount(double rate, double initialAmount)
{ super(initialAmount);
interestRate = rate;
}

74 Foundations of Computer Science – A. Luchetta 2021-2022


Constructors of subclasses

In reality, the interpreter always calls the super() constructor when it build a
subclass
if the call to super (...) constructor is not explicitly indicated by the programmer, the
compiler automatically inserts the invocation of super() without parameters
this happens, for example, in the case of the first constructor of SavingsAccount
The explicit invocation of super (...), if present, must be the first statement of the
constructor

75 Foundations of Computer Science – A. Luchetta 2021-2022


How to call a constructor of superclass

Syntax:
SubclassName(arguments)
{ super(possibleArguments);
...
}

Purpose: to invoke in a subclass the constructor of the superclass passing any


arguments (which can also be different from the arguments of the subclass
constructor)
Note: it must be the first statement of the subclass constructor
Note: If not explicitly stated, super() is invoked implicitly with no arguments

76 Foundations of Computer Science – A. Luchetta 2021-2022


Polymorphism
Multiple types of references
Let's add a method to BankAccount to transfer money from a bank account to
another
public class BankAccount
{ ...
public void transferTo(BankAccount other, double amount)
{ withdraw(amount); // this.withdraw
other.deposit(amount);
}
}
BankAccount acct1 = new BankAccount(500);
BankAccount acct2 = new BankAccount();
acct1.transferTo(acct2, 200);
System.out.println(acct1.getBalance()); 300
System.out.println(acct2.getBalance()); 200

78 Foundations of Computer Science – A. Luchetta 2021-2022


Conversion between references
An object of type SavingsAccount is a special case of objects of type BankAccount
This property is reflected in a syntactic property
a reference to an object of a derived class can be assigned to an object variable of
the type of one of its superclasses
SavingsAccount sAcct = new SavingsAccount(10);
BankAccount bAcct = sAcct;
Object obj = sAcct;

BankAccounts
Object SavingsAccounts

79 Foundations of Computer Science – A. Luchetta 2021-2022


Conversion between references

The three variables, although of different types, point to the same object

sAcct SavingsAccount

bAcct balance 0

obj interestRate 10

80 Foundations of Computer Science – A. Luchetta 2021-2022


Conversion between references
Using the bAcct variable, you can use the object as if it were of the BankAccount
type, but without being able to access the specific properties of SavingsAccount

SavingsAccount sAcct = new SavingsAccount(10);


BankAccount bAcct = sAcct;
bAcct.deposit(500); // OK
bAcct.addInterest(); cannot resolve symbol
symbol : method addInterest()
location: class BankAccount
bAcct.addInterest();
^
1 error
81 Foundations of Computer Science – A. Luchetta 2021-2022
Conversion between references
What purpose can this type of conversion have?
why do we want to treat an object of type SavingsAccount as if it were of type
BankAccount?
BankAccount other = new BankAccount(1000);
SavingsAccount sAcct = new SavingsAccount(10);
BankAccount bAcct = sAcct;
other.transferTo(bAcct, 500);

The BankAccount transferTo() method requires an argument of type BankAccount


and does not know (nor use) the specific methods of SavingsAccount, but it is
convenient to be able to use it without having to modify it!
public void transferTo(BankAccount other, double amount)

82 Foundations of Computer Science – A. Luchetta 2021-2022


Conversion between references

The conversion between subclass reference and superclass reference can also occur
implicitly (as between int and double)
BankAccount other = new BankAccount(1000);
SavingsAccount sAcct = new SavingsAccount(10);
other.transferTo(sAcct, 500);

Since the transferTo() method requires a reference of type BankAccount, the compiler
verifies that the argument is of type BankAccount or any subclass of BankAccount
and, if the reference is of a type of a subclass, it automatically converts the
reference.

83 Foundations of Computer Science – A. Luchetta 2021-2022


“Magic” methods

Now we can understand how it is possible to define methods which, like println(),
can receive as arguments objects of any type
a reference to an object of any type can always be automatically converted to a
reference of type Object
public void println(Object obj)
{ println(obj.toString()); // calls the method for strings
}
public void println(String s)
{ ... // this method can print strings
}

84 Foundations of Computer Science – A. Luchetta 2021-2022


“Magic” methods
public void println(Object obj)
{ println(obj.toString()); // calls the method for strings
}
public void println(String s)
{ ... // this method can print strings
}
But an instance of String is also an instance of Object ...
how do we choose the right method, from the overloaded ones, when we invoke
println() with a string?
in the automatic conversion of references during the invocation of methods, the
compiler always "does the least number of conversions"
therefore, the "more specific" method is used
85 Foundations of Computer Science – A. Luchetta 2021-2022
Conversion betwee references

Conversely, the reverse conversion cannot take place automatically


BankAccount bAcct = new BankAccount(1000);
SavingsAccount sAcct = bAcct;

incompatible types
But does it make sense to try to found : BankAccount
required: SavingsAccount
make such a conversion? sAcct = bAcct;
^
1 error

86 Foundations of Computer Science – A. Luchetta 2021-2022


Conversion betwee references
The conversion of a reference to a superclass into a reference to a subclass only
makes sense if, due to the algorithm's specifications, we are sure that the superclass
reference actually points to an object of the subclass
It requires an explicit cast statement
SavingsAccount sAcct = new SavingsAccount(10, 1000);
BankAccount bAcct = sAcct;
...
SavingsAccount sAcct2 = (SavingsAccount) bAcct;
// if in run-time bAcct does not actually point to an object of
// type SavingsAccount, the interpreter throws
// the java.lang.ClassCastException

87 Foundations of Computer Science – A. Luchetta 2021-2022


Polymorphism

We already know that a subclass object can be used as if it were a superclass object

BankAccount acct = new SavingsAccount(10, 1000);


acct.deposit(500);
acct.withdraw(200);

When invoking deposit(), which method is invoked?


the deposit() method defined in BankAccount?
the deposit() method redefined in SavingsAccount?

88 Foundations of Computer Science – A. Luchetta 2021-2022


Polymorphism

We might think
acct is a variable declared as a BankAccount type, therefore the BankAccount
deposit() method is invoked (i.e. no fees are charged for the payment operation ...)
But acct contains a reference to an object which is actually of type SavingsAccount!
And the Java interpreter knows it (the compiler doesn't)
according to Java semantics, the SavingsAccount deposit() method is invoked

89 Foundations of Computer Science – A. Luchetta 2021-2022


Polymorphism

We call this semantics polymorphism and it is characteristic of the object-oriented


programming languages
the invocation of a method in runtime is always determined by the type of the
object actually used as an implicit argument, and NOT by the type of the object
variable
We speak of polymorphism (from the Greek, "many forms") because the same
processing (in this case deposit()) is carried out in different ways, depending on the
actual object used

90 Foundations of Computer Science – A. Luchetta 2021-2022


Polymorphism
BankAccount acct = new SavingsAccount(10, 1000);
acct.deposit(500);
acct.withdraw(200);
We have already met one form of polymorphism in connection with overloaded methods
the invocation of the println() method actually translates into the invocation of a method
chosen from among different methods, in relation to the type of the explicit argument
In the case of the method overloading, the compiler decides which method to invoke
In the case above the situation is very different, because the compiler cannot make the
decision, but the runtime environment (the interpreter) must make it
we talk about about early binding (anticipated decison) in the case of overloaded
methods and about late binding (delayed decision) in the case above

91 Foundations of Computer Science – A. Luchetta 2021-2022


Instanceof operator

Syntax:
referenceVariableName instanceof ClassName

Purpose: it is a boolean operator that returns true if and only if the reference variable
points to an object that is an instance of the ClassName class (or one of its subclasses),
false otherwise
In the case of the assignment to reference variable af a variable of type ClassName, the
interpreter DOES NOT throw java.lang.ClassCastException, if the check with instanceof
has been positive
Note: the result does not depend on the type declared for the reference variable, but on
the type of the object to which the variable actually refers at the time of execution

92 Foundations of Computer Science – A. Luchetta 2021-2022


Common errors when programming methods and
constructors
Calling an instance method without implicit argument

public class MyClass


{
public static void main(String[] args)
{
BankAccount acct = new BankAccount();
deposit(500); // ERROR!
}
}
The compiler cannot compile the source code because the method deposit() is an
instance method and requires to be called with implicit argument.
In fact, the compiler does not know which object the method deposit must be
applied to

94 Foundations of Computer Science – A. Luchetta 2021-2022


Calling an instance method without implicit argument
There are cases (and are very common) in which we can an instance method without
specifying the implicit argument
This is true when we call an instance method from another instance method in the
same class
In this case, we use the implicit argument this
public void withdraw(double amount)
{
public static void main(String[] args)
{
balance = getBalance() - amount;
}
} balance = this.getBalance() - amount;

95 Foundations of Computer Science – A. Luchetta 2021-2022


Trying to ribuild an object

Sometimes we may be tempted to call a constructor on an already constructed


object to restore it to its initial conditions
The compiler message error is a little weird
The compiler looks for a BankAccount method and obviously can't find it

BankAccount bAcct = new BankAccount();


bacct.deposit(500);
bAcct.BankAccount(); // IT DOES NOT WORK – COMPILER ERROR
Cannot resolve symbol
Symbol: method BankAccount
Location: class BankAccount
96 Foundations of Computer Science – A. Luchetta 2021-2022
Overshadowing the inherited instance variables

We know that a subclass inherits the instance variables defined in the superclass
each object in the subclass has its own copy of these variables, as does each object
in the superclass
but if they are private, the subclass methods cannot access them!
public class SavingsAccount extends BankAccount
{ ...
public void addInterest()
{ deposit(getBalance() * interestRate/100);
}
}

97 Foundations of Computer Science – A. Luchetta 2021-2022


Overshadowing the inherited instance variables

Let's try to directly access directly: the compiler reports the error
balance has private access in BankAccount
Therefore, to access inherited private variables, we must use public methods made
available by the superclass, if any
public class SavingsAccount extends BankAccount
{ ...
public void addInterest()
{ deposit(balance * interestRate/100);
}
}

98 Foundations of Computer Science – A. Luchetta 2021-2022


Overshadowing the inherited instance variables
Sometimes we fall into the error of defining the variable also in the subclass

public class SavingsAccount extends


BankAccount
{ ...
public void addInterest()
{ deposit(balance * interestRate / 100);
}
private double balance;
}

In this way, the compiler does not report any errors, but now SavingsAccount has
two variables called balance, one of its own and one inherited
there is no relationship between the two balance variables!
99 Foundations of Computer Science – A. Luchetta 2021-2022
Overshadowing the inherited instance variables

public class SavingsAccount extends


BankAccount
{ ...
public void addInterest()
{ deposit(balance * interestRate / 100);
}
private double balance;
}

100 Foundations of Computer Science – A. Luchetta 2021-2022


Overshadowing the inherited instance variables

The existence of two distinct balance variables is a source of errors that are difficult
to diagnose
Changes to variable balance made by SavingsAccount methods are not visible to
BankAccount methods, and vice versa
for example, the invocation of withdraw() (defined in BankAccount) changes the
balance variable of BankAccount, but does not change the balance variable defined
in SavingsAccount
the interest calculation will be wrong

101 Foundations of Computer Science – A. Luchetta 2021-2022


Overshadowing the inherited instance variables

Why does Java have this apparent "weakness"?


according to the rules of the OOP, whoever writes a subclass should not know
anything about the elements declared private in the superclass, and should not
write code based on these characteristics
therefore it is perfectly legal to define and use a variable balance in the subclass
it would be strange to prevent this, since the designer of the subclass doesn't have
to know that there is a balance variable in the superclass!
The logic error is to use a variable in the subclass with the same name as that of the
superclass and hope that they are the same thing!

102 Foundations of Computer Science – A. Luchetta 2021-2022

You might also like