From 5c4668228da5bffb9649f8fef208d66297f168c2 Mon Sep 17 00:00:00 2001 From: Desislava Asenova <9128192+desislavaa@users.noreply.github.com> Date: Fri, 10 Nov 2023 23:54:11 +0200 Subject: [PATCH] [05-generics] Add Code Snippets (#126) * Add Generics code snippets --- .../snippets/src/BridgeMethodsExample.java | 85 ++++++++++++++ 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 ++++++++ 6 files changed, 262 insertions(+) create mode 100644 05-generics/snippets/src/BridgeMethodsExample.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/src/BridgeMethodsExample.java b/05-generics/snippets/src/BridgeMethodsExample.java new file mode 100644 index 00000000..25d258da --- /dev/null +++ b/05-generics/snippets/src/BridgeMethodsExample.java @@ -0,0 +1,85 @@ +import java.util.HashMap; +import java.util.Map; + +// Base class Entity +abstract class Entity { + private final long id; + + public Entity(long id) { + this.id = id; + } + + public long getId() { + return id; + } +} + +// Generic Storage class for Entity +class EntityStorage { + private Map entities; + + public EntityStorage() { + this.entities = new HashMap<>(); + } + + public T getEntity(long id) { + return entities.get(id); + } + + public void addEntity(T entity) { + this.entities.put(entity.getId(), entity); + } +} + +// Specialized Storage class for Employee +class Employee extends Entity { + private String name; + + public Employee(long id, String name) { + super(id); + this.name = name; + } + + public String getName() { + return name; + } +} + +// Specialized Storage class for EmployeeStorage with bridge method +class EmployeeStorage extends EntityStorage { + public EmployeeStorage() { + super(); + } + + // Additional methods specific to EmployeeStorage + public String getEmployeeName(long id) { + return getEntity(id).getName(); + } + + // Due to type erasure, the getEntity method in the EmployeeStorage class has an erased signature. + // The compiler generates a bridge method in the EmployeeStorage class to ensure that the + // overridden method in the EntityStorage interface adheres to the erasure rules. + // + // Bridge methods are synthetic methods added by the compiler to maintain polymorphism + // and type safety in the presence of type erasure. They are not directly written + // in the source code but are introduced during the compilation process. + @Override + public Employee getEntity(long id) { + return super.getEntity(id); + } +} + +public class BridgeMethodsExample { + public static void main(String[] args) { + Employee employee = new Employee(1, "John Doe"); + + EmployeeStorage employeeStorage = new EmployeeStorage(); + + // Access specific method + System.out.println("Employee Name: " + employeeStorage.getEmployeeName(1)); + + // Access generic method through the bridge + Entity genericEntity = employeeStorage.getEntity(1); + System.out.println("Generic Entity ID: " + genericEntity.getId()); + } +} 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..88efe787 --- /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(2022, 2023)); + } + +}