From 9b890f326c08ca103db480a487c48c7b0a119d17 Mon Sep 17 00:00:00 2001 From: 100yo Date: Fri, 8 Nov 2024 23:39:34 +0200 Subject: [PATCH] Add Generics code snippets --- 05-generics/snippets/README.md | 1 + 05-generics/snippets/src/BridgeMethods.java | 41 +++++++ 05-generics/snippets/src/Container.java | 11 ++ 05-generics/snippets/src/Fruit.java | 6 + 05-generics/snippets/src/GenericRecord.java | 3 + .../snippets/src/GenericsPlayground.java | 110 ++++++++++++++++++ 05-generics/snippets/src/Pair.java | 47 ++++++++ 7 files changed, 219 insertions(+) create mode 100644 05-generics/snippets/README.md create mode 100644 05-generics/snippets/src/BridgeMethods.java create mode 100644 05-generics/snippets/src/Container.java create mode 100644 05-generics/snippets/src/Fruit.java create mode 100644 05-generics/snippets/src/GenericRecord.java create mode 100644 05-generics/snippets/src/GenericsPlayground.java create mode 100644 05-generics/snippets/src/Pair.java diff --git a/05-generics/snippets/README.md b/05-generics/snippets/README.md new file mode 100644 index 00000000..31c90b58 --- /dev/null +++ b/05-generics/snippets/README.md @@ -0,0 +1 @@ +# Generics / Code snippets diff --git a/05-generics/snippets/src/BridgeMethods.java b/05-generics/snippets/src/BridgeMethods.java new file mode 100644 index 00000000..49f46e70 --- /dev/null +++ b/05-generics/snippets/src/BridgeMethods.java @@ -0,0 +1,41 @@ +class Box { + private T value; + + public void setValue(T value) { + this.value = value; + } +} + +class BoxOfInt extends Box { + private Integer value; + + @Override + public void setValue(Integer value) { + this.value = value; + } + +/* + After type parameter erasure, the overriden setValue() method in the superclass and here + would have different signatures: + + public void setValue(Object value) { this.value = value; } // in Box + public void setValue(Integer value) { this.value = value; } // in BoxOfInt + + To solve this, the compiler generates a synthetic method in BoxOfInt, called a "bridge method": + + public void setValue(Object value) { this.value = (Integer) value; } // in BoxOfInt + + Bridge methods are not visible in the source code but can be seen in the resulting bytecode. + Have a look disassembling it with javap -c BoxOfInt.class + */ + +} + +public class BridgeMethods { + + public static void main(String... args) { + Box boxOfInt = new BoxOfInt(); + boxOfInt.setValue(1); + } + +} diff --git a/05-generics/snippets/src/Container.java b/05-generics/snippets/src/Container.java new file mode 100644 index 00000000..9e8279aa --- /dev/null +++ b/05-generics/snippets/src/Container.java @@ -0,0 +1,11 @@ +public class Container { + + public static void main(String[] args) { + Container ci = new Container<>(); + Container cd = new Container<>(); + + // Container cs = new Container<>(); // will not compile + + } + +} diff --git a/05-generics/snippets/src/Fruit.java b/05-generics/snippets/src/Fruit.java new file mode 100644 index 00000000..073b2d58 --- /dev/null +++ b/05-generics/snippets/src/Fruit.java @@ -0,0 +1,6 @@ +final class Pineapple extends Fruit {} +final class Melon extends Fruit {} + +public sealed class Fruit permits Pineapple, Melon { + private T t; +} diff --git a/05-generics/snippets/src/GenericRecord.java b/05-generics/snippets/src/GenericRecord.java new file mode 100644 index 00000000..d718b9ef --- /dev/null +++ b/05-generics/snippets/src/GenericRecord.java @@ -0,0 +1,3 @@ +public record GenericRecord(K key, V value) { + +} diff --git a/05-generics/snippets/src/GenericsPlayground.java b/05-generics/snippets/src/GenericsPlayground.java new file mode 100644 index 00000000..0c566772 --- /dev/null +++ b/05-generics/snippets/src/GenericsPlayground.java @@ -0,0 +1,110 @@ +import java.util.ArrayList; +import java.util.List; + +class LivingThing { + +} + +class Human extends LivingThing { + private String name; + + public Human(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} + +class Student extends Human { + private int fn; + + public Student(String name, int fn) { + super(name); + this.fn = fn; + } + + @Override + public String toString() { + return "Student{" + + "fn=" + fn + + '}'; + } +} + +class FMIStudent extends Student { + public FMIStudent(String name, int fn) { + super(name, fn); + } + +} + +public class GenericsPlayground { + + // The Get & Put principle in action + + private static void getHumans(List listOfHumans) { + + // we can safely get, and we can rely on always getting a Human + for (Human h : listOfHumans) { // we can safely iterate as Human and call methods of Human + System.out.println(h.getName()); + } + + // we can only put null + listOfHumans.add(null); + + } + + private static void putHumans(List listOfSuperHumans) { + + // we can safely put instances of Human and successors of Human + listOfSuperHumans.add(new Student("Georgi Todorov", 62348)); + listOfSuperHumans.add(new Human("Anelia Angelova")); + listOfSuperHumans.add(new FMIStudent("Zahari Zvezdomirov", 62216)); + // listOfSuperHumans.add(new LivingThing()); // will not compile, why? + + // if we get, we can just rely on getting a java.lang.Object + Object o = listOfSuperHumans.get(0); + if (o instanceof Student) { + System.out.println(((Student) o).getName()); + } + System.out.println(o); + + } + + private static int neitherGetNorPut(List listOfUnknown) { + + // if we get, we can just rely on getting a java.lang.Object + Object o = listOfUnknown.get(0); + + // we can only put null + listOfUnknown.add(null); + // listOfUnknown.add("kuku"); // will not compile + + // we can use only methods that are agnostic to the type of elements + return listOfUnknown.size(); + + } + + public static void main(String[] args) { + + List listOfFMIStudents = new ArrayList<>(); + List listOfStudents = new ArrayList<>(); + List listOfHumans = new ArrayList<>(); + List listOfLivingThings = new ArrayList<>(); + List listOfObjects = new ArrayList<>(); + + getHumans(listOfHumans); + getHumans(listOfStudents); + getHumans(listOfFMIStudents); + + putHumans(listOfHumans); + putHumans(listOfLivingThings); + putHumans(listOfObjects); + + System.out.println(neitherGetNorPut(new ArrayList<>(List.of(1, 2, 3)))); // 4 + + } + +} diff --git a/05-generics/snippets/src/Pair.java b/05-generics/snippets/src/Pair.java new file mode 100644 index 00000000..ac7f9a80 --- /dev/null +++ b/05-generics/snippets/src/Pair.java @@ -0,0 +1,47 @@ +import java.util.List; +import java.util.Set; + +public class Pair { + + private K key; + private V value; + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public void setKey(K key) { + this.key = key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + @Override + public String toString() { + return "Pair{" + + "key=" + key + + ", value=" + value + + '}'; + } + + public static void main(String[] args) { + Pair pair1 = new Pair<>("Stoyo", 1); + Pair pair2 = new Pair<>("Boyo", 6); + + Pair pair3 = new Pair<>(1.0, 1.0); + + Pair, Set> pair4 = new Pair<>(List.of("FMI", "rulez"), Set.of(2024, 2025)); + } + +}