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

  • 942