SWEN20003 Object Oriented Software Development
SWEN20003
Object Oriented Software Development
Generics
Generics SWEN20003 1 / 36
The Road So Far
Java Foundations
Classes and Objects
I Encapsulation
I Information Hiding (Privacy)
Inheritance and Polymorphism
I Inheritance
I Polymorphism
I Abstract Classes
I Interfaces
Modelling classes and relationships
Generics SWEN20003 2 / 36
Recap – Modelling classes and
relationships
Learning Objectives:
Identify classes and relationships
Represent classes and relationships in UML
Develop simple Class Diagrams
Generics SWEN20003 3 / 36
Lecture Objectives
After this lecture you should be able to:
Understand generic classes in Java
Use generically typed classes
Generics SWEN20003 4 / 36
Introduction
Java allows class, interface or method definitions to
include parameter types.
Such definitions are called generics:
Enables generic logic to be written that applies to
any class type
Allows code re-use
Example: What about a generic Sort class that would
allow any type of object to be sorted?
Generics SWEN20003 5 / 36
A look back…
You have already seen a generic interface.
What is the Comparable interface? How does it work?
public interface Comparable
public int compareTo(T other);
}
What does T mean?
Generics SWEN20003 6 / 36
A look back…
You have already seen a generic interface.
What is the Comparable interface? How does it work?
public interface Comparable
public int compareTo(T other);
}
What does T mean?
Generics SWEN20003 6 / 36
A look back…
You have already seen a generic interface.
What is the Comparable interface? How does it work?
public interface Comparable
public int compareTo(T other);
}
What does T mean?
Generics SWEN20003 6 / 36
A look back…
You have already seen a generic interface.
What is the Comparable interface? How does it work?
public interface Comparable
public int compareTo(T other);
}
What does T mean?
Generics SWEN20003 6 / 36
Type Parameters
T is a type parameter, or type variable
The value of T is literally a type (class/interface);
Integer, String, Robot, Book, Driveable
When T is given a value (type), every instance of
the placeholder variable is replaced
public class Robot implements Comparable
public class Book implements Comparable
public class Dog implements Comparable
Generics SWEN20003 7 / 36
Type Parameters
How do you write a class that can be compared with an
object of the same type?
public class Dog implements Comparable
private String name;
public Dog(String name) {
this.name = name;
}
public int compareTo(Dog dog) {
return this.name.compareTo(dog.name);
}
}
Generics SWEN20003 8 / 36
Type Parameters
How do you write a class that can be compared with an
object of the same type?
public class Dog implements Comparable
private String name;
public Dog(String name) {
this.name = name;
}
public int compareTo(Dog dog) {
return this.name.compareTo(dog.name);
}
}
Generics SWEN20003 8 / 36
Type Parameters
Using type parameters allows us to define a class or
method that uses arbitrary, generic types, that applies
to any and all types.
But why?
Can we compare objects without using the generic
Comparable interface?
Generics SWEN20003 9 / 36
Type Parameters
Using type parameters allows us to define a class or
method that uses arbitrary, generic types, that applies
to any and all types.
But why?
Can we compare objects without using the generic
Comparable interface?
Generics SWEN20003 9 / 36
Using the Non-generic Comparable Intf.
public class Circle implements Comparable {
private double centreX = 0.0, centreY = 0.0;
private double radius = 0.0;
@Override
public int compareTo(Object o) {
Circle c = null;
if (o instanceof Circle) {
c = (Circle)o;
if (c.radius > this.radius)
return 1;
else if (c.radius < this.radius) return -1; else return 0; } else { return -2; } } } Generics SWEN20003 10 / 36 Using the Non-generic Comparable Intf. public class Square implements Comparable{ private double centreX = 0.0, centreY = 0.0; private double length = 0.0; @Override public int compareTo(Object o) { Square s = null; if (o instanceof Square) { s = (Square)o; if (s.length > this.length)
return 1;
else if (s.length < s.length)
return -1;
else
return 0;
} else {
return -2;
}
}
Generics SWEN20003 11 / 36
Using the Non-generic Comparable Intf.
public class CompareShapes {
public static void main(String[] args) {
Circle c1 = new Circle(0.0, 0.0, 5);
Circle c2 = new Circle(0.0, 0.0, 10);
System.out.println("Compare c1 and c2
= " + c1.compareTo(c2));
Square s = new Square(0.0, 0.0, 10);
System.out.println("Compare c1 and s
= " + c1.compareTo(s));
}
}
Yes it works, but the solution is not elegant!
The programmer has to check for -2 which is not a valid
comparison.
Can we avoid this?
Generics SWEN20003 12 / 36
Using the Non-generic Comparable Intf.
public class CompareShapes {
public static void main(String[] args) {
Circle c1 = new Circle(0.0, 0.0, 5);
Circle c2 = new Circle(0.0, 0.0, 10);
System.out.println("Compare c1 and c2
= " + c1.compareTo(c2));
Square s = new Square(0.0, 0.0, 10);
System.out.println("Compare c1 and s
= " + c1.compareTo(s));
}
}
Yes it works, but the solution is not elegant!
The programmer has to check for -2 which is not a valid
comparison.
Can we avoid this?
Generics SWEN20003 12 / 36
Using the Non-generic Comparable Intf.
public class CompareShapes {
public static void main(String[] args) {
Circle c1 = new Circle(0.0, 0.0, 5);
Circle c2 = new Circle(0.0, 0.0, 10);
System.out.println("Compare c1 and c2
= " + c1.compareTo(c2));
Square s = new Square(0.0, 0.0, 10);
System.out.println("Compare c1 and s
= " + c1.compareTo(s));
}
}
Yes it works, but the solution is not elegant!
The programmer has to check for -2 which is not a valid
comparison.
Can we avoid this?
Generics SWEN20003 12 / 36
Using the Non-generic Comparable Intf.
public class CompareShapes {
public static void main(String[] args) {
Circle c1 = new Circle(0.0, 0.0, 5);
Circle c2 = new Circle(0.0, 0.0, 10);
System.out.println("Compare c1 and c2
= " + c1.compareTo(c2));
Square s = new Square(0.0, 0.0, 10);
System.out.println("Compare c1 and s
= " + c1.compareTo(s));
}
}
Yes it works, but the solution is not elegant!
The programmer has to check for -2 which is not a valid
comparison.
Can we avoid this?
Generics SWEN20003 12 / 36
Using the Generic Comparable Intf.
public class CircleT implements Comparable
private double centreX = 0.0;
private double centreY = 0.0;
private double radius = 0.0;
@Override
public int compareTo(CircleT c) {
if (c.radius > this.radius)
return 1;
else if (c.radius < this.radius)
return -1;
else
return 0;
}
}
Assume you also have a SquareT class which implements
the generic Comparable interface.
Generics SWEN20003 13 / 36
Using the Generic Comparable Intf.
public class CompareShapesT {
public static void main(String[] args) {
CircleT c1 = new CircleT(0.0, 0.0, 5);
CircleT c2 = new CircleT(0.0, 0.0, 10);
System.out.println("Compare c1 and c2 = "
+ c1.compareTo(c2));
SquareT s = new SquareT(0.0, 0.0, 10);
System.out.println("Compare c1 and s = "
+ c1.compareTo(s));
//The line above will give a compiler error
}
}
Generics SWEN20003 14 / 36
Using the ArrayList Class
What are the limitations of array?
Finite length
Resizing is a manual operation
Requires effort to “add” or “remove” elements
Is there an alternative?
ArrayList class, which is a generic class, solves the
above problems!
Generics SWEN20003 15 / 36
Using the ArrayList Class
What are the limitations of array?
Finite length
Resizing is a manual operation
Requires effort to “add” or “remove” elements
Is there an alternative?
ArrayList class, which is a generic class, solves the
above problems!
Generics SWEN20003 15 / 36
Using the ArrayList Class
What are the limitations of array?
Finite length
Resizing is a manual operation
Requires effort to “add” or “remove” elements
Is there an alternative?
ArrayList class, which is a generic class, solves the
above problems!
Generics SWEN20003 15 / 36
Using the ArrayList Class
What are the limitations of array?
Finite length
Resizing is a manual operation
Requires effort to “add” or “remove” elements
Is there an alternative?
ArrayList class, which is a generic class, solves the
above problems!
Generics SWEN20003 15 / 36
Using the ArrayList Class
import java.util.ArrayList;
public class PrintCircleRadius {
public static void main(String[] args) {
ArrayList
circles.add(new CircleT(0.0, 0.0, 5));
circles.add(new CircleT(0.0, 0.0, 10));
circles.add(new CircleT(0.0, 0.0, 7));
printRadius(circles);
}
private static void printRadius(ArrayList
int index = 0;
for(CircleT c: circles) {
System.out.println(“Radius at index ” + index +
” = ” + c.getRadius());
index++;
}
}
}
Generics SWEN20003 16 / 36
Using the ArrayList Class
So what does the ArrayList give you?
Can be iterated like arrays (for-each)
Automatically handles resizing
Can insert, remove, get, and modify elements at
any index (plus many more capabilities)
Inherently able to toString()
ArrayList is a class with an array as an instance
variable.
Generics SWEN20003 17 / 36
Using the ArrayList Class
Are there any limitations of the ArrayList class?
Although an ArrayList grows automatically when
needed, it does not shrink automatically, hence can
consume more memory than required –
trimToSize() method must be invoked to release
the excess memory.
Cannot store primitive data types (int, float, etc.).
Generics SWEN20003 18 / 36
Using the ArrayList Class
Are there any limitations of the ArrayList class?
Although an ArrayList grows automatically when
needed, it does not shrink automatically, hence can
consume more memory than required –
trimToSize() method must be invoked to release
the excess memory.
Cannot store primitive data types (int, float, etc.).
Generics SWEN20003 18 / 36
Using the ArrayList Class
Elements of an ArrayList can be easily sorted if:
The stored element class implements the
Comaparable
The compareTo() method of the class must provide a
comparison (returning an integer) which will be used to
decide how the elements are sorted.
Generics SWEN20003 19 / 36
Using the ArrayList Class
Elements of an ArrayList can be easily sorted if:
The stored element class implements the
Comaparable
The compareTo() method of the class must provide a
comparison (returning an integer) which will be used to
decide how the elements are sorted.
Generics SWEN20003 19 / 36
Using the ArrayList Class
import java.util.ArrayList;
import java.util.Collections;
public class PrintCircleRadiusSorted {
public static void main(String[] args) {
ArrayList
circles.add(new CircleT(0.0, 0.0, 5));
circles.add(new CircleT(0.0, 0.0, 10));
circles.add(new CircleT(0.0, 0.0, 7));
Collections.sort(circles);
printRadius(circles);
}
private static void printRadius(ArrayList
int index = 0;
for(CircleT c: circles) {
System.out.println(“Radius of circle: at index ” +
index++ + ” = ” + c.getRadius());
}
}
}
Generics SWEN20003 20 / 36
Using the ArrayList Class
ArrayList can be used for storing different types of
objects, provided they inherit the same base class –
therefore not quite different types of objects theoretically.
Why is this useful?
Common behaviour across objects can be executed
seamlessly – see next example.
Generics SWEN20003 21 / 36
Using the ArrayList Class
public abstract class Shape {
public abstract double getArea();
}
public class Circle extends Shape {
private double radius = 0.0;
// Code for constructors, getter and setter go here
@Override
public double getArea() {
return Math.PI*radius*radius;
}
}
public class Square extends Shape {
private double length = 0.0;
// Code for constructors, getter and setter go here
@Override
public double getArea() {
return length*length;
}
}
Generics SWEN20003 22 / 36
Using the ArrayList Class
import java.util.ArrayList;
public class ComputeAreaShapes {
public static void main(String[] args) {
ArrayList
shapes.add(new Circle(0.0, 0.0, 5));
shapes.add(new Circle(0.0, 0.0, 10));
shapes.add(new Square(0.0, 0.0, 7));
printArea(shapes);
}
private static void printArea(ArrayList
int index = 0;
for(Shape s: shapes) {
System.out.println(“Area of shape: at index ” +
index++ + ” = ” + s.getArea());
}
}
}
Generics SWEN20003 23 / 36
Assess Yourself
Implement the method
ArrayList
which continually accepts integers from a user until they
end input, and returns an ArrayList of all the integers
entered.
Implement a second method
double average(ArrayList
that returns the average of all elements in numbers.
Generics SWEN20003 24 / 36
Assess Yourself
public ArrayList
ArrayList
while (scanner.hasNextInt()) {
numbers.add(scanner.nextInt());
}
return numbers;
}
Generics SWEN20003 25 / 36
Assess Yourself
public double average(ArrayList
double sum = 0.0;
for (Integer number : numbers) {
sum += number;
}
return sum / numbers.size();
}
Generics SWEN20003 26 / 36
Assess Yourself
Write a main method that allows a user to continually
enter integers, where each number is added to an
ArrayList.
The program should then create a PriorityQueue for
arranging the numbers based on the following rules:
Ascending order
Descending order
Shortest (least characters) first
Ascending order by the last (rightmost) digit
Generics SWEN20003 27 / 36
Defining a Generic Class
Keyword
Generic Class: A class that is defined with an arbitrary
type for a field, parameter or return type.
The type parameter is included in angular brackets
after the class name in the class definition heading.
A type parameter can have any reference type (i.e.,
any class type) plugged in.
Traditionally, a single uppercase letter is used for a
type parameter, but any non-keyword identifier may
be used.
A class definition with a type parameter is stored in
a file and compiled just like any other class.
Generics SWEN20003 28 / 36
Defining Generics
public class Sample
private T data;
public void setData(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
Generics SWEN20003 29 / 36
Defining a Generic Class – Multiple Types
public class TwoTypePair
private T1 first;
private T2 second;
public TwoTypePair() {
first = null;
second = null;
}
public TwoTypePair(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public void setFirst(T1 first){
this.first = first;
}
public void setSecond(T2 second) {
this.second = second;
}
// Additional methods go here
}
Generics SWEN20003 30 / 36
Using a Generic Class – Multiple Types
import java.util.Scanner;
public class TwoTypePairDemo {
public static void main(String[] args) {
TwoTypePair
new TwoTypePair
Scanner keyboard = new Scanner(System.in);
System.out.println(“Our current rating for ” +
rating.getFirst() + ” is ” + rating.getSecond());
System.out.println(“How would you rate them?”);
int score = keyboard.nextInt();
rating.setSecond(score);
System.out.println(“Our new rating for “+
rating.getFirst() + ” is ” + rating.getSecond());
}
}
Generics SWEN20003 31 / 36
Generic Methods
Keyword
Generic Method: A method that accepts arguments, or
returns objects, of an arbitrary type.
A generic method can be defined in any class. The type
parameter (e.g. T) is local to the method.
public
public
public
public
Generics SWEN20003 32 / 36
Generic Methods
Keyword
Generic Method: A method that accepts arguments, or
returns objects, of an arbitrary type.
A generic method can be defined in any class. The type
parameter (e.g. T) is local to the method.
public
public
public
public
Generics SWEN20003 32 / 36
Generic Methods
Keyword
Generic Method: A method that accepts arguments, or
returns objects, of an arbitrary type.
A generic method can be defined in any class. The type
parameter (e.g. T) is local to the method.
public
public
public
public
Generics SWEN20003 32 / 36
Generic Methods
Keyword
Generic Method: A method that accepts arguments, or
returns objects, of an arbitrary type.
A generic method can be defined in any class. The type
parameter (e.g. T) is local to the method.
public
public
public
public
Generics SWEN20003 32 / 36
Generic Methods
Keyword
Generic Method: A method that accepts arguments, or
returns objects, of an arbitrary type.
A generic method can be defined in any class. The type
parameter (e.g. T) is local to the method.
public
public
public
public
Generics SWEN20003 32 / 36
Assess Yourself
Write a generic method that accepts two arguments:
array: an array of elements whose type is T
item: an object of the same type as the array’s
elements
The method should return a count of how many times
item appears in array.
Generics SWEN20003 33 / 36
Assess Yourself
public class TestGenericMethods {
public static void main(String[] args) {
Integer[] nums = {1, 3, 6, 9, 3, 5, 9, 3, 5, 42, null};
String[] names = {“Jon”, “Arya”, “Dany”, “Tyrion”, “Jon”};
System.out.println(countOccurrences(nums, 3));
System.out.println(countOccurrences(names, “Jon”));
}
public static
int count = 0;
if (item == null) {
for (T arrayItem : array){
count = arrayItem == item ? count + 1 : count;
}
} else {
for (T arrayItem : array){
count = item.equals(arrayItem) ? count + 1 : count;
}
}
return count;
}
}
Generics SWEN20003 34 / 36
Pitfall: What Can’t We Do?
Generic programming is powerful, but has its limitations.
When using generics, we can’t:
Instantiate parametrized objects
T item = new T();
Create arrays of parametrized objects
T[] elements = new T[];
Otherwise, most things are fair game.
Generics SWEN20003 35 / 36
Learning Outcomes
You should be able to:
Understand generic classes in Java
Use generically typed classes
Define generically typed classes
Understand generics’ subtyping
Generics SWEN20003 36 / 36