Skip to content

Commit

Permalink
Add Generics code snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
100yo committed Nov 8, 2024
1 parent 1ecf726 commit 9b890f3
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 0 deletions.
1 change: 1 addition & 0 deletions 05-generics/snippets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Generics / Code snippets
41 changes: 41 additions & 0 deletions 05-generics/snippets/src/BridgeMethods.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class Box<T> {
private T value;

public void setValue(T value) {
this.value = value;
}
}

class BoxOfInt extends Box<Integer> {
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<Integer> boxOfInt = new BoxOfInt();
boxOfInt.setValue(1);
}

}
11 changes: 11 additions & 0 deletions 05-generics/snippets/src/Container.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
public class Container<T extends Number> {

public static void main(String[] args) {
Container<Integer> ci = new Container<>();
Container<Double> cd = new Container<>();

// Container<String> cs = new Container<>(); // will not compile

}

}
6 changes: 6 additions & 0 deletions 05-generics/snippets/src/Fruit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
final class Pineapple extends Fruit {}
final class Melon extends Fruit {}

public sealed class Fruit<T> permits Pineapple, Melon {
private T t;
}
3 changes: 3 additions & 0 deletions 05-generics/snippets/src/GenericRecord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public record GenericRecord<K, V>(K key, V value) {

}
110 changes: 110 additions & 0 deletions 05-generics/snippets/src/GenericsPlayground.java
Original file line number Diff line number Diff line change
@@ -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<? extends Human> 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<? super Human> 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<FMIStudent> listOfFMIStudents = new ArrayList<>();
List<Student> listOfStudents = new ArrayList<>();
List<Human> listOfHumans = new ArrayList<>();
List<LivingThing> listOfLivingThings = new ArrayList<>();
List<Object> 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

}

}
47 changes: 47 additions & 0 deletions 05-generics/snippets/src/Pair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import java.util.List;
import java.util.Set;

public class Pair<K, V> {

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<String, Integer> pair1 = new Pair<>("Stoyo", 1);
Pair<String, Integer> pair2 = new Pair<>("Boyo", 6);

Pair<Double, Double> pair3 = new Pair<>(1.0, 1.0);

Pair<List<String>, Set<Integer>> pair4 = new Pair<>(List.of("FMI", "rulez"), Set.of(2024, 2025));
}

}

0 comments on commit 9b890f3

Please sign in to comment.