Java Generics
Copyright 2017 - Jacob D. Parr
https://www.jacobparr.com
(all rights reserved)

Coffee<T>
Java Generics
A Generic Quiz
For every code snippet, determine if it's...


LEGAL
ILLEGAL
Hit the down arrow to continue
Java Generics
A Generic Quiz
Question #1
Hit the down arrow to continue
List<String> list = new ArrayList<String>();
Java Generics
A Generic Quiz
Question #1
Hit the down arrow to continue
List<String> list = new ArrayList<String>();

Java Generics
A Generic Quiz
Question #2
Hit the down arrow to continue
List<String> list = new ArrayList<>();
Java Generics
A Generic Quiz
Question #2
Hit the down arrow to continue
List<String> list = new ArrayList<>();

Java Generics
A Generic Quiz
Question #3
Hit the down arrow to continue
List<Object> list = new ArrayList<String>();
Java Generics
A Generic Quiz
Question #3
Hit the down arrow to continue
List<Object> list = new ArrayList<String>();

- Lists are not polymorphic (Object vs String)
Java Generics
A Generic Quiz
Question #4
Hit the down arrow to continue
ArrayList<Object> list = new ArrayList<String>();
Java Generics
A Generic Quiz
Question #4
Hit the down arrow to continue
ArrayList<Object> list = new ArrayList<String>();

- Lists are not polymorphic (Object vs String)
- Even if the list are of the same type
Java Generics
A Generic Quiz
Question #5
Hit the down arrow to continue
ArrayList<String> list = new ArrayList<Object>();
Java Generics
A Generic Quiz
Question #5
Hit the down arrow to continue
ArrayList<String> list = new ArrayList<Object>();

- Lists are not polymorphic (String vs Object)
- Even if the list are of the same type
Java Generics
A Generic Quiz
Question #6
Hit the down arrow to continue
ArrayList list = new ArrayList<String>();
Java Generics
A Generic Quiz
Question #6
Hit the down arrow to continue
ArrayList list = new ArrayList<String>();

- A typed list is assigned to an untyped list
Java Generics
A Generic Quiz
Question #7
Hit the down arrow to continue
ArrayList<String> list = new ArrayList();
Java Generics
A Generic Quiz
Question #7
Hit the down arrow to continue
ArrayList<String> list = new ArrayList();

- Valid, but it will generate a compiler warning
Java Generics
A Generic Quiz
Question #8
Hit the down arrow to continue
ArrayList<String> stringList = null; ArrayList<? extends String> extdStringList = stringList;
Java Generics
A Generic Quiz
Question #8
Hit the down arrow to continue
ArrayList<String> stringList = null; ArrayList<? extends String> extdStringList = stringList;

- Assigning String to something that extends String
Java Generics
A Generic Quiz
Question #9
Hit the down arrow to continue
ArrayList<?> list = new ArrayList<Number>();
Java Generics
A Generic Quiz
Question #9
Hit the down arrow to continue
ArrayList<?> list = new ArrayList<Number>();

- Assigning a typed list to a list of anything
Java Generics
A Generic Quiz
Question #10
Hit the down arrow to continue
ArrayList<? extends Number> extendsList = null; ArrayList<? super Number> superList = extendsList;
Java Generics
A Generic Quiz
Question #10
Hit the down arrow to continue
ArrayList<? extends Number> extendsList = null; ArrayList<? super Number> superList = extendsList;

Java Generics
A Generic Quiz
Question #11
Hit the down arrow to continue
ArrayList<? super Number> superNumList = null; ArrayList<? super Integer> superIntList = superNumList;
Java Generics
A Generic Quiz
Question #11
Hit the down arrow to continue
ArrayList<? super Number> superNumList = null; ArrayList<? super Integer> superIntList = superNumList;

- From a read perspective, the list of super-Integer contains Integers or it's super class, Number
Java Generics
A Generic Quiz
Question #12
Hit the down arrow to continue
ArrayList<Object> list = new ArrayList<Object>(); list.add(“Hello”);
Java Generics
A Generic Quiz
Question #12
Hit the down arrow to continue
ArrayList<Object> list = new ArrayList<Object>(); list.add(“Hello”);

- List of Object - we can add anything to that
Java Generics
A Generic Quiz
Question #13
Hit the down arrow to continue
ArrayList<?> list = new ArrayList<String>(); list.add(“Hello”);
Java Generics
A Generic Quiz
Question #13
Hit the down arrow to continue
ArrayList<?> list = new ArrayList<String>(); list.add(“Hello”);

- We do not know what the list contains therefore we cannot add anything to it
- Expecting capture<?>
- Effectively "read-only"
Java Generics
A Generic Quiz
Question #14
Hit the down arrow to continue
ArrayList<? super Integer> list= new ArrayList<Integer>(); list.add(1);
Java Generics
A Generic Quiz
Question #14
Hit the down arrow to continue
ArrayList<? super Integer> list= new ArrayList<Integer>(); list.add(1);

- Expects an Integer or a sub type
Java Generics
A Generic Quiz
Question #15
Hit the down arrow to continue
ArrayList<? extends Number> list = new ArrayList<Integer>(); list.addAll(new ArrayList<Integer>());
Java Generics
A Generic Quiz
Question #15
Hit the down arrow to continue
ArrayList<? extends Number> list = new ArrayList<Integer>(); list.addAll(new ArrayList<Integer>());

-
addAll(Collection<? extends E> c) is expecting
Collection<? extends capture<? extends Number>>)
Java Generics
A Generic Quiz
Question #16
Hit the down arrow to continue
ArrayList<? super Integer> listA = new ArrayList<Number>(); ArrayList<? extends Integer> listB = new ArrayList<Integer>(); listB.addAll(listA);
Java Generics
A Generic Quiz
Question #16
Hit the down arrow to continue
ArrayList<? super Integer> listA = new ArrayList<Number>(); ArrayList<? extends Integer> listB = new ArrayList<Integer>(); listB.addAll(listA);

- listB expects an Integer or sub class
- From a read perspective, all we know about listA
is that it is an Object
Java Generics
A Generic Quiz
Question #17
Hit the down arrow to continue
ArrayList<? super Integer> listA = new ArrayList<Number>(); ArrayList<? extends Integer> listB = new ArrayList<Integer>(); listA.addAll(listB);
Java Generics
A Generic Quiz
Question #17
Hit the down arrow to continue
ArrayList<? super Integer> listA = new ArrayList<Number>(); ArrayList<? extends Integer> listB = new ArrayList<Integer>(); listA.addAll(listB);

- From a read perspective, listB is Integer
- Which is write compatible with listA
Java Generics
A Generic Quiz
Question #18
Hit the down arrow to continue
ArrayList<Integer> intList = new ArrayList<Integer>(); intList.add(new Integer(1)); ArrayList<? extends Number> extendsNumList = intList; Integer integer = extendsNumList.get(0);
Java Generics
A Generic Quiz
Question #18
Hit the down arrow to continue
ArrayList<Integer> listA = new ArrayList<Integer>();
listA.add(new Integer(1));
ArrayList<? extends Number> listB = listA;
Integer integer = listB.get(0);

- From a read perspective, listB is a Number
Java Generics
A Generic Quiz
Question #19
Hit the down arrow to continue
ArrayList<String>[] twoDimArray = new ArrayList<String>[10];
Java Generics
A Generic Quiz
Question #19
Hit the down arrow to continue
ArrayList<String>[] twoDimArray = new ArrayList<String>[10];

- Arrays of a generic types are not allowed
- Erasure of <String> at runtime
Java Generics
A Generic Quiz
Question #20
Hit the down arrow to continue
Pair<String, String>[] array = new Pair[2]; array[0] = new Pair<String, String>(“1′′, “y”); array[1] = new Pair(true, false);
Java Generics
A Generic Quiz
Question #20
Hit the down arrow to continue
Pair<String, String>[] array = new Pair[2]; array[0] = new Pair<String, String>(“1′′, “y”); array[1] = new Pair(true, false);

- The instantiation of new Pair[2] is not generic
- Pair<String,String>[] is a compile time constraint
- But new Pair(true, false) is unchecked (warning)
- array cannot enforce anything beyond Pair
Java Generics
A Generic Quiz
Question #21
Hit the down arrow to continue
Pair<?,?>[] array = new Pair<?,?>[2] ; array[0] = new Pair<Integer,Integer>(0,0); array[1] = new Pair<String,String>(“Hello”,”There”);
Java Generics
A Generic Quiz
Question #21
Hit the down arrow to continue
Pair<?,?>[] array = new Pair<?,?>[2] ; array[0] = new Pair<Integer,Integer>(0,0); array[1] = new Pair<String,String>(“Hello”,”There”);

- Effectively the same as the previous example
Java Generics
Create a Dog
Create the class Dog
- name: String
- owner: String
- getters/setters
- Constructor accepting both params
- Add functions: speak(), doTrick() and eatBone()
Java Generics
Create a PetShow
This is our public static void main(..)
- Create a List of type Dog
- Add several dogs to the list
- Loop through the pets
- System.out.printf("%s walks onto the stage.%n", ...)
- pet.speak()
- pet.doTrick()
- System.out.printf("%s exits the stage.%n", ...)
Java Generics
Refactor PetShow - Extract showPet()
- Select the inner loop
- Refactor | Extract | Method...
- Name the new method showPet(p:Dog)
Java Generics
Refactor Dog - Extract Pet Interface
- From the class Dog
- Refactor | Extract | Interface...
- Name the new interface Pet
- Select the methods
- speak()
- doTrick()
- getName()
eatBone()
- When prompted, DON'T replace all occurances
Java Generics
Create a Cat
Create the class Class
- name: String
- owner: String
- getters/setters
- Constructor accepting both params
- Implements Pet
- Use the quick fix to add unimplemented methods
- System.out.format("%s meows softly.%n", name);
- System.out.format("%s licks itself.%n", name);
Java Generics
Update PetShow for all Pets
- Change List<Dog> to List<Pet>
- Change for (Dog pet : pets) to for (Pet pet : pets)
- Change show(Dog pet) to show(Pet pet)
- Extract runPetShow(pets:List<Pet>)
- Select the for loop
- Refactor | Extract | Method...
- Name the method runPetShow
- Update the list of pets to include some Cats
Java Generics
Running Three Shows
- Create three lists
- One for cats
- One for dogs
- One for pets (from the list of cats & dogs)
- Add two more shows
- runPetShow(pets) - original
- runPetShow(cats)
- runPetShow(dogs)
Why doesn't that work?
Java Generics
Should we allow this?
List<Pet> pets = new ArrayList<Pets>()
List<Dog> dogs = new ArrayList<Dogs>() // Dogs and dogs only !!
addCats(pets);
addCats(dogs); //Compile error
public void addCats(List<Pet> pets) {
pets.add(new Cat(...); // No compile error
}
- We cannot allow a List<Dog> to become a List<Pet>
- If we allowed this, then cats and dogs would be living together and all hell would start to break loose
Java Generics
How do we fix runPetShow()?
- Update runPetShow(..) to accept List<? extends Pet>
That works !!!
Java Generics
What about addCats(..)?
- Update addCats(..) to accept List<? extends Pet>
And now that doesn't :-(
List<Pet> pets = new ArrayList<Pets>()
List<Dog> dogs = new ArrayList<Dogs>() // Dogs and dogs only !!
addCats(pets);
addCats(dogs); // Now this compiles
public void addCats(List<Pet> pets) {
pets.add(new Cat(...); // But now this doesn't compile :-(
}
Java Generics
How to fix addCats(..)?
- How can I prevent addCats(..) from accepting dogs?
- Change it back to addCats(List<Pet>)
- What can I do to addCats(..) to make this work?
- How about addCats(<? extends Cat>)?
Java Generics
Super Generics to the rescue
- The solution is addCat(List<? super Cat>)
Java Generics
Recap
<? super Xxx>
- When updating we can add Xxx (or its subtype)
- When reading, at best it is an Object
- It's "write-only"
<? extends Xxx>
- When updating, we cannot add objects
- When reading, it is Xxx (or its subtype)
- It's "read-only"
And as a general rule, don't return wildcards from a method...
Java Generics
By Jacob D Parr
Java Generics
- 961