Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

29
Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction

Transcript of Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

Page 1: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

Advanced Generics and other niceties

SOFTENG 251

Object Oriented Software Construction

Page 2: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 2Advanced generics and niceties

Announcements

Test official time change: 6:30pm – come in at 6:15 ~ 6:20 to start reading test script

(Thursday 24th)

Wednesday tutorial going over past years’ tests Post questions on Wiki by Tuesday night

Some questions from past years not applicable to this year’s

Assignment 2: aim to get at least first 4 tasks finished and demonstrated by Thursday (24th) lab Task 5 – submit via dropbox if need be

Optional tasks – can demonstrate by 1st May

Page 3: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 3Advanced generics and niceties

Subtyping

public static void main(String[] args) { Object obj = "I’m a String, but also an Object"; Movie movie = new Movie("Psycho",1960); printTitle(movie);}

public static void printTitle(Item item) { System.out.println(item.getTitle());}

Remember polymorphism allows reference variables of type T to point to objects of type T or its subclasses

e.g. List := ArrayListItem := MoviePriced := CDItem := CD

Item

Book Movie CD

<<interface>>

Priced

Page 4: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 4Advanced generics and niceties

Subtyping in arrays

Can an array of T point to an array of T’s subclass?

e.g. Item[] := Movie[] ?

Yes

public static void main(String[] args) { Movie[] movies = new Movie[5]; populate(movies); list(movies);}...public static void list(Item[] items) { for (Item item : items) { System.out.println(item.getTitle()); }}

Page 5: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 5Advanced generics and niceties

public static void main(String[] args) { List<Movie> movies = new ArrayList<Movie>(); populate(movies); list(movies);}...public static void list(List<Item> items) { for (Item item : items) { System.out.println(item.getTitle()); }}

Subtyping in generics

?

Can a reference variable of type U parameterised with T point to an object of type U (or its subclass) parameterised with T’s subclass?

e.g. List<Item> := List<Movie> or List<Item> := ArrayList<Movie>?

NO…! :-S

Page 6: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 6Advanced generics and niceties

Subtyping in generics

public static void main(String[] args) { List<Movie> movies = new ArrayList<Movie>(); populate(movies); list(movies);}...public static void list(List<Item> items) { ... items.add(new Book("LOTR","Tolkien"));}

Suppose this was allowed…

Then this would also be valid (!)(If we take this method out of context, then all we can see is adding a Book to a vector of Item’s, which seems perfectly valid)

Effectively we’d be allowed to add a Book to a vector that’s only supposed to have Movies!

Page 7: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 7Advanced generics and niceties

Subtyping in generics How can we parameterise a List to accept any subtype of Item

(including Item itself)? One way: public<T extends Item> static void list(List<T>

items)

There’s actually another way......

public static void main(String[] args) { List<Movie> movies = new ArrayList<Movie>(); List<Book> books = new LinkedList<Book>(); populate(movies); populate(books); list(movies); list(books);}...public static void list(List<Item> items) { for (Item item : items) { System.out.println(item.getTitle()); }}

???

Page 8: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 8Advanced generics and niceties

public static void main(String[] args) { List<Movie> movies = new ArrayList<Movie>(); List<Book> books = new LinkedList<Book>(); populate(movies); populate(books); list(movies); list(books);}...public static void list(List<? extends Item> items) { for (Item item : items) { System.out.println(item.getTitle()); }}

Wildcard types Use wildcards to denote ‘unknown type’ <? extends T> (i.e. any subclass of T, including T itself) signifies

a bounded wildcard <?> (i.e. any type) signifies an unbounded wildcard Note: <?> is equivalent to <? extends Object>

Page 9: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 9Advanced generics and niceties

More wildcards <? super T> is also a bounded wildcard, meaning the reverse

of extends, i.e. “any superclass (ancestor) of T, including T itself”

E.g. below: find items in first, but not in second – second can be more general than first:

public<T> List<T> listDiff(List<T> list1, List<? super T> list2) { List<T> itemsOnlyIn1 = new ArrayList<T>(); for (T item : list1) { if (!list2.contains(item)) { itemsOnlyIn1.add(item); } } return itemsOnlyIn1;}

Look, we can use wildcards with type parameters too!

List<Book> books = ...; //[book1,book2,book3]List<Items> archive = ...; //[book1,cd1,movie1,book2,cd2]List<Book> newBooks = listDiff(books, archive); //[book3]

Page 10: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 10Advanced generics and niceties

Examples of wildcards in API

Realise extends in generics means both extends and implements

public static <T> void sort(List<T> list, Comparator<? super T> c)

public static <T extends Comparable<? super T>> void sort(List<T> list)

CD

<<interface>>

Priced

+getPrice():Money

public class PriceComparatorimplements Comparator<Priced> { public int compare(Priced p1, Priced p2) { return p1.getPrice().compareTo(p2.getPrice()); }}

List<CD> albums = getAlbums();Collections.sort(albums, new PriceComparator());List<Shirt> shirts = getShirts();Collections.sort(shirts, new PriceComparator());

Shirt

This allows us to sort a specific list with a more general comparator, increasing flexibility. E.g:

Page 11: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 11Advanced generics and niceties

Collection: bulk methods Collection<? extends E>

Collection of E or subclasses

Below: what happens to the elements of the Set items after copy.remove(item1)?

Set<Movie> items = new HashSet<Movie>();items.add(item1);items.add(item2);items.add(item3);List<Item> copy = new ArrayList<Item>();copy.addAll(items);copy.remove(item1);

Methods in Collection<E>:+addAll(Collection<? extends E>):boolean+containsAll(Collection<?>):boolean+removeAll(Collection<?>):boolean+retainAll(Collection<?>):boolean

Add all elements in items to copyaddAll() expects Collections<? extends Item> and we’re giving in a Set<Movie> all matches up

HashSet<Movie>

items : Set<Movie>

ArrayList<Item>

copy : List<Item>

item1 : Movie

item2 : Movie

item3 : Movie

Page 12: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 12Advanced generics and niceties

Assignment 2 task 5 (kind of)

public static<T> List<T> genericSearch(List<T> items, SearchCriterion<T> filter)

Given a List items and a filter, apply the filter to each element in items and return a List of only the elements accepted by the filter

public class ShortTitles implementsSearchCriterion<Movie> { private int length; public ShortTitles(int length) { this.length = length; } public boolean accept(Movie mov) { return mov.getTitle().length() < length; }}

SearchCriterion<Movie> filter = new ShortTitles(5);List<Movie> movies = mdb.listMovies();List<Movie> results = genericSearch(movies, filter);

results : List<Movie> T Movie

TVSeries

Item

tvShows : List<Movie>

filter : SearchCriterion<Movie>

Accept any movie whose title is less than length characters long

Page 13: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 13Advanced generics and niceties

Assignment 2 task 5

public static<T> List<T> genericSearch(List<? extends T> items, SearchCriterion<T> filter)

Search List items more specific than T with filter for T, and return a List of T flexibility from one side

results : List<Movie>

tvShows : List<TVSeries>

? extends T

T

public class ShortTitles implementsSearchCriterion<Movie> { private int length; public ShortTitles(int length) { this.length = length; } public boolean accept(Movie mov) { return mov.getTitle().length() < length; }}

SearchCriterion<Movie> filter = new ShortTitles(5);List<TVSeries> tvShows = mdb.listTVShows();List<Movie> results = genericSearch(tvShows, filter);

Movie

TVSeries

Item

filter : SearchCriterion<Movie>

Page 14: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 14Advanced generics and niceties

Assignment 2 task 5

public static<T> List<T> genericSearch(List<? extends T> items, SearchCriterion<? super T> filter)

Search List items more specific than T with filter more general than T, and return a List of T flexibility from both sides

Movie

TVSeries

Item

results : List<Movie>

filter : SearchCriterion<Item>

tvShows : List<TVSeries>

? super T

? extends T

T

public class ShortTitles implementsSearchCriterion<Item> { private int length; public ShortTitles(int length) { this.length = length; } public boolean accept(Item item) { return item.getTitle().length() < length; }}

SearchCriterion<Item> filter = new ShortTitles(5);List<TVSeries> tvShows = mdb.listTVShows();List<Movie> results = genericSearch(tvShows, filter);

Page 15: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 15Advanced generics and niceties

Wildcard caveats Can’t provide argument for a parameter of wildcard type

(except for null) Can’t instantiate generic types parameterised with a

wildcard (but you can declare them) Think of wildcard-parameterised types as “read-only” types

public static void populate(List<? extends Item> items) { items.add(new Movie("Vertigo",1958)); items.add(new Book("Dilbert","Adams")); items.add(null); //COMPILER ALLOWS}

public static Vector<?> reverseA(List<? extends Item> list) { List<?> rev = new ArrayList<?>(); ...}

Page 16: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 16Advanced generics and niceties

List<Movie> m = new ArrayList<Movie>();...public<T extends Item> void inspect(List<T> v) { T first = v.get(0); String title = first.getTitle();}

Aside: type erasure

Only the compiler knows about generics The JVM (Java Virtual Machine) doesn’t

Requiring JVM implementations to cater for generics would be impractical (hint: Sun isn’t the only JVM vendor in the market!)

Thus compiler erases information about generic types when generating bytecodes (.class files) to be executed by the JVM

Maintain compatibility with legacy code – i.e. Java programs written before generics were introduced

‘Item’

Page 17: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 17Advanced generics and niceties

Type erasure – limitations What does this mean?

1. You can’t use type parameters for operations that require runtime knowledge of the exact type being used

public<T extends Item> void addItem(List<T> list) { list.add(new T());}

public<T> T[] makeArray(Vector<T> v) { T[] array = new T[5]; for ( int i = ...}

public <T extends Item> void yikes(Object obj) { if (obj instanceof T) { T item = (T)obj; }}

In all three cases, the JVM would have no knowledge of the exact type that T is supposed to be, so it would not be able to find the appropriate class definition in order to perform instantiation, array creation or casting

Compiler issues warning

Page 18: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 18Advanced generics and niceties

Type erasure – limitations

2. You can’t use parameterised types for operations that would lose type information at runtime due to erasure

public void failToOverload(List<Movies> movies) { ...}public void failToOverload(List<Book> books) { ...}

public void convert(List rawList) { if (rawList instanceOf List<Item>) { List<Item> items = (List<Item>) rawList; }}

List<Item> does not exist in runtime: it’s just plain old List. Again, due to type erasure, the information about the type argument is lost

For the same reasons, you can’t overload a method with the same generic type as parameter, even if they are each parameterised with a different type

Page 19: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 19Advanced generics and niceties

Type erasure – limitations

3. Also, certain “suspicious” operations are allowed so as to enable interoperability with legacy code

public static void main(String[] args) { List oldBooks = (List)legacyCode(); List<Books> = oldBooks; //COMPILER WARNING}

public static List legacyCode() { List rawList = new ArrayList(); rawList.add(new Book("LOTR","Tolkien")); return rawList;}

If you do not parameterise a generic type, it becomes a raw type. But compiler doesn’t like this (sounds familiar?)

This is actually allowed! (Why?) BUT, the compiler issues a warning, and this practice is generally discouraged (unless there’s no other choice).

Page 20: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 20Advanced generics and niceties

Further reading

Generics can be pretty daunting and confusing The best way to understand generics is to keep applying them

The compiler is your judge!

The Java Tutorial on generics: good comprehensive reference http://java.sun.com/docs/books/tutorial/java/generics/index.html

(for “starters”)

http://java.sun.com/docs/books/tutorial/extra/generics/index.html (more comprehensive)

Page 21: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 21Advanced generics and niceties

Autoboxing – prelude Recall difference between primitive and reference types

Can’t use primitive types in a context expecting only reference types. E.g: Can’t instantiate List<int>, or call remove(double) on Set

To compensate for this Java provides a “wrapper” class for each primitive type Plus an abstract class Number to represent all numeric

primitives

But wrapping/unwrapping primitives every time can be a pain

Reference: Anything that extends Object

Integer decimal = new Integer(30);Double fraction = new Double(0.25);Double sum = new Double(decimal.intValue()+fraction.doubleValue());System.out.println(sum);System.out.println(decimal.compareTo(new Integer(25)));List<Number> numbers = new ArrayList<Number>();numbers.add(decimal);numbers.add(fraction); Most Number

subclasses implement Comparable

Primitive: int boolean double ...

Page 22: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 22Advanced generics and niceties

Autoboxing (Java 1.5)

Integer decimal = 30;Double fraction = 0.25;double sum = decimal + fraction;System.out.println(sum);System.out.println(decimal.compareTo(25));List<Integer> numbers = ...int num1 = numbers.get(0);int num2 = numbers.get(1);

new Integer(30);new Double(0.25);

decimal.intValue() + fraction.doubleValue();

new Integer(25)

Translates to:

numbers.get(0).intValue();

Double wrongPrecision = 30;Number n = 20.0;double tooGeneral = n;

Integer danger = null;int ouch = danger;

But note: Although int is a double, Integer is NOT a Double

Although you can call n.doubleValue(), this assignment is only valid if n is a Double

danger.intValue()Guess what happens here…

Page 23: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 23Advanced generics and niceties

Person p1 = ...;Person p2 = ...;Person p3 = ...;Movie movie = ... ;movie.addCrewRole(DIRECTOR, p1);movie.addCrewRole(PRODUCER, p2);movie.addCrewRole("dictator", p3);

Person p4 = movie.getCrewRole("bum");

Enumerated types

Java lacked support for enumerated types prior to 1.5, so integer/String constants were commonly used as workaround

This approach has problems Not type-safe

Error-prone

public static final String DIRECTOR = "director";public static final String PRODUCER = "director";public static final String WRITER = "writer";public static final String EDITOR = "editor";public static final String CINEMATOGRAPHER = "cinematographer";public static final String COMPOSER = "composer";

The role is just a String. Any bogus String value can be given where really a restricted set of names is expected.

We could accidentally make two roles “the same”, leading to unexpected behaviour

Page 24: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 24Advanced generics and niceties

Java 1.5 enum types

An enum declaration in Java looks like that of its C, C# and C++ counterparts, but the similarity is only superficial

public enum Role {DIRECTOR, PRODUCER, WRITER, EDITOR, CINEMATOGRAPHER, COMPOSER}

An enum declaration can also include additional state and behaviour – and implement further interfaces!

Think of enums as special classes that can only have a limited number of distinct instances usable in switch statements

public String describe(Role role) { switch (role) { case DIRECTOR: return "Tells people what to do and does nothing for oneself"; case PRODUCER: return "Gets all the money"; etc... }}

Page 25: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 25Advanced generics and niceties

Java 1.5 enum types

public enum Role { DIRECTOR, PRODUCER, WRITER, EDITOR, CINEMATOGRAPHER, COMPOSER}

Compiling the enum declaration Role generates a fully-fledged class which (amongst other things):

Order of declaration matters equals() – returns true if two Role

objects have the same value

toString() – returns its value as a String

name() – returns its value

ordinal() – returns its position relative the complete possible set of values

values() – (static) returns an array containing all possible Role values

compareTo(Role) – compares the ordinal() beteween this and other

All methods above except toString() are final, meaning they can’t be further overridden

Page 26: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 26Advanced generics and niceties

Java 1.5 enum types

public enum Role { DIRECTOR, PRODUCER, WRITER, EDITOR, CINEMATOGRAPHER, COMPOSER}

for( Role role : Role.values() ) System.out.println( role );

Role king = Role.DIRECTOR;Role brains = Role.WRITER;Role poet = Role.WRITER;Role err = Role.IDONTEXIST;

System.out.println(king.toString());

System.out.println(brains.equals(poet));

System.out.println(brains.ordinal());

System.out.println(king.compareTo(brains));

Note how instances of an enumeration type are created.

DIRECTORPRODUCERWRITEREDITORCINEMATOGRAPHERCOMPOSER

-2

true

DIRECTOR

2

Compilation error

Page 27: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 27Advanced generics and niceties

Method overloading

Java allows several methods of the same name to be defined within a class as long as the methods have different sets of parameters Contrast to overriding

One parameter set is different to another if at least one of the following is true: The number of parameters is different

The types of the parameters is different

The ordering of parameter types is different

public void println() { ... }public void println(String message) { ... }public void println(String message, int repeat) { ... }public void println(int heading, String message) { ... }public void println(int number) { ... }public void println(Object object) { ... }

Page 28: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 28Advanced generics and niceties

Vararg – motivation Test if a list of things have all the expected elements

Iterate through each element and match with expected element This can get rather tedious – imagine we have to do 20 test

cases like thisList<String> words = getList();Iterator<String> iterator = words.iterator();assertEquals(5, words.size());assertEquals("first",iterator.next());assertEquals("second",iterator.next());assertEquals("third",iterator.next());assertEquals("fourth",iterator.next());assertEquals("fifth",iterator.next());

Wouldn’t it be nice if we can do something like this instead:

List<String> words = getList();assertCollectionEquals(words, "first","second","third","fourth","fifth");

List<String> letters = getAnotherList();assertCollectionEquals(letters, "x","y","z","b");

Page 29: Advanced Generics and other niceties SOFTENG 251 Object Oriented Software Construction.

SOFTENG 251 Object Oriented Software Construction 29Advanced generics and niceties

Vararg usage Vararg T... represents a variable sequence of arguments of type T vararg parameter of type T... is equivalent to T[] Can only come as the last argument to prevent ambiguity

public static<T> void assertCollectionEquals(Collection<T> actual, T... expected) { assertEquals(expected.length, actual.size()); Iterator<T> actualIterator = actual.iterator(); for (T expectedElem : expected) { assertEquals(expectedElem,actualIterator.next()); }}

public static void printf(String format, Object... args) { ... }

System.out.printf("%d people say %s", 10, "hi");

Hey! Like in C: printf("%d people say %s", 10, "hi");

In fact, Java has one too! System.out.printf();