Answer
Java Generics
Generics allow you to write type-safe code that works with different data types while providing compile-time type checking.
Why Generics?
Java
// WITHOUT generics — unsafe, requires casting
List list = new ArrayList();
list.add("Hello");
list.add(42); // no type check!
String s = (String) list.get(1); // ClassCastException at runtime!
// WITH generics — type-safe
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
// stringList.add(42); // ❌ Compile error — caught at compile time!
String s = stringList.get(0); // no cast needed
Generic Class
Java
public class Box<T> {
private T content;
public void put(T item) { this.content = item; }
public T get() { return content; }
}
Box<String> stringBox = new Box<>();
stringBox.put("Hello");
String s = stringBox.get(); // no cast
Box<Integer> intBox = new Box<>();
intBox.put(42);
Integer n = intBox.get();
Generic Method
Java
public class ArrayUtils {
// Works with ANY type
public static <T> void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
}
Integer[] nums = {1, 2, 3};
ArrayUtils.swap(nums, 0, 2); // [3, 2, 1]
System.out.println(ArrayUtils.max(10, 20)); // 20
System.out.println(ArrayUtils.max("Apple", "Banana")); // Banana
Bounded Type Parameters
Java
// <T extends Number> — T must be Number or subclass (Integer, Double, Float)
public static <T extends Number> double sum(List<T> list) {
return list.stream().mapToDouble(Number::doubleValue).sum();
}
List<Integer> ints = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);
System.out.println(sum(ints)); // 6.0
System.out.println(sum(doubles)); // 7.5
Wildcards
Java
// ? — unknown type
// ? extends T — upper bound (T or subclass)
// ? super T — lower bound (T or superclass)
// Read-only — accepts List<Integer>, List<Double>, List<Number>
public static double sumList(List<? extends Number> list) {
return list.stream().mapToDouble(Number::doubleValue).sum();
}
// Write — accepts List<Integer> or List<Number> or List<Object>
public static void addNumbers(List<? super Integer> list) {
list.add(1);
list.add(2);
}
Common Generic Collections
Java
// All Collections use generics
List<String> names = new ArrayList<>();
Map<String, Integer> scores = new HashMap<>();
Set<Long> ids = new HashSet<>();
Queue<Runnable> tasks = new LinkedList<>();
Optional<WebDriver> driver = Optional.empty();
In Automation Frameworks
Java
// Generic utility to wait for any element type
public static <T extends WebElement> T waitForElement(
WebDriverWait wait, ExpectedCondition<T> condition) {
return wait.until(condition);
}
// Generic page factory method
public static <T extends BasePage> T initPage(WebDriver driver, Class<T> pageClass) {
try {
return pageClass.getConstructor(WebDriver.class).newInstance(driver);
} catch (Exception e) {
throw new RuntimeException("Failed to init page: " + pageClass.getName(), e);
}
}
// Usage
LoginPage loginPage = initPage(driver, LoginPage.class);
