// Generic Box usage
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
String value = stringBox.getValue(); // No casting needed

Box<Integer> intBox = new Box<>();
intBox.setValue(42);

// Bounded type usage
NumberBox<Integer> intNumberBox = new NumberBox<>();
NumberBox<Double> doubleNumberBox = new NumberBox<>();
// NumberBox<String> stringBox = new NumberBox<>(); // Compile error!

// Pair usage
Pair<String, Integer> pair = new Pair<>("age", 25);
String key = pair.getKey();
Integer val = pair.getValue();

// Generic collections
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
String first = names.get(0); // Type-safe

Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 30);
ages.put("Bob", 25);
Integer aliceAge = ages.get("Alice"); // Type-safe

// Wildcard usage
List<Integer> ints = Arrays.asList(1, 2, 3);
Utils.printList(ints);

List<String> strings = Arrays.asList("a", "b");
Utils.printList(strings);

// Upper bounded
List<Integer> integers = Arrays.asList(1, 2, 3);
double sum1 = Utils.sum(integers);

List<Double> doubles = Arrays.asList(1.5, 2.5);
double sum2 = Utils.sum(doubles);