Interview prep · 227 questions

Java interview questions for QA and SDET

Updated

Java the way testers and SDETs actually meet it — OOP for framework design, collections for test data, the == vs .equals() trap, exceptions and POJOs — each with the short answer to say out loud, the follow-up, and the mistake to avoid. Not a generic Java crammer; Java through a testing lens. Skim the previews; open what you need.

16 questions

What are the four pillars of OOP, and where do they show up in a test framework?

Java OOPjuniormid

Encapsulation (bundle data with the methods that guard it), inheritance (a type reuses another's behaviour), polymorphism (one interface, many implementations), abstraction (expose what, hide how).

Encapsulation (bundle data with the methods that guard it), inheritance (a type reuses another's behaviour), polymorphism (one interface, many implementations), abstraction (expose what, hide how).

The interview edge is naming where each lives in automation: a Page Object encapsulates its locators; a BasePage others inherit; a driver interface with Chrome/Firefox implementations is polymorphism; and an abstraction like LoginPage.login() hiding the clicks. Reciting definitions is junior; mapping them to a framework is the SDET answer.

Key points
  • Encapsulation, Inheritance, Polymorphism, Abstraction
  • Page Object = encapsulation; BasePage = inheritance
  • Driver interface with browser impls = polymorphism
They'll ask next · tap one for the answer
The trap

Just listing the four words is a junior answer. Interviewers wait for a concrete example of each — ideally from test code, since that's the job.

Copy link

What's the difference between == and .equals() in Java?

Java Essentialsjuniormid

== compares references — are these two variables the exact same object in memory. .equals() compares value — do these two objects mean the same thing, per the class's definition.

== compares references — are these two variables the exact same object in memory. .equals() compares value — do these two objects mean the same thing, per the class's definition.

For objects, == is almost never what you want. Two strings with identical text can be different objects, so "abc" == new String("abc") is false while .equals() is true. This is the single most common Java bug in test assertions — comparing expected and actual with == and getting a false failure.

Real-world example

A test compared an API's returned status string to "ACTIVE" with == and flaked randomly — sometimes the strings were interned, sometimes not. Switching to .equals() (or better, an assertion library) fixed it permanently.

Key points
  • == compares references (same object?); .equals() compares value
  • For objects/strings you almost always want .equals()
  • == on strings is the classic false-failure in test assertions
They'll ask next · tap one for the answer
Copy link

Overloading versus overriding — what's the difference?

Java OOPmid

Overloading is same method name, different parameters, in the same class — resolved at compile time by the arguments you pass.

Overloading is same method name, different parameters, in the same class — resolved at compile time by the arguments you pass. Overriding is a subclass replacing a parent's method with the same signature — resolved at run time by the actual object type.

In a framework: a click(WebElement) and click(By) are overloads; a BasePage method a specific page overrides is overriding. The tell interviewers listen for is 'compile-time vs run-time' — that's what proves you understand the mechanism, not just the words.

Key points
  • Overload: same name, different params, same class, compile-time
  • Override: subclass replaces parent method, same signature, run-time
  • Overloading is polymorphism at compile time; overriding at run time
They'll ask next · tap one for the answer
Copy link

Abstract class or interface — when would you use each?

Java OOPmid

An interface is a contract — a set of methods a type promises to provide; a class can implement many. An abstract class is a partial base — it can hold shared state and implemented methods, and a…

An interface is a contract — a set of methods a type promises to provide; a class can implement many. An abstract class is a partial base — it can hold shared state and implemented methods, and a class extends only one.

Rule of thumb: interface for 'can do this' capabilities across unrelated types (a Payable, a Reportable); abstract class for 'is a kind of' with shared code, like a BasePage all pages extend for the common driver and waits. Since Java 8 interfaces can have default methods, so the line blurred — but single vs multiple inheritance and shared state still decide it.

Key points
  • Interface: contract, multiple per class, capability-based
  • Abstract class: partial base with shared state/code, single inheritance
  • BasePage = abstract class; a cross-cutting capability = interface
They'll ask next · tap one for the answer
Copy link

Why does encapsulation matter in a Page Object?

Java OOPmid

Encapsulation means the Page Object owns its locators privately and exposes only intent-level methods — login(user, pass), not the raw fields. Tests call the behaviour and never touch a selector.

Encapsulation means the Page Object owns its locators privately and exposes only intent-level methods — login(user, pass), not the raw fields. Tests call the behaviour and never touch a selector.

That's the whole payoff: when the login form's markup changes, you edit one private locator in one class, and every test that logs in keeps working untouched. Expose the locators publicly and they leak into tests, and a UI tweak becomes a fifty-file change. Encapsulation is what makes a UI framework survivable.

Key points
  • Locators private, intent-level methods public
  • A UI change touches one class, not every test
  • Leaked locators = a redesign becomes a mass edit
They'll ask next · tap one for the answer
Copy link

Why are Java strings immutable, and when do you use StringBuilder?

Java Essentialsmid

A String can't be changed after creation — every 'modification' makes a new object. That gives safety (strings can be shared and cached, keys in maps stay stable) but means building a string in a…

A String can't be changed after creation — every 'modification' makes a new object. That gives safety (strings can be shared and cached, keys in maps stay stable) but means building a string in a loop with + creates a pile of throwaway objects.

Use StringBuilder when you're assembling a string piece by piece — concatenating in a loop, building a dynamic locator or a report line. For a handful of concatenations it doesn't matter; in a loop it's the difference between one object and hundreds.

Key points
  • Strings are immutable — every change makes a new object
  • Immutability buys safety and safe map keys
  • StringBuilder for building strings in a loop
They'll ask next · tap one for the answer
Copy link

List, Set, Map — what's the difference and when do you reach for each?

Collectionsjunior

A List is an ordered sequence that allows duplicates — use it when order matters or items can repeat (a list of test rows).

A List is an ordered sequence that allows duplicates — use it when order matters or items can repeat (a list of test rows). A Set holds unique elements, no duplicates — use it to dedupe or check membership (the set of visible product IDs). A Map is key-value pairs — use it for lookups (a map of username to expected role).

The question behind the question in automation: 'I scraped these values, are they all unique?' is a Set; 'what's the price for this SKU?' is a Map; 'the rows in order' is a List.

Key points
  • List: ordered, duplicates allowed
  • Set: unique elements, membership/dedupe
  • Map: key-value lookups
They'll ask next · tap one for the answer
Copy link

ArrayList versus LinkedList — how do you choose?

Collectionsmid

ArrayList is backed by a resizable array — fast random access by index, slower inserts/removals in the middle (it shifts elements).

ArrayList is backed by a resizable array — fast random access by index, slower inserts/removals in the middle (it shifts elements). LinkedList is nodes with pointers — fast inserts/removals at the ends, but slow index access because it walks the chain.

Honest answer for test code: use ArrayList almost always. You mostly iterate and index into collections of test data, which ArrayList does best, and the constant factors favour it. LinkedList earns its place only with heavy add/remove at the front — rare in a test suite.

Key points
  • ArrayList: array-backed, fast random access, slow middle inserts
  • LinkedList: node-based, fast end inserts, slow index access
  • Default to ArrayList for test data — you mostly iterate and index
They'll ask next · tap one for the answer
Copy link

How does a HashMap work under the hood?

Collectionsmidsenior

It stores entries in buckets indexed by the key's hashCode. Put: hash the key to find a bucket, and store the key-value there.

It stores entries in buckets indexed by the key's hashCode. Put: hash the key to find a bucket, and store the key-value there. Get: hash the key, go straight to the bucket, and use equals() to find the exact entry. That's why lookups are roughly O(1).

Two keys can hash to the same bucket — a collision — so a bucket holds multiple entries (a list, or a tree when it gets long). This is why a key's hashCode and equals must agree: break that contract and a key you stored becomes unfindable, landing in one bucket and searched for in another.

Key points
  • Keys hashed to buckets; get/put are ~O(1)
  • Collisions share a bucket (list/tree of entries)
  • hashCode + equals must agree or keys go missing
They'll ask next · tap one for the answer
Copy link

Checked versus unchecked exceptions — what's the difference?

Java Essentialsmid

Checked exceptions (IOException, InterruptedException) must be declared or caught — the compiler forces you to handle them.

Checked exceptions (IOException, InterruptedException) must be declared or caught — the compiler forces you to handle them. Unchecked exceptions (NullPointerException, IllegalArgumentException) extend RuntimeException and don't have to be caught; they signal bugs.

In Selenium you meet both: NoSuchElementException is unchecked (a bug or a bad wait), while InterruptedException from Thread.sleep is checked and must be handled. The design intent: checked for recoverable external conditions, unchecked for programming errors you should fix rather than catch.

Key points
  • Checked: compiler forces handling (IOException)
  • Unchecked: RuntimeException family, optional (NullPointer)
  • Checked = recoverable external; unchecked = a bug to fix
They'll ask next · tap one for the answer
Copy link

What is try-with-resources and why prefer it?

Java Essentialsmid

A try that declares a resource in parentheses — try (var reader = new FileReader(f)) { ... } — and closes it automatically when the block ends, success or exception.

A try that declares a resource in parentheses — try (var reader = new FileReader(f)) { ... } — and closes it automatically when the block ends, success or exception. The resource just has to implement AutoCloseable.

It replaces the error-prone finally block where people forget to close, or close in the wrong order, or leak on an exception path. In test code it's how you handle files, DB connections and readers cleanly — no dangling handles that slowly exhaust a shared environment.

Key points
  • Declares a resource that auto-closes at block end
  • Works on any AutoCloseable, closes even on exception
  • Replaces forgettable finally-block cleanup
They'll ask next · tap one for the answer
Copy link

What does the static keyword mean, and when do you use it in test code?

Java Essentialsmid

static belongs to the class, not an instance — one copy shared by all. A static method is called on the class (Utils.formatDate()), a static field is shared state, and a static block runs once when…

static belongs to the class, not an instance — one copy shared by all. A static method is called on the class (Utils.formatDate()), a static field is shared state, and a static block runs once when the class loads.

In frameworks: utility methods that don't need object state are static; constants are static final; a shared WebDriver in a base class is sometimes static (though that causes trouble in parallel runs). The caution worth voicing: static mutable state is a classic parallel-test bug — two tests sharing one static driver clobber each other.

Key points
  • Belongs to the class, one shared copy
  • Static methods for stateless utilities; static final for constants
  • Static mutable state (a shared driver) breaks parallel tests
They'll ask next · tap one for the answer
The trap

Reaching for static everywhere is a smell. Static mutable state is exactly what makes a suite unsafe to parallelise — name that awareness, don't just define the keyword.

Copy link

What's a POJO, and why does it matter in test automation?

Java for Automationmid

A POJO — Plain Old Java Object — is a simple class with fields, getters and setters and no framework baggage.

A POJO — Plain Old Java Object — is a simple class with fields, getters and setters and no framework baggage. In automation it's how you model data: a User POJO, an Order POJO, a request or response body.

It matters most in API testing. Instead of digging through raw JSON with string keys, you deserialise the response into a typed POJO and assert on order.getTotal() — compile-time safe, refactorable, readable. Serialising a POJO to build a request body beats hand-writing JSON strings that break silently.

Key points
  • Plain class: fields + getters/setters, no framework ties
  • Models data — User, Order, request/response bodies
  • Typed API testing: deserialise JSON into a POJO, assert on fields
They'll ask next · tap one for the answer
Copy link

Which collections do you actually use in a real Selenium framework?

Java for Automationsenior

List<WebElement> for grabbing many elements — every row, every link — then iterating. Map for lookups like test data keyed by name, or expected values by field.

List<WebElement> for grabbing many elements — every row, every link — then iterating. Map for lookups like test data keyed by name, or expected values by field. Set to assert uniqueness — collect visible IDs and prove no duplicates.

The senior detail is knowing why: findElements returns a List; you convert to a Set when you're deduping; you use a Map to drive data-driven checks. It's not about memorising the API, it's showing you pick the structure that matches the question the test is asking.

Key points
  • List<WebElement> from findElements — iterate rows/links
  • Map for test-data lookups and expected values
  • Set to assert uniqueness / dedupe scraped values
They'll ask next · tap one for the answer
Copy link

Would you use Java streams in test code?

Java for Automationsenior

Yes, where they make an assertion clearer. Streams shine for filtering and transforming collections you scraped: prices.stream().allMatch(p -> p > 0), or mapping WebElements to their text and…

Yes, where they make an assertion clearer. Streams shine for filtering and transforming collections you scraped: prices.stream().allMatch(p -> p > 0), or mapping WebElements to their text and collecting into a List to compare against expected.

The judgement is not overusing them. A short stream that reads like the assertion is great; a nested five-operation stream nobody can debug is worse than a plain loop. In a test, readability wins — the next person needs to see what's being checked at a glance.

Key points
  • Great for filter/map/match over scraped collections
  • map WebElements to text, allMatch/anyMatch for assertions
  • Keep them short and readable — a loop beats an unreadable stream
They'll ask next · tap one for the answer
Copy link

What does the final keyword do?

Java Essentialsmid

final means 'can't change after it's set'. A final variable can be assigned once (a constant), a final method can't be overridden, and a final class can't be extended.

final means 'can't change after it's set'. A final variable can be assigned once (a constant), a final method can't be overridden, and a final class can't be extended.

In practice: final for constants (base URLs, timeouts as static final), and to lock a field a class shouldn't reassign. It signals intent — 'this doesn't change' — which both the compiler and the next reader rely on. Overusing it on every local variable is noise, but on constants and key fields it documents guarantees.

Key points
  • final variable = assign once; method = no override; class = no extend
  • Use for constants (static final) and locked fields
  • Signals 'this doesn't change' to compiler and reader
They'll ask next · tap one for the answer
Copy link
They'll ask next