{ this.object = object; } public T get() { return object; } public static void main(String[] args) { Box<String> b = new Box<String>(); b.set("moi"); System.out.println(b.get()); } } Type that we can determine runtime It is a String now
{ this.object = object; } public T get() { return object; } public static void main(String[] args) { // Java SE 10 var b = new Box<String>(); b.set("moi"); System.out.println(b.get()); } } Shorter syntax in Java 10
public static void main(String[] args) { Pair<String, Integer> b = new Pair<>(); b.key = "key"; b.value = new Integer(3); // or by using autoboxing // = 3; } } Two generic values In Java 5 autoboxing makes automatic conversion
implements Flyable { public void fly() { System.out.println("bird in the air!"); } } class Airplane implements Flyable { public void fly() { System.out.println("airplane in the air!"); } } class Test { public static void main(String[] args) { doSomething(new Bird()); doSomething(new Airplane()); doSomething(new Flyable() { @Override public void fly() { System.out.println("Anonymous inner class in the air"); } }); doSomething(() -> System.out.println("Lambda in the air")); } public static <T extends Flyable> void doSomething(T stuff) { stuff.fly(); } } extends?
startThread() { new Thread(value).start(); } } class Test implements Runnable { public static void main(String[] args) { Box<Test> b1 = new Box<>(); b1.value = new Test(); b1.startThread(); } public void run() { System.out.println("Hello from thread"); } } Does it work?
class Waitress extends Person {} class Test { public static void main(String[] args) { var list1 = List.of(new Programmer(), new Programmer()); var list2 = List.of(new Waitress(), new Waitress()); Test.<Programmer, Waitress>copy(list1, list2); } public static void copy(List<? extends Person> dest, List<? extends Person> src) { } } Using Custom Classes
class Waitress extends Person {} class Test { public static void main(String[] args) { var list1 = List.of(new Person(), new Programmer()); var list2 = List.of(new Person(), new Waitress(), new Object()); Test.<Programmer, Waitress>copy(list1, list2); } public static void copy(List<? super Programmer> dest, List<? super Waitress> src) { } } Can be Waitress or super class
extends Person {} class Test { public static void main(String[] args) { var list1 = List.of(new Programmer(), new Programmer()); var list2 = List.of(new Person(), new Person()); Test.<Programmer, Waitress>copy(list1, list2); } public static <T1 super Programmer, T2 super Waitress> void copy(List<T1> dest, List<T2> src) { } } Super is only supported in the wild card.., does not work
– implementation uses dynamically resized arrays. Grow 50% of it's size each time • LinkedList – double-linked list. Also implements Queue – interface. • Also Vector (deprecated) • Performance varies depending on what you do!
a generic array of T • T [] data = new T[3] • Generics are implemented using “type erasure” • generic type information is not available at runtime • only used at compile time for type checking and then erased • This allows generics to be backward compatible with older Java versions that do not have generics • When an array is instantiated, its actual type must be known at runtime • … but generic type information is not available at runtime.
a number • Simple example • ”jack” => [106, 97, 99, 107] => 409 • Object could be stored internally in an array in index 409 • Hash collisions could occur ”kcaj” => 409 • If this is the case, many times equals methods is used • Not having proper hashCode can also seem to work, but performance can be an issue • Many collection classes rely that hashCode (and equals) is implemented correctly • HashMap, HashSet, Hashtable, LinkedHashMap
name, int age) { @Override public int hashCode() { // Poor implementation: constant hash code return 1; } @Override public boolean equals(Object o) { return this == o; // just checks memory addresses } } public class Main { public static void main(String[] args) { HashMap<GoodPerson, String> goodMap = new HashMap<>(); HashMap<BadPerson, String> badMap = new HashMap<>(); // Populate GoodPerson HashMap goodMap.put(new GoodPerson("John", 30), "Developer"); goodMap.put(new GoodPerson("Jane", 25), "Designer"); System.out.println("GoodPerson map retrieval: " + goodMap.get(new GoodPerson("John", 30))); // Populate BadPerson HashMap badMap.put(new BadPerson("John", 30), "Developer"); badMap.put(new BadPerson("Jane", 25), "Designer"); // calculates the hashcode, it is 1 // uses hashcode to find the person from an array // All instances are in index 1! // array contains a linked list which will hold two BadPersons // in index 1 // it goes through the linked list and checks with equals can // it find the given person // since equals checks memory addresses the given BadPerson object // has different address than the ones in the map. // no objects are found and null is given System.out.println("BadPerson map retrieval: " + badMap.get(new BadPerson("John", 30))); // The retrieval for BadPerson may not work as intended due to the poor equals method. } }