| Abstract Class | A class declared with abstract keyword; cannot be instantiated; may have abstract and concrete methods |
| Interface | A pure contract type; supports default, static, private methods (Java 8/9+); all fields are public static final |
| Functional Interface | An interface with exactly one abstract method (SAM); used as lambda targets; annotated with @FunctionalInterface |
| Marker Interface | An interface with no methods (e.g., Serializable, Cloneable, Remote); signals capability to JVM/framework |
| Default Method | A method in an interface with a body, introduced in Java 8; allows backward-compatible API evolution |
| Sealed Interface | Introduced in Java 17; restricts which classes/interfaces can implement it using permits |
| Diamond Problem | Ambiguity when two interfaces provide same default method; resolved by overriding in implementing class |
| Interface Segregation | SOLID principle: clients should not be forced to depend on methods they do not use; prefer narrow interfaces |
| Comparable | Interface for natural ordering; implemented by the class itself; compareTo() method |
| Comparator | External ordering strategy; functional interface; compare() method; allows multiple sort orders |
constructors, state, partial impl
pure contract, no state
default + static methods
private methods added
1 abstract method (SAM)
zero methods
Java 17, permits clause
Java Abstraction & Interfaces Interview Questions & Answers
Q1. What is abstraction in Java and why is it important?
A: Abstraction is an OOP principle that hides implementation details and exposes only the essential features of an object to the outside world. In Java, abstraction is achieved through abstract classes and interfaces. It is important because it reduces complexity, promotes loose coupling, enables polymorphism, and allows you to define contracts that multiple classes can fulfill independently. For example, a Shape abstract class exposes area() without dictating how each shape computes it.
Q2. What is an abstract class in Java?
A: An abstract class is a class declared with the abstract keyword that cannot be instantiated directly. It can contain both abstract methods (without a body) and concrete methods (with a body), instance variables, constructors, and static members. It is used when you want to provide a partial implementation and force subclasses to complete the rest.
abstract class Animal {
private String name;
public Animal(String name) { // constructor allowed
this.name = name;
}
public String getName() { return name; } // concrete method
public abstract void makeSound(); // abstract method
}
class Dog extends Animal {
public Dog(String name) { super(name); }
@Override
public void makeSound() {
System.out.println(getName() + " says: Woof!");
}
}
Q3. What is an interface in Java?
A: An interface is a reference type in Java that defines a contract — a set of method signatures that implementing classes must provide. Before Java 8, interfaces could only have public abstract methods and public static final constants. From Java 8 onward, interfaces can also have default and static methods. From Java 9 onward, private methods are allowed. An interface is declared with the interface keyword and implemented using implements.
Q4. What is the full comparison between abstract class and interface?
A: The table below covers all key differences:
| Aspect | Abstract Class | Interface |
|---|---|---|
| Keyword | abstract class | interface |
| Instantiation | Cannot be instantiated | Cannot be instantiated |
| Inheritance | Single inheritance only (extends) | Multiple interfaces via implements |
| Constructor | Yes, can have constructors | No constructors |
| Fields | Any access modifier, instance/static | Only public static final constants |
| Method types | Abstract + concrete, any access | Abstract, default, static, private (Java 9) |
| Access modifiers | Any modifier on members | Methods implicitly public (except private) |
| State | Can maintain state via instance fields | No instance state |
| Use case | "Is-a" relationship with shared state/behavior | "Can-do" capability / pure contract |
| Speed (historical) | Slightly faster (direct vtable) | Negligible difference in modern JVM |
Q5. What are the rules for abstract methods in Java?
A: Rules for abstract methods: (1) An abstract method has no body — it ends with a semicolon. (2) It must be declared inside an abstract class or interface. (3) It cannot be private (subclass couldn't override it). (4) It cannot be static (static methods are not overridable). (5) It cannot be final (final prevents overriding). (6) Any concrete subclass must provide an implementation, or it must also be declared abstract. (7) The overriding method must have a compatible return type (covariant return types are allowed).
Q6. Can an abstract class have a constructor? Why?
A: Yes. An abstract class can and often should have a constructor. Even though you cannot instantiate an abstract class directly, its constructor is called when a concrete subclass is instantiated via super(). The constructor is used to initialize fields defined in the abstract class. This ensures that common state is set up correctly regardless of which subclass is created. If no constructor is declared, the compiler inserts a default no-arg constructor.
abstract class Vehicle {
private final String brand;
private final int year;
// abstract class constructor — called by subclass via super()
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
public String getBrand() { return brand; }
public int getYear() { return year; }
public abstract double fuelEfficiency();
}
class ElectricCar extends Vehicle {
private final double rangeKm;
public ElectricCar(String brand, int year, double rangeKm) {
super(brand, year); // calls abstract class constructor
this.rangeKm = rangeKm;
}
@Override
public double fuelEfficiency() { return rangeKm; }
}
Q7. What are default methods in Java interfaces (Java 8)?
A: Default methods are interface methods declared with the default keyword that provide a concrete implementation. Introduced in Java 8, they allow existing interfaces to gain new methods without breaking all implementing classes. They are inherited by implementing classes, which can override them if needed. They are not abstract and always public. They allow interfaces to evolve without breaking backward compatibility.
interface Greeter {
String greet(String name); // abstract method
default String greetLoudly(String name) { // default method (Java 8)
return greet(name).toUpperCase();
}
}
class FormalGreeter implements Greeter {
@Override
public String greet(String name) {
return "Good day, " + name;
}
// greetLoudly() is inherited automatically
}
public class Main {
public static void main(String[] args) {
Greeter g = new FormalGreeter();
System.out.println(g.greetLoudly("Alice"));
// Output: GOOD DAY, ALICE
}
}
Q8. What are static methods in interfaces (Java 8)?
A: Interfaces can declare static methods from Java 8 onward. These are utility/helper methods belonging to the interface type itself, not to any instance or implementing class. They are called using the interface name (e.g., MyInterface.staticMethod()). Implementing classes do not inherit interface static methods, and they cannot be overridden. They are typically used to provide factory or utility logic closely tied to the interface's contract.
Q9. What are private methods in interfaces (Java 9)?
A: Java 9 added private instance and private static methods to interfaces. They are used to share common code between multiple default or static methods within the same interface, avoiding code duplication. Private methods are not visible to implementing classes or subinterfaces — they are purely an internal implementation detail of the interface. This makes interfaces cleaner and avoids polluting the public API with helper methods.
Q10. What is a functional interface?
A: A functional interface is an interface that has exactly one abstract method (SAM — Single Abstract Method). It can have any number of default, static, and private methods. Functional interfaces are the target type for lambda expressions and method references in Java 8+. Examples from the standard library include Runnable, Callable, Comparator, Predicate, Function, Consumer, and Supplier.
Q11. What is the @FunctionalInterface annotation?
A: @FunctionalInterface is an optional but strongly recommended annotation placed on an interface to signal that it is intended to be a functional interface. The compiler enforces that the annotated interface has exactly one abstract method — if you accidentally add a second abstract method, the compiler produces an error. It serves as documentation and a compile-time safety check. The annotation itself does not change runtime behavior; any interface with one abstract method is a functional interface regardless of the annotation.
Q12. What are SAM interfaces?
A: SAM stands for Single Abstract Method. A SAM interface (also called a functional interface) is any interface with exactly one abstract method. The term "SAM" predates Java 8 and was used in the context of anonymous inner classes. With Java 8, SAM interfaces became the foundation for lambda expressions — a lambda expression is syntactic sugar for an anonymous implementation of the SAM. The compiler infers which abstract method the lambda implements based on the target type context.
Q13. What are marker interfaces in Java?
A: A marker interface is an interface with no methods and no constants — it is empty. Its sole purpose is to tag or mark a class as having a certain property or capability that the JVM, serialization framework, or another component can detect via instanceof checks. Common examples: java.io.Serializable (marks objects that can be serialized), java.lang.Cloneable (marks objects that can be cloned via Object.clone()), and java.rmi.Remote (marks remote objects for RMI). Modern alternatives to marker interfaces include annotations (e.g., @Deprecated).
Q14. Explain interface constants (public static final fields).
A: Any field declared in an interface is implicitly public static final, meaning it is a constant. Even if you omit these modifiers, the compiler adds them. This means interface fields must be initialized at declaration time, cannot be instance variables, and cannot be changed after assignment. Using interfaces purely to hold constants (the "Constant Interface" anti-pattern) is discouraged; use a final class with a private constructor or an enum instead.
Q15. Can a class implement multiple interfaces?
A: Yes. Java allows a class to implement multiple interfaces using a comma-separated list: class MyClass implements InterfaceA, InterfaceB, InterfaceC. This is the main mechanism Java uses to simulate multiple inheritance of type. The class must provide implementations for all abstract methods from all interfaces (or be declared abstract itself). If two interfaces provide conflicting default methods, the implementing class must override the method to resolve the ambiguity.
Q16. Can an interface extend another interface?
A: Yes. An interface can extend one or more other interfaces using the extends keyword (not implements). This creates an interface inheritance hierarchy. The child interface inherits all abstract, default, and static methods of the parent(s), and can add new methods or override default methods. A class implementing the child interface must implement all methods from the entire hierarchy. Example: interface C extends A, B { }.
Q17. When should you use an abstract class vs an interface?
A: Use an abstract class when: (1) you want to share code (concrete methods) among closely related classes; (2) subclasses need access to instance state (non-final, non-static fields); (3) you need constructors to enforce initialization; (4) the relationship is "is-a" and the hierarchy is tightly coupled. Use an interface when: (1) you want to define a pure contract that unrelated classes can implement; (2) you need to support multiple inheritance of type; (3) the relationship is "can-do" or capability-based; (4) you want maximum flexibility and decoupling. In modern Java (8+), default methods blur the line, but the core guidance remains: favor interfaces for contracts and abstract classes for shared implementation.
Q18. What are sealed interfaces in Java 17?
A: Sealed interfaces (finalized in Java 17 via JEP 409) restrict which classes or interfaces can implement or extend them using a permits clause. This gives library/API authors precise control over the type hierarchy. Every permitted implementor must be in the same package (or module) and must be declared final, sealed, or non-sealed. Sealed types pair well with pattern matching (switch expressions) because the compiler can exhaustively check all permitted subtypes.
sealed interface Shape permits Circle, Rectangle, Triangle {}
final class Circle implements Shape { double radius; }
final class Rectangle implements Shape { double width, height; }
final class Triangle implements Shape { double base, height; }
// Exhaustive pattern matching (Java 21 preview / Java 21)
static double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.radius * c.radius;
case Rectangle r -> r.width * r.height;
case Triangle t -> 0.5 * t.base * t.height;
};
}
Q19. What is the Comparable interface and how does it work?
A: java.lang.Comparable<T> is an interface with one method: int compareTo(T o). A class implements Comparable to define its natural ordering. The compareTo method returns a negative integer (this < o), zero (this == o), or positive integer (this > o). Collections.sort() and Arrays.sort() use natural ordering when no Comparator is given. Example: String, Integer, LocalDate all implement Comparable.
Q20. What is the Comparator interface and how does it differ from Comparable?
A: java.util.Comparator<T> is a functional interface with method int compare(T o1, T o2). It defines an external comparison strategy, separate from the class being compared. Key differences: Comparable is implemented by the class itself and defines one natural order; Comparator is a separate object and allows multiple different orderings for the same class. Comparator is preferred when you cannot modify the class, or when you need more than one sort order. Java 8 added chainable factory methods: Comparator.comparing(), thenComparing(), reversed().
| Aspect | Comparable | Comparator |
|---|---|---|
| Package | java.lang | java.util |
| Method | compareTo(T o) | compare(T o1, T o2) |
| Implementation | By the class itself | By a separate class/lambda |
| Orderings | One natural order | Multiple custom orders |
| Functional? | No (not @FunctionalInterface) | Yes (functional interface) |
| Modify class? | Must modify the class | No class modification needed |
Q21. What are Iterable and Iterator interfaces?
A: java.lang.Iterable<T> has one abstract method: Iterator<T> iterator(). Any class implementing Iterable can be used in a for-each loop. java.util.Iterator<T> has methods: boolean hasNext() and T next() (and optional void remove()). The for-each loop is syntactic sugar that calls iterator() and then loops using hasNext()/next(). All Java collections implement Iterable. Custom data structures (linked lists, trees) should implement Iterable to be foreach-compatible.
Q22. What is AutoCloseable vs Closeable?
A: Both are used with try-with-resources. java.lang.AutoCloseable (Java 7) has void close() throws Exception. java.io.Closeable extends AutoCloseable and has void close() throws IOException — a narrower exception. Closeable is intended for I/O resources; it also adds the contract that repeated calls to close() have no additional effect (idempotent). AutoCloseable makes no idempotency guarantee. Use AutoCloseable for general resources (JDBC connections, locks); use Closeable for I/O streams.
Q23. What is the difference between Runnable and Callable?
A: java.lang.Runnable has one method: void run() — no return value, cannot throw checked exceptions. java.util.concurrent.Callable<V> has one method: V call() throws Exception — returns a value and can throw checked exceptions. Use Runnable for fire-and-forget tasks; use Callable when you need a result or checked exception propagation. ExecutorService.submit(Callable) returns a Future<V>; submit(Runnable) returns Future<?> (always null on get).
Q24. What are generic interfaces in Java?
A: An interface can be parameterized with one or more type parameters, making it generic. This allows a single interface to work with many types in a type-safe way. Example: interface Repository<T, ID> { T findById(ID id); List<T> findAll(); }. Implementing classes provide concrete types: class UserRepo implements Repository<User, Long>. Generic interfaces are the foundation of the Java Collections Framework (List<E>, Map<K,V>, etc.).
Q25. Explain the diamond problem with default methods and how Java resolves it.
A: The diamond problem occurs when a class implements two interfaces that each provide a default implementation of the same method signature. Java 8 requires the implementing class to explicitly override that method to resolve the ambiguity — the compiler produces an error if you do not. Inside the override, you can explicitly invoke a specific interface's default method using the syntax InterfaceName.super.methodName(). This resolution rule is deterministic and eliminates the classic C++ diamond ambiguity.
interface A {
default String hello() { return "Hello from A"; }
}
interface B {
default String hello() { return "Hello from B"; }
}
// Compiler ERROR if we don't override hello()
class C implements A, B {
@Override
public String hello() {
return A.super.hello(); // explicitly choose A's default
}
}
// Usage
C c = new C();
System.out.println(c.hello()); // Hello from A
Q26. What is the default method resolution order in Java?
A: Java uses three rules in order: (1) Classes win over interfaces — if a class provides a concrete method, it always takes priority over any default method from an interface. (2) More specific interfaces win — if interface B extends interface A and both define the same default method, B's version wins because it is more specific. (3) Explicit override required — if two sibling interfaces (neither extends the other) both provide the same default method, the implementing class must override the method or compilation fails. These rules guarantee no ambiguity.
Q27. What is the Interface Segregation Principle?
A: The Interface Segregation Principle (ISP) is the "I" in SOLID. It states that no client should be forced to depend on methods it does not use. Instead of one large interface, prefer many small, focused interfaces. For example, instead of one Worker interface with work(), eat(), and sleep(), split into Workable, Eatable, and Sleepable. A robot class can implement only Workable. ISP reduces coupling, makes mocking in tests easier, and prevents bloated implementations.
Q28. Can an abstract class implement an interface without providing implementations?
A: Yes. An abstract class can implement an interface and leave some or all of the interface's abstract methods unimplemented (abstract). The first concrete subclass in the hierarchy must then implement those methods. This is a common pattern for Template Method design: the abstract class implements part of the interface and defers the remaining methods as abstract, to be filled by concrete subclasses.
Q29. What happens if a class does not implement all interface methods?
A: If a class does not implement all abstract methods from the interfaces it claims to implement, the class must itself be declared abstract. If it is declared concrete (no abstract keyword), the compiler produces a compilation error listing the unimplemented method(s). This enforces the interface contract: every concrete class must fully honor every interface it implements.
Q30. Can an interface have instance variables?
A: No. All variables declared in an interface are implicitly public static final (constants). They belong to the interface type, not to any instance. You cannot declare instance variables (non-static fields) in an interface. This is a fundamental difference from abstract classes, which can have any type of field including instance variables with any access modifier.
Q31. What is the purpose of the Serializable marker interface?
A: java.io.Serializable is a marker interface (no methods) that signals to the Java Serialization API (ObjectOutputStream / ObjectInputStream) that objects of the class can be converted to a byte stream and later reconstructed. Without this marker, attempting to serialize an object throws NotSerializableException. Classes should also define a serialVersionUID constant to ensure version compatibility. Fields marked transient are not serialized.
Q32. What is the purpose of the Cloneable marker interface?
A: java.lang.Cloneable marks a class as permitting the protected Object.clone() method to make a field-by-field copy. Without it, calling clone() on an object throws CloneNotSupportedException. The cloning contract is considered broken by many Java experts (Joshua Bloch recommends copy constructors or copy factories instead) because clone() bypasses constructors and can produce shallow copies. Nevertheless, Cloneable frequently appears in interviews.
Q33. What is the Remote marker interface?
A: java.rmi.Remote is a marker interface used with Java RMI (Remote Method Invocation). A class implementing Remote signals that its instances can be made accessible from other JVMs over a network. All methods in a Remote interface must declare throws RemoteException. RMI uses this marker to generate stubs and skeletons for remote communication.
Q34. Can an interface extend multiple interfaces?
A: Yes. An interface can extend multiple interfaces simultaneously: interface C extends A, B { }. The child interface inherits all abstract and default methods from all parent interfaces. If two parents have conflicting default methods with the same signature, the child interface must override that method. This is how Java achieves multiple inheritance of type safely at the interface level.
Q35. Is it possible for an abstract class to have no abstract methods?
A: Yes. An abstract class does not need to have any abstract methods. The abstract keyword on the class merely prevents direct instantiation. This is sometimes useful when you want to prevent creation of a base class even though all its methods are concrete — for example, an abstract utility base class that only subclasses should use.
Q36. Can we declare an interface method as synchronized?
A: No. synchronized is an implementation detail, not a contract. Interface methods cannot be declared synchronized — synchronization must be handled in the implementing class. Similarly, interface methods cannot be declared native.
Q37. Can we declare an interface method as strictfp?
A: Yes, though it is extremely rare. The strictfp modifier can be applied to an interface declaration (making all methods within it use strict floating-point semantics) or to individual default methods. Abstract methods do not carry strictfp into implementations — the implementing class must also declare strictfp for that guarantee.
Q38. What is the difference between abstract methods in abstract class vs interface?
A: In an abstract class, abstract methods can have any access modifier except private (the subclass must override them, so they must be visible). In an interface, all abstract methods are implicitly public — you cannot use protected or package-private. This means an implementing class must override interface methods with public visibility (you cannot narrow access). Abstract class abstract methods can also be package-private, unlike interface methods.
Q39. What are the common built-in functional interfaces in java.util.function?
A: The java.util.function package (Java 8) provides: Function<T,R> (apply T, return R), BiFunction<T,U,R> (two inputs), Predicate<T> (test T, return boolean), Consumer<T> (accept T, no return), Supplier<T> (no input, return T), UnaryOperator<T> (extend Function, same type), BinaryOperator<T> (extend BiFunction, same type). Primitive specializations include IntPredicate, LongFunction, DoubleConsumer, etc., to avoid boxing overhead.
Q40. How does a lambda expression relate to a functional interface?
A: A lambda expression is an anonymous implementation of a functional interface's single abstract method. The compiler uses the target type (the functional interface type expected in the context) to infer which SAM the lambda implements. The lambda's parameter types, return type, and checked exceptions must be compatible with the SAM's signature. At runtime, lambdas are typically implemented via invokedynamic (not anonymous inner classes), which is more memory-efficient.
Q41. What is a method reference and how does it relate to functional interfaces?
A: A method reference (::) is a shorthand for a lambda that just calls an existing method. There are four kinds: (1) static method: ClassName::staticMethod; (2) instance method of a particular instance: instance::method; (3) instance method of an arbitrary instance of a type: ClassName::instanceMethod; (4) constructor: ClassName::new. All four forms are compatible with functional interfaces whose SAM signature matches the referenced method's signature.
Q42. Can an abstract class have a private constructor?
A: Yes, technically allowed. However, a private constructor in an abstract class means no subclass can call super() explicitly, and the compiler cannot generate the implicit super call for a no-arg constructor either (since private constructors are not visible to subclasses). This effectively prevents subclassing entirely, making the abstract class useless. It is not a practical pattern.
Q43. Can you have a final abstract class?
A: No. This is a contradiction. abstract means the class must be subclassed (otherwise it can never be instantiated). final means the class cannot be subclassed. The compiler rejects final abstract class with a compilation error.
Q44. Can you have a final method in an abstract class?
A: Yes. An abstract class can have final concrete methods. These methods provide fixed behavior that subclasses cannot override, which is the foundation of the Template Method design pattern — the abstract class defines the algorithm skeleton in a final method, calling abstract hook methods that subclasses must implement.
Q45. What is the Template Method design pattern and how does it use abstract classes?
A: The Template Method pattern defines the skeleton of an algorithm in a base (abstract) class, deferring some steps to subclasses. A final method in the abstract class calls a sequence of steps, some of which are abstract (overridden by subclasses) and some are concrete (shared behavior). This enforces the algorithm structure while allowing customization of individual steps without changing the overall flow.
Q46. What happens when an abstract class has a static method with the same signature as an interface default method?
A: Static methods in classes and interfaces do not override each other. A static method in an abstract class is independent of any interface default method with the same name. The class's static method is accessed via the class name; the interface's static method is accessed via the interface name. Neither hides nor overrides the other. Only instance methods participate in dynamic dispatch and default method resolution.
Q47. Explain interface default method inheritance in a class hierarchy.
A: If a concrete class extends a class that already provides a concrete implementation of a method that an interface also declares as a default method, the class wins over the interface default. Rule: class-provided implementations always take priority over interface defaults. This prevents interface defaults from unexpectedly changing behavior when added to existing hierarchies (backward compatibility guarantee).
Q48. What is the significance of interfaces being reference types?
A: Since interfaces are reference types, you can declare variables of an interface type, pass interface-typed parameters, return interface types from methods, and use interfaces as generic type bounds. This enables programming to interfaces (the Dependency Inversion Principle) — client code depends on the abstraction (interface), not the concrete implementation. Switching implementations requires no change to the client code.
Q49. Can you create an anonymous class from an abstract class?
A: Yes. You can instantiate an abstract class with an anonymous class that provides implementations of all abstract methods: Animal a = new Animal("Cat") { public void makeSound() { System.out.println("Meow"); } };. This creates an unnamed subclass on the fly. Before Java 8 lambdas, this was commonly used with functional interfaces too. Anonymous classes can access final or effectively-final local variables from the enclosing scope.
Q50. What is the difference between an abstract class and a concrete class?
A: A concrete class is a fully implemented class that can be instantiated directly with new. All its methods have bodies. An abstract class has at least one abstract method (or is explicitly declared abstract) and cannot be instantiated. Abstract classes sit in the hierarchy between interfaces (no implementation) and concrete classes (full implementation), providing partial implementation and a common template for related subclasses.
Q51. How do you call an interface's default method from an implementing class?
A: If the implementing class does not override the default method, it inherits and can call it normally as this.methodName() or just methodName(). If the class overrides the method but still wants to call the interface's default, it uses InterfaceName.super.methodName(). This is only valid inside an instance method of the implementing class, not in static contexts.
Q52. Can two unrelated interfaces have the same default method without causing compile errors in a class that implements only one?
A: Yes. A conflict only arises when a single class implements both interfaces that define the same default method. If a class implements only one of them, there is no conflict — it inherits that interface's default cleanly. The diamond problem manifests only at the point where a class inherits two conflicting defaults simultaneously.
Q53. What are the non-sealed, sealed, and final options for permitted subtypes?
A: When a sealed class or interface permits subtypes, each permitted subtype must choose one of: (1) final — no further extension allowed; (2) sealed — can be extended, but with its own permits restriction; (3) non-sealed — reopens the hierarchy for unrestricted extension. non-sealed is unique to Java 17+ sealed types and has no equivalent in prior Java versions. It allows library authors to permit some subtypes to be freely extended.
Q54. Why were default methods added to interfaces in Java 8?
A: The primary motivation was backward compatibility during the Java 8 Collections API enhancement. Adding new abstract methods (like forEach, stream(), removeIf) to existing interfaces like Collection and List would have broken every existing implementation of those interfaces. Default methods allowed these methods to be added to existing interfaces with a default implementation, making zero existing implementations break. It was a pragmatic compromise for API evolution.
Q55. What is the Predicate functional interface?
A: java.util.function.Predicate<T> has SAM boolean test(T t). It represents a boolean-valued function of one argument and is widely used for filtering. It has useful default methods: and(Predicate), or(Predicate), negate(), and static method not(Predicate) (Java 11). Example: list.stream().filter(s -> s.length() > 3).collect(toList()) — the lambda is a Predicate<String>.
Q56. What is the Consumer functional interface?
A: java.util.function.Consumer<T> has SAM void accept(T t). It represents an operation that accepts one argument and returns no result (side-effect operation). Default method andThen(Consumer) chains consumers. Used in Iterable.forEach(), Stream.peek(), Optional.ifPresent(). Example: list.forEach(System.out::println) — the method reference is a Consumer<String>.
Q57. What is the Supplier functional interface?
A: java.util.function.Supplier<T> has SAM T get(). It represents a supplier of results with no input — a factory or lazy value provider. Used in Optional.orElseGet(Supplier), CompletableFuture.supplyAsync(Supplier). Example: Optional.empty().orElseGet(() -> "default").
Q58. What is the Function functional interface?
A: java.util.function.Function<T,R> has SAM R apply(T t). It maps input type T to output type R. Default methods: andThen(Function) (compose after) and compose(Function) (compose before). Static method identity() returns a function that returns its input. Used in Stream.map(), Optional.map().
Q59. What is the UnaryOperator and BinaryOperator?
A: UnaryOperator<T> extends Function<T,T> — same input and output type (e.g., transforming a string). BinaryOperator<T> extends BiFunction<T,T,T> — takes two operands of same type and returns same type (e.g., adding two integers). Both are used in Stream.reduce(), List.replaceAll(), etc. They signal through the type system that the operation is closed over a single type.
Q60. Can a functional interface override Object methods?
A: Yes. A functional interface may declare methods that override java.lang.Object public methods (equals, hashCode, toString). These do not count as additional abstract methods because every implementing class already inherits concrete implementations from Object. So a functional interface can have one SAM plus any number of Object method declarations without violating the single-abstract-method rule. Comparator is an example — it declares equals(Object) but is still a functional interface.
Q61. What is the difference between abstract class and interface in terms of design intent?
A: An abstract class represents an "is-a" relationship with partial reuse — subclasses are specializations of the same type and share code. An interface represents a "has-a capability" or "can-do" relationship — unrelated classes (e.g., Dog and Airplane) can both implement Flyable without sharing any code. Abstract classes model taxonomy; interfaces model capabilities and roles. A class models what something IS; an interface models what something CAN DO.
Q62. What are the limitations of marker interfaces compared to annotations?
A: Marker interfaces can only be checked at runtime via instanceof (cheap check) and provide type safety (you can use the marker as a type bound). Annotations are more flexible: they can carry metadata (values), can be applied to methods/fields/parameters/local variables (not just classes), can be processed at compile time (annotation processors), and can have retention policies (source, class, runtime). Modern frameworks (Spring, Jackson) prefer annotations for marking because of their richer expressiveness.
Q63. What is the Comparable contract and how does it relate to equals?
A: The Comparable contract requires that compareTo defines a total ordering consistent with equals: if x.equals(y) then x.compareTo(y) == 0. The reverse recommendation (but not requirement) is also strong: if x.compareTo(y) == 0 then x.equals(y) should be true. Violation causes surprising behavior when using TreeSet or TreeMap, which use compareTo for equality decisions (an element might not be found even though equals says it is present).
Q64. How does Java 8's Comparator.comparing() work?
A: Comparator.comparing(keyExtractor) creates a Comparator that compares objects by extracting a Comparable sort key from each. You can chain thenComparing() for secondary sort keys. Example: Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName).reversed() sorts persons by last name, then first name, and then reverses. This fluent API replaced most verbose anonymous Comparator implementations.
Q65. What is the Iterator remove() method contract?
A: Iterator.remove() removes from the underlying collection the last element returned by next(). It is optional — implementations may throw UnsupportedOperationException. It can be called at most once per call to next(). It is the only safe way to remove elements from a collection while iterating — using Collection.remove() directly during iteration throws ConcurrentModificationException for most collections.
Q66. Explain how try-with-resources works with AutoCloseable.
A: The try-with-resources statement (Java 7) automatically calls close() on any AutoCloseable resource declared in the try header when the block exits, whether normally or via exception. Resources are closed in reverse order of declaration. If both the body and close() throw exceptions, the body exception propagates and the close exception is added as a suppressed exception (accessible via Throwable.getSuppressed()). This eliminates the verbose finally-block boilerplate for resource cleanup.
Q67. Can you use a lambda where a Runnable is expected?
A: Yes. Since Runnable is a functional interface (SAM: void run()), any no-arg, void-returning lambda can be used as a Runnable: Runnable r = () -> System.out.println("Running");. This is extensively used with Thread, ExecutorService, and CompletableFuture.runAsync().
Q68. What is the relationship between Callable and Future?
A: Callable<V> defines a computation that returns a result. When submitted to an ExecutorService via submit(callable), it returns a Future<V>. The Future represents the pending result — you can call future.get() to block and retrieve the result when the computation completes, or future.get(timeout, unit) to wait with a timeout. If call() threw a checked exception, get() wraps it in an ExecutionException.
Q69. What is a generic bounded interface?
A: An interface can use bounded type parameters. For example, interface Summable<T extends Number> { T sum(List<T> items); } restricts T to Number and its subtypes. Bounded wildcards (? extends T, ? super T) can appear in method signatures within generic interfaces. This enables type-safe APIs that work across a family of related types without sacrificing compiler checking.
Q70. Can a generic interface be implemented with different type parameters by the same class?
A: No. Due to Java's type erasure, a class cannot implement the same generic interface twice with different type arguments. For example, class Foo implements Comparable<String>, Comparable<Integer> is illegal. After erasure, both reduce to Comparable and the class would need two conflicting compareTo implementations. A class can implement only one parameterization of a generic interface.
Q71. What is the Abstract Factory pattern and how does it use interfaces?
A: Abstract Factory is a creational design pattern that provides an interface for creating families of related objects without specifying concrete classes. The factory interface declares creation methods for each product type. Concrete factories implement the interface to produce products for a specific platform or theme. Client code depends only on the factory interface and product interfaces, achieving full decoupling from concrete classes.
Q72. What is the Strategy pattern and how does it use interfaces?
A: The Strategy pattern defines a family of algorithms, encapsulates each one in a class implementing a common strategy interface, and makes them interchangeable. The context class holds a reference to a strategy interface and delegates behavior to it. In Java 8+, lambdas simplify strategy usage — the strategy interface is typically a functional interface, and each strategy is a lambda or method reference. Example: Sorter interface with different sorting algorithm implementations.
Q73. How do sealed interfaces enable exhaustive pattern matching?
A: Because a sealed interface declares all permitted subtypes, the compiler knows the complete closed set of possible implementations. In Java 21's switch expression with pattern matching, if you cover all permitted subtypes in cases, the compiler recognizes the switch as exhaustive and does not require a default case. This catches missing cases at compile time, making code safer when new subtypes are added to the sealed hierarchy (adding a new permitted type forces you to handle it everywhere).
Q74. What is the significance of @FunctionalInterface with inheritance?
A: If a child interface extends a functional interface and adds no new abstract methods, it remains a functional interface and can be annotated with @FunctionalInterface. If it adds one new abstract method, it is no longer functional and the annotation causes a compiler error. If a child interface overrides the parent's SAM with an abstract declaration (re-abstract it), that does not add a new SAM — it is still the same functional interface type.
Q75. Explain how the Iterable and for-each loop interact.
A: The Java compiler desugars for (T item : collection) into: call collection.iterator() to get an Iterator<T>, then loop calling it.hasNext() and it.next(). This means any class implementing Iterable<T> (or arrays) can be used in a for-each loop. Arrays are handled specially by the compiler (no Iterable required). Custom data structures (graphs, trees, custom sequences) become for-each compatible simply by implementing Iterable.
Q76. What is the difference between interface segregation and single responsibility?
A: Single Responsibility Principle (SRP) applies to classes — a class should have one reason to change, one primary responsibility. Interface Segregation Principle (ISP) applies to interfaces — an interface should be narrow and focused, not forcing clients to implement irrelevant methods. They are complementary: SRP guides class design, ISP guides interface design. A class following SRP naturally leads to implementing small, focused interfaces following ISP.
Q77. Can abstract methods be overloaded in an abstract class?
A: Yes. Abstract methods can be overloaded in an abstract class (same name, different parameter list). A subclass can implement any or all overloaded versions. The subclass must implement all overloads that are abstract; if any overload is not implemented by the concrete subclass, the subclass must itself be abstract.
Q78. What is a covariant return type and how does it apply to interface method overriding?
A: Covariant return types allow an overriding method to return a subtype of the return type declared in the parent/interface. For example, if an interface declares Animal create(), an implementing class may override it as Dog create() (where Dog extends Animal). This is type-safe because any code expecting an Animal will still work with a Dog. Covariant returns were introduced in Java 5 and apply to both abstract class overriding and interface method implementation.
Q79. What are the access modifier rules for overriding interface methods?
A: Interface abstract methods are implicitly public. When a class implements (overrides) an interface method, the implementing method must also be public. Java's overriding rule says you cannot narrow access — since the interface declares methods public, the implementation cannot be package-private, protected, or private. Failing to mark the implementation public causes a compile error ("attempting to assign weaker access privileges").
Q80. What is the role of interfaces in dependency injection?
A: Dependency Injection (DI) frameworks (Spring, Guice) rely heavily on interfaces for decoupling. A service declares its dependencies as interface types. The DI container provides concrete implementations at runtime. This means you can swap implementations (e.g., real DB vs. in-memory for tests) without changing the service code. Spring uses Java interfaces as the basis for AOP proxies — if a class implements at least one interface, Spring creates a JDK dynamic proxy; otherwise it uses CGLIB.
Q81. How does Java handle interface constants inheritance?
A: When a class implements an interface, all public static final constants of the interface are accessible within the class without qualification. Similarly, when an interface extends another interface, it inherits the parent's constants. This can cause naming conflicts if two interfaces define constants with the same name — the class must then qualify the constant with the interface name. The "constant interface anti-pattern" is discouraged because it pollutes the class's namespace.
Q82. Can an interface be declared inside a class?
A: Yes. Interfaces can be declared as nested types inside a class, making them static member types. A nested interface is implicitly static (you do not need the static keyword). It is referenced as OuterClass.InnerInterface. This is commonly used to logically group an interface with its primary associated class — for example, Map.Entry is a nested interface inside Map.
Q83. Can a class be both abstract and implement an interface partially?
A: Yes. An abstract class can implement an interface and provide implementations for only some of the interface's methods, leaving others abstract. Concrete subclasses must implement the remaining abstract methods. This pattern is used to provide a convenient skeletal implementation — for example, AbstractList implements List but leaves get(int) and size() abstract, providing concrete implementations for most other List operations in terms of those two.
Q84. What is the skeletal implementation pattern?
A: The skeletal implementation pattern (described by Joshua Bloch in Effective Java) pairs an interface with an abstract class that provides default implementations for most interface methods. The abstract class is named AbstractXxx (e.g., AbstractList, AbstractMap). Users can implement the interface directly (full flexibility) or extend the abstract class (convenience). This gives the best of both worlds: interface-based typing with reusable partial implementation.
Q85. How does the Decorator pattern use interfaces?
A: The Decorator pattern wraps an object with additional behavior by having both the wrapper (decorator) and the wrapped object implement the same interface. The decorator delegates to the wrapped object and adds behavior before/after. Since all components share the interface type, decorators are composable and transparent to clients. Java I/O streams (BufferedReader wrapping FileReader) are the canonical example of the decorator pattern using interfaces.
Q86. What is the Proxy pattern and how does it use interfaces?
A: A proxy implements the same interface as the real subject and controls access to it. The proxy can add logging, caching, access control, or lazy initialization without changing the real object or client code. Java's java.lang.reflect.Proxy creates dynamic proxies at runtime for any interface. Spring AOP uses dynamic proxies (JDK for interfaces, CGLIB for classes) to weave cross-cutting concerns like transactions and security.
Q87. What is the Observer pattern and how does it use interfaces?
A: The Observer pattern defines a one-to-many dependency: when a subject changes state, all registered observers are notified. The observer interface (e.g., EventListener) defines the callback method. Subjects maintain a list of Observer interface references and invoke the callback on each. Java's built-in event model, Swing listeners, and reactive libraries all use this interface-based pattern. Lambdas make registering observers concise when the observer interface is functional.
Q88. What is the Command pattern and its relation to functional interfaces?
A: The Command pattern encapsulates a request as an object implementing a command interface (typically with an execute() method). Commands can be queued, logged, or undone. In Java 8+, since a no-arg void command interface is a SAM, lambda expressions can serve as commands, eliminating the need for a separate interface in many cases — Runnable or Consumer can act as the command interface directly.
Q89. How do interfaces support the Open/Closed Principle?
A: The Open/Closed Principle (OCP) states that software entities should be open for extension but closed for modification. Interfaces enable OCP by defining stable contracts: you can add new implementing classes (extending behavior) without modifying existing code that depends on the interface. For example, adding a new payment processor class implementing PaymentGateway requires no change to the checkout service that programs against PaymentGateway.
Q90. What are the implications of interface evolution with default methods for library authors?
A: Library authors can add new methods to existing interfaces using default methods without breaking binary or source compatibility with existing implementations. However, if an existing class happens to already have a method with the same name/signature, the class method takes priority (rule 1: class wins). If two library interfaces both add the same default method, any class implementing both faces a diamond conflict. Library authors should use default methods conservatively and document them clearly.
Q91. What is the difference between extends and implements for interfaces?
A: A class uses implements to adopt an interface's contract. An interface uses extends to inherit from one or more other interfaces. You cannot use implements for an interface inheriting another interface — that is a compile error. You cannot use extends for a class adopting an interface — also a compile error. The keywords explicitly reflect the relationship: a class implements a contract; an interface extends/refines another contract.
Q92. Can an enum implement an interface?
A: Yes. Enums can implement interfaces. This is powerful for adding behavior to enum constants. Each enum constant can optionally override interface methods individually (by providing a constant-specific class body). Example: an Operation enum implementing a MathOperation interface with apply(double x, double y) — each constant (PLUS, MINUS, MULTIPLY) provides its own implementation. This is a clean alternative to switch statements over enums.
Q93. What happens if you declare a variable of an interface type and assign null to it?
A: It is valid — interface types are reference types, and any reference variable can hold null. null instanceof SomeInterface evaluates to false (null is not an instance of anything). Calling any method on a null interface reference throws NullPointerException. The practice of assigning null to interface references is legal but should be avoided in favor of Optional for optional values.
Q94. How does instanceof work with interfaces?
A: object instanceof InterfaceName returns true if the object's runtime type implements the interface (directly or through inheritance). Since a class can implement multiple interfaces, an object may be an instance of many interface types simultaneously. The compiler allows instanceof checks with interfaces even when the static type of the variable has no declared relationship to the interface (unlike class-to-class instanceof, which the compiler flags as impossible if types are unrelated and final).
Q95. What is the functional interface for handling exceptions in lambdas?
A: Java's standard functional interfaces (Function, Predicate, etc.) do not declare checked exceptions, so lambdas that throw checked exceptions do not fit directly. The common solutions are: (1) wrap the checked exception in a runtime exception inside the lambda; (2) define a custom functional interface that declares throws Exception; (3) use utility wrappers that convert checked-exception-throwing functions to unchecked. Libraries like Vavr and Failsafe provide checked-exception-friendly functional interfaces.
Q96. What is the Iterable.forEach default method?
A: Iterable.forEach(Consumer<? super T> action) is a default method added in Java 8. It iterates all elements and applies the given consumer action to each. It is equivalent to a for-each loop but uses a functional style. The default implementation is: for (T t : this) { action.accept(t); }. Specific collection implementations may override it for performance. Example: list.forEach(System.out::println).
Q97. How do interface static methods differ from utility classes?
A: Interface static methods allow you to place utility/factory methods directly on the interface type they relate to, without a separate utility class. For example, Comparator.naturalOrder() and Comparator.reverseOrder() are static methods on the interface. This improves discoverability — users look at the interface they are working with and find helpers there. Utility classes (like Collections) remain useful for broader utilities spanning many types, but interface static methods are more cohesive for single-interface utilities.
Q98. What is the difference between Closeable.close() idempotency requirement and AutoCloseable?
A: java.io.Closeable explicitly documents that its close() method must be idempotent — calling it multiple times has the same effect as calling it once (no additional exceptions on subsequent calls). This is important because try-with-resources can call close() in multiple code paths. java.lang.AutoCloseable makes no such guarantee — repeated calls may throw exceptions. When implementing a resource, following the Closeable idempotency contract is best practice even if you only extend AutoCloseable.
Q99. Can a private interface method call an abstract interface method?
A: Yes. A private method in an interface (Java 9+) has access to the interface's own methods, including abstract ones (via implicit this). When a private method calls an abstract method, the actual implementation invoked at runtime is the one provided by the concrete implementing class — standard dynamic dispatch applies. This allows private helper methods to delegate behavior to the abstract contract, making default method implementations DRY.
Q100. Summarize the key decision guide: abstract class vs interface.
A:
| Question | Choose Abstract Class | Choose Interface |
|---|---|---|
| Need shared state? | Yes — instance fields needed | No — only constants |
| Need constructors? | Yes | No |
| Multiple inheritance? | No — single extends | Yes — multiple implements |
| Relationship type? | Is-a (tight coupling) | Can-do (loose coupling) |
| Shared implementation? | Yes — concrete methods | Only via default methods |
| Restrict hierarchy? | No (use sealed class) | Yes — sealed interface (Java 17) |
| Lambda target? | No | Yes — if functional interface |
Q101. What is the impact of adding a new abstract method to an existing interface?
A: Adding a new abstract method to an existing interface is a breaking change. All existing classes that implement the interface will fail to compile (or fail at runtime with AbstractMethodError for pre-compiled classes) because they do not implement the new method. This is why Java 8 introduced default methods — to allow adding new methods to existing interfaces without breaking existing implementations. In API design, you should avoid adding abstract methods to published interfaces; use default methods instead.
Q102. What is AbstractMethodError and when does it occur?
A: java.lang.AbstractMethodError is a runtime error thrown when code attempts to invoke an abstract method that has no implementation. This typically happens when a class was compiled against an older version of an interface, then the interface added a new abstract method, and the class is run against the newer interface without recompilation. With default methods this is prevented, but it can still occur in scenarios involving inheritance and dynamic class loading with mismatched versions.
Q103. What are private static methods in interfaces (Java 9)?
A: Java 9 added both private instance methods and private static methods to interfaces. Private static methods are utility helpers for static methods within the interface. They cannot access instance state (none exists in interfaces) and cannot be called by implementing classes. They reduce duplication within interface static methods. Example: a private static validate() helper called by two public static factory methods on the same interface.
interface MathUtils {
static int add(int a, int b) {
checkArgs(a, b); // private static helper
return a + b;
}
static int multiply(int a, int b) {
checkArgs(a, b); // reuse without code duplication
return a * b;
}
private static void checkArgs(int a, int b) { // Java 9 private static
if (a < 0 || b < 0) throw new IllegalArgumentException("Negative not allowed");
}
default String describe(int a, int b) {
return format(a, b); // private instance helper
}
private String format(int a, int b) { // Java 9 private instance
return "(" + a + ", " + b + ")";
}
}
Q104. What is the role of interfaces in the Collections Framework?
A: The Java Collections Framework is built entirely on interfaces. The root interfaces are Collection<E>, Map<K,V>, and Iterator<E>. Sub-interfaces include List, Set, Queue, Deque, SortedSet, SortedMap, NavigableSet, NavigableMap. Concrete classes (ArrayList, LinkedList, HashMap, TreeMap) implement these interfaces. Client code programs to interface types (e.g., List<String> list = new ArrayList<>()), enabling easy substitution of implementations.
Q105. How do you implement multiple interfaces that each have a method with the same name but different signatures?
A: If two interfaces declare methods with the same name but different parameter lists (overloaded signatures), there is no conflict — the class simply provides both implementations as regular method overloads. The conflict only arises when the name and parameter list are identical (same signature). For identical signatures with compatible return types, the class provides one implementation that satisfies both. For incompatible return types, Java cannot compile the implementation at all — this is a true interface incompatibility that cannot be resolved.
Q106. What is the Flyweight pattern and how do interfaces assist?
A: The Flyweight pattern shares common state among many fine-grained objects to reduce memory. Interface types enable Flyweight by allowing cached shared instances to be returned as interface references — the client does not know it is receiving a shared object. The flyweight factory returns the appropriate shared instance based on intrinsic state. This is the pattern behind Integer.valueOf() (which caches -128 to 127) and string interning.
Q107. What is the Chain of Responsibility pattern and how do interfaces support it?
A: The Chain of Responsibility pattern passes a request along a chain of handlers, where each handler decides to process the request or pass it to the next. The handler interface defines a handle(Request r) method (and optionally a setNext(Handler h) method). Concrete handlers implement the interface. Java's servlet filters and logging handlers (java.util.logging) use this pattern with interface-based handler chains.
Q108. What are the Java 17 changes to sealed interfaces vs Java 16?
A: Sealed classes and interfaces were a preview feature in Java 15 and 16 (JEPs 360 and 397). Java 17 finalized them as a standard feature (JEP 409) with no changes from Java 16's preview. The finalization means sealed types are stable, production-ready, and no longer require --enable-preview. Record classes (also finalized in Java 16) frequently accompany sealed interfaces for modeling algebraic data types (ADTs) in Java.
Q109. Explain how Comparable is used with TreeSet and TreeMap.
A: TreeSet<T> and TreeMap<K,V> use a sorted order for their elements/keys. If no Comparator is provided at construction, they rely on the natural ordering defined by Comparable. Elements added to a TreeSet or keys added to a TreeMap must implement Comparable, otherwise a ClassCastException is thrown at runtime. The tree structures (Red-Black trees) use compareTo to determine position — they do not use equals or hashCode.
Q110. What happens when Comparable and equals are inconsistent in a TreeSet?
A: TreeSet uses compareTo (not equals) to determine element uniqueness. If compareTo returns 0 for two objects but equals returns false, TreeSet treats them as duplicates (only keeps one). Conversely, if equals returns true but compareTo returns non-zero, TreeSet treats them as different elements. This inconsistency causes the set to violate the Set interface's contract. The general rule: compareTo should be consistent with equals.
Q111. How do you create a Comparator for null-safe sorting?
A: Java 8 added Comparator.nullsFirst(Comparator) and Comparator.nullsLast(Comparator) which wrap another comparator and handle null values by placing them first or last respectively. Example: Comparator.nullsFirst(Comparator.comparing(Person::getName)) sorts persons by name, placing null-named persons first. This avoids NullPointerException when sorting collections that may contain null elements or null sort keys.
Q112. What is the role of the interface in the Builder pattern?
A: In a fluent Builder pattern, a builder interface defines the build steps, and a concrete builder implements them. Using an interface for the builder enables multiple builder implementations (e.g., an XML builder and a JSON builder for the same product) and facilitates testing (mock builders). Each builder method returns the builder type (for chaining), and the terminal build() method returns the product. Java records' builders or Lombok's @Builder generate this pattern automatically.
Q113. What is the relationship between abstract classes and the Template Method pattern?
A: The Template Method pattern is the canonical use case for abstract classes. The abstract class defines a final template method that calls a fixed sequence of steps (some abstract, some concrete). Subclasses override only the abstract steps (hooks) to customize behavior without changing the overall algorithm. This avoids code duplication (shared steps in the abstract class) while enforcing structure (final template method cannot be bypassed). Example: HttpServlet with service() dispatching to abstract doGet()/doPost().
Q114. What is the difference between Iterable.forEach and Stream.forEach?
A: Iterable.forEach(Consumer) is a sequential, guaranteed ordered operation on the collection. Stream.forEach(Consumer) may execute in any order (for parallel streams), and its behavior on ordered streams is nondeterministic for parallel execution — use Stream.forEachOrdered(Consumer) if ordering matters with parallel streams. Additionally, Iterable.forEach operates on the collection directly; Stream.forEach is a terminal operation on a stream pipeline that may involve intermediate lazy operations.
Q115. How do you use Comparator.thenComparing()?
A: thenComparing is a default method on Comparator that appends a secondary comparator, used when the primary comparator considers two elements equal (returns 0). You can chain multiple thenComparing calls for multi-level sorting. Example: Comparator.comparing(Employee::getDepartment).thenComparing(Employee::getSalary, Comparator.reverseOrder()).thenComparing(Employee::getName) sorts by department, then descending salary within department, then name alphabetically.
Post a Comment
Add