47Java for SDET
What you will master here
- OOP pillars with test-framework examples
- Overloading vs overriding; abstract class vs interface
- Access modifiers, final, static
- Collections: List/Set/Map, ArrayList vs LinkedList, HashMap internals
- Generics, exceptions (checked vs unchecked), try-with-resources
- Streams + lambdas — filter/map/collect on test data
- String immutability, equals/hashCode contract
- Threading basics; ThreadLocal for parallel WebDriver
47.1 Why Java for SDET
Java is the lingua franca of enterprise test automation. Selenium, REST Assured, TestNG/JUnit, Cucumber-JVM, Allure — all assume a JVM. Understanding the language well separates someone who copies WebDriver snippets from someone who designs maintainable frameworks.
47.2 The four OOP pillars
Encapsulation
public class LoginPage {
private final WebDriver driver;
private final By userField = By.id("user");
public LoginPage(WebDriver driver) { this.driver = driver; }
public DashboardPage login(String u, String p) {
driver.findElement(userField).sendKeys(u);
/* ... */
return new DashboardPage(driver);
}
}
Inheritance
public abstract class BasePage {
protected final WebDriver driver;
protected BasePage(WebDriver driver) { this.driver = driver; }
protected void waitVisible(By l) { /* shared */ }
}
public class LoginPage extends BasePage {
public LoginPage(WebDriver d) { super(d); }
}
Polymorphism — overloading vs overriding
Overloading (compile-time)
void click(By l) { ... }
void click(WebElement el) { ... }
void click(By l, int t) { ... }
- Same name, different parameters
- Resolved at compile time
Overriding (run-time)
class BaseTest { void setup() {} }
class ApiTest extends BaseTest {
@Override void setup() { /* replaces */ }
}
- Same signature, subclass replaces parent
- Resolved at run time (dynamic dispatch)
Abstraction — abstract class vs interface
| Aspect | Abstract class | Interface |
|---|---|---|
| Instantiable? | No | No |
| State (fields) | Yes | Constants only |
| Constructors | Yes | No |
| Multiple inheritance | One superclass | Implement many |
| Methods | Abstract + concrete | Abstract + default/static (Java 8+) |
47.3 Access modifiers
| Modifier | Same class | Same package | Subclass | Everywhere |
|---|---|---|---|---|
| public | ✓ | ✓ | ✓ | ✓ |
| protected | ✓ | ✓ | ✓ | — |
| default (package-private) | ✓ | ✓ | — | — |
| private | ✓ | — | — | — |
47.4 Collections
| Type | Backed by | Order | Duplicates | Best for |
|---|---|---|---|---|
| ArrayList | resizable array | insertion | Y | random access reads |
| LinkedList | doubly-linked nodes | insertion | Y | O(1) head/tail ops |
| HashSet | HashMap (keys) | none | N | fast membership |
| LinkedHashSet | linked HashMap | insertion | N | ordered uniqueness |
| TreeSet | Red-Black tree | sorted | N | sorted set |
| HashMap | buckets + chaining | none | N (keys) | O(1) key lookup |
| LinkedHashMap | + linked list | insertion | N (keys) | LRU caches |
| TreeMap | Red-Black tree | sorted | N (keys) | sorted map / range queries |
| ConcurrentHashMap | striped lock | none | N (keys) | thread-safe map |
HashMap internals (must know)
- Array of buckets; key's
hashCode()indexes into the array - Collisions chain as linked list; Java 8+ converts to tree when bucket length > 8 (TREEIFY_THRESHOLD)
- Load factor 0.75 — when size exceeds capacity×0.75, capacity doubles and rehash happens
equals()+hashCode()contract: equal objects MUST have equal hash codes
47.5 Generics
public class Stack<T> {
private final List<T> data = new ArrayList<>();
public void push(T x) { data.add(x); }
public T pop() { return data.remove(data.size() - 1); }
}
// Bounded
public <T extends Comparable<T>> T max(List<T> xs) {
return xs.stream().max(Comparable::compareTo).orElseThrow();
}
// Wildcards
List<? extends Number> numbers; // read-only (covariant)
List<? super Integer> integers; // write-only (contravariant)
47.6 Exceptions
| Type | When | Must catch? |
|---|---|---|
| Checked (Exception, IOException, SQLException) | Recoverable conditions | Yes — declare or catch |
| Unchecked (RuntimeException, NullPointerException) | Programming errors | No — but should fix |
| Error (OutOfMemoryError, StackOverflowError) | JVM-level fatal | Don't catch |
// try-with-resources — auto-closes
try (Connection c = DriverManager.getConnection(url);
PreparedStatement ps = c.prepareStatement(sql)) {
/* use */
} catch (SQLException e) {
throw new RuntimeException("DB failed", e);
}
47.7 Streams + lambdas
List<User> admins = users.stream()
.filter(u -> u.role().equals("admin"))
.sorted(Comparator.comparing(User::createdAt))
.collect(Collectors.toList());
// Group by
Map<String, List<User>> byRole = users.stream()
.collect(Collectors.groupingBy(User::role));
// Reduce
int total = orders.stream().mapToInt(Order::total).sum();
// Parallel — be careful
long count = bigList.parallelStream().filter(predicate).count();
47.8 String immutability + equals/hashCode
String a = "hello";
String b = "hello";
a == b; // true — string pool
a.equals(b); // true — value comparison
new String("hello") == "hello"; // false — different object
// Always use .equals() for content comparison
"alice".equals(user.name());
// equals/hashCode contract for custom classes
@Override public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User u)) return false;
return Objects.equals(email, u.email);
}
@Override public int hashCode() { return Objects.hash(email); }
47.9 Threading + ThreadLocal for WebDriver
// Each thread gets its own WebDriver instance — required for parallel TestNG
public class DriverFactory {
private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
public static void set(WebDriver d) { driver.set(d); }
public static WebDriver get() { return driver.get(); }
public static void remove() {
WebDriver d = driver.get();
if (d != null) d.quit();
driver.remove();
}
}
Module 44 — Java Q&A
Difference between overloading and overriding?
Overloading: same method name, different parameters, resolved at compile time (static dispatch). Overriding: subclass replaces parent's method with same signature, resolved at run time (dynamic dispatch).
Abstract class vs interface?
Abstract class can have state (fields), constructors, and a mix of abstract + concrete methods; single inheritance. Interface defines a contract — constants + abstract methods (+ default/static since Java 8); a class can implement many. Use abstract for shared state, interface for capability contracts.
ArrayList vs LinkedList?
ArrayList — backed by resizable array; O(1) get by index, O(n) insert in middle. LinkedList — doubly-linked nodes; O(1) head/tail ops, O(n) get by index. For most SDET use cases ArrayList wins (better cache locality).
How does HashMap work?
Array of buckets; key's hashCode picks the bucket. Collisions chain as a list, converted to a tree if length > 8 (Java 8+). Load factor 0.75 triggers rehash. equals + hashCode contract: equal objects must have equal hash codes; unequal can have same hash (collision).
Checked vs unchecked exceptions?
Checked extend Exception (not RuntimeException) — compiler forces declaration or catch (IOException, SQLException). Unchecked extend RuntimeException — represent programming errors; no compiler check. Use checked for recoverable, unchecked for bugs/preconditions.
What is try-with-resources?
Syntax that auto-closes anything implementing
AutoCloseable when the block exits (normally or via exception). Replaces verbose finally blocks for closing files, connections, streams.Why is String immutable?
Thread-safety, hash-code caching, string interning (pool reuses identical literals), and security (can't change a String passed to a sensitive API after the check). Use StringBuilder for mutable strings.
equals/hashCode contract?
If
a.equals(b) then a.hashCode() == b.hashCode() MUST be true. Reverse not required (collisions exist). Break the contract and HashMap/HashSet behave incorrectly for your type.What's ThreadLocal and why does Selenium need it?
Storage that holds a value per thread — calls from thread A see only A's value. Selenium WebDriver is not thread-safe; for parallel TestNG runs, each thread must hold its own driver. ThreadLocal<WebDriver> is the canonical pattern.
What does final mean on a class/method/variable?
final class — can't be subclassed. final method — can't be overridden. final variable — can be assigned only once (reference; object contents may still mutate). Constants are
public static final.What's the difference between == and .equals() for objects?
== compares object references (same instance). .equals() compares logical equality if overridden. Always use .equals() for content. String literals share the pool so == may accidentally seem to work — don't rely on it.
What's a Stream and how is it different from a Collection?
A Collection holds data. A Stream is a pipeline of operations on data — lazy until a terminal operation runs. Streams support functional operations (filter, map, reduce) and can be parallel. Consumed once; not re-iterable.
When would you use ConcurrentHashMap over HashMap?
When multiple threads read/write the same map concurrently. ConcurrentHashMap uses lock striping for high throughput; HashMap is not thread-safe and corrupts on concurrent writes.
Collections.synchronizedMap exists but is slower (single global lock).What are generics for?
Type-safety at compile time without code duplication.
List<User> guarantees only User can be added. Erasure means generics disappear at runtime — but the compiler catches type errors that would have been runtime ClassCastException.