Two parents? Not allowed. Two promises? Fine.
In the fest app, Ticket extends Event and CanteenOrder extends FoodItem. Both must go through the same payment screen. Riya tries class Ticket extends Event, Payable and javac stops her: a class can have only one parent class (Lesson 7.2).
Sir, Ticket already extends Event. How can it also be "payable" like a canteen order?
Make Payable an interface: a list of methods every payable thing promises to have. A class extends one parent but can implement as many interfaces as it likes.
And the payment screen?
It accepts a Payable. It doesn't care whether it's a ticket or a dosa, only that it can tell you the amount. That's abstraction at its cleanest.
What is an interface?
An interface is a reference type, declared with the interface keyword, that defines a contract: a set of method signatures that implementing classes must provide. A class implements one or more interfaces with the implements keyword. Interface methods are implicitly public abstract unless declared default (Java 8, with a body), static (Java 8) or private (Java 9). Fields are implicitly public static final constants. An interface cannot be instantiated and has no constructors or instance fields.
An interface is a job description: "anyone in this role must be able to do X and Y". A class can hold several roles at once, whatever family it comes from.
Words you'll meet in this lesson
Payable.withGst(500).m() from an implementing class.What an interface can contain
| Abstract methods | double amount(); is implicitly public abstract. Implementations must be public. |
|---|---|
| Constants | int MAX_ITEMS = 10; is implicitly public static final |
| Default methods | Java 8+: default String receipt() { … }, inherited and overridable |
| Static methods | Java 8+: called only as Payable.withGst(x); not inherited by implementing classes |
| Private methods | Java 9+: helpers for default/static methods; invisible outside |
| Not allowed | Constructors, instance fields, new Payable() ("Payable is abstract; cannot be instantiated") |
Exam tip: a class extends one class and implements many interfaces, and extends comes first: class Ticket extends Event implements Payable, Notifiable. An interface extends other interfaces (possibly several). Forgetting public on an implementing method gives "attempting to assign weaker access privileges; was public".
The kinds of interface members
Abstract methods
The contract. Every implementing class must write them.
must implementdefault methods
Ready-made behaviour built on the contract. Lets an interface grow without breaking old classes.
Java 8static and private
Utilities called on the interface itself; private helpers that remove duplication.
Java 8 / 9Every kind of member in one program
interface Payable {
double GST_RATE = 0.18; // constant: public static final
double amount(); // abstract: the contract
default String receipt() { // default: inherited behaviour
return line("Amount", amount()) + "\n" + line("With GST", withGst(amount()));
}
static double withGst(double a) { // static: a utility
return a * (1 + GST_RATE);
}
private String line(String label, double value) { // private helper (Java 9)
return String.format("%-9s Rs %.2f", label, value);
}
}
class Ticket implements Payable {
@Override
public double amount() { return 500; } // must be public
}
public class Main {
public static void main(String[] args) {
Payable p = new Ticket();
System.out.println(p.receipt());
System.out.println("Static call: " + Payable.withGst(1000));
}
}Interface or abstract class?
| Interface | Abstract class | |
|---|---|---|
| A class can have | Many (implements A, B, C) | One (extends) |
| Instance fields (state) | No; only constants | Yes |
| Constructors | No | Yes |
| Method bodies | default, static, private (Java 8/9+) | Any concrete methods |
| Member access | Public (except private helpers) | Any access level |
| Models | A capability ("can be paid", "can be tracked") | A family with shared state ("is a vehicle") |
| Typical use | Contracts between parts of a system, plug-ins | Shared base code and template methods |
The diamond rule for defaults: if a class implements two interfaces that both provide a default label(), javac refuses: "class Ticket inherits unrelated defaults for label() from types Payable and Notifiable". The class must override label(), and may call a specific one with Payable.super.label(). Also: a method inherited from a class always wins over an interface default ("class wins").
Designing with interfaces
Write the contract
javac compiles an interface to ainterface Payable { double amount(); }.classfile marked as an interface (and abstract).amount()is stored aspublic abstracteven though you didn't type those words.Implement it in any class, from any family
A Ticket object is now an Event, a Payable and a Notifiable at once:class Ticket extends Event implements Payable, Notifiable { public double amount() { return price; } public String contact() { return phone; } }instanceofis true for all three, and it can be stored in a variable of any of those types.Program to the interface
Calls through an interface type usedouble total(Payable[] items) { double sum = 0; for (Payable p : items) sum += p.amount(); return sum; }invokeinterface; the JVM finds the implementation in the object's class, just like dynamic dispatch with classes.Add behaviour later with a default method
Before Java 8, adding a method to an interface broke every implementing class. A default method gives old classes a working implementation automatically; that's howdefault String receipt() { return "Receipt: Rs " + amount(); }List.sortandforEachwere added to existing collections.Resolve clashes explicitly
@Override public String label() { return Payable.super.label() + " + " + Notifiable.super.label(); }X.super.m()works only for an interface the class directly implements. It lets the class reuse either (or both) default versions after javac forces it to decide.
One class, several promises: both views
Left: the code and its result. Right: the class, its parent class (solid line) and its interfaces (dashed lines).
Ticket implements Payable, Notifiable 6 steps- Interface as a type: a Ticket can be stored in a
Payablevariable, andamount()runs Ticket's implementation. - No instances: an interface has no constructor and no state;
new Payable()doesn't compile. - default method:
receipt()has a body in Payable. Ticket inherits it, and it calls Ticket'samount(). - static method: belongs to the interface itself:
Payable.withGst(500)→ 590.0. Not callable asp.withGstorTicket.withGst. - Diamond: both interfaces supply a default
label(). javac won't guess which one Ticket should use. - Resolved: Ticket overrides
label()and callsPayable.super.label().
- Ticket has one superclass (Event, solid line) and implements two interfaces (dashed lines). The object is all three types.
- An interface has no constructor and no instance fields, so there's no object to build.
- The default method's code lives in the interface, but it runs on the Ticket object; its call to
amount()dispatches to Ticket. withGstis not inherited by Ticket. It's called withinvokestaticon the interface.- Two inherited defaults with the same signature and no class method to settle it: javac reports a compile error.
- Once Ticket declares
label(), its own method wins.Payable.super.label()reuses one default.
Interfaces in real systems
Interfaces are the most common way large Java systems connect their parts.
Watch it with an example: one tracking page for parcels and food orders
A courier parcel and a food order come from unrelated classes, but both implement Trackable. Watch the tracking page use the interface's abstract, default and static methods, and settle a default-method clash.
- Interface type: the tracking page holds a
Trackable. Right now it's a courier Parcel, sostatus()runs Parcel's implementation. - Unrelated class: a FoodOrder has nothing in common with Parcel except the promise. The same variable and call work.
- default method:
summary()is written once in the interface. It runs on the FoodOrder and calls itsstatus(). - static method:
Trackable.isValidAwb(...)is a helper that belongs to the interface; it isn't inherited by Parcel or FoodOrder. - Diamond: Parcel also implements
Insurable, and both interfaces have a defaultlabel(). javac refuses to guess. - Resolved: Parcel overrides
label()and reuses Trackable's default withTrackable.super.label().
1. The Collections Framework
List, Set and Map are interfaces; ArrayList, HashSet and HashMap implement them. Code written against List works with any implementation (Module 11).
2. Swappable payment and SMS providers
A PaymentGateway or SmsSender interface hides which vendor is used. Switching providers, or using a fake one in tests, means adding a class, not rewriting checkout.
3. Lambdas and functional interfaces
Comparator, Runnable and Predicate have one abstract method each, so a short lambda can implement them: sorting orders by price is one line (Lesson 14.1).
4. Capabilities the JDK understands
Implementing Comparable lets objects be sorted; AutoCloseable lets them be used in try-with-resources (Lesson 9.6). Your class gains abilities by making promises.
Examples are simplified. Frameworks for dependency injection rely heavily on interfaces so implementations can be configured rather than hard-coded.
One checkout for unrelated things
interface Payable {
double amount();
default String receipt() {
return getClass().getSimpleName() + ": Rs " + amount();
}
}
interface Notifiable {
String contact();
}
class Event {
final String title;
Event(String title) { this.title = title; }
}
class Ticket extends Event implements Payable, Notifiable {
Ticket(String title) { super(title); }
@Override public double amount() { return 499; }
@Override public String contact() { return "riya@college.in"; }
}
class CanteenOrder implements Payable {
private final int plates;
CanteenOrder(int plates) { this.plates = plates; }
@Override public double amount() { return plates * 60; }
}
public class Main {
public static void main(String[] args) {
Payable[] cart = { new Ticket("Tech Fest"), new CanteenOrder(3) };
double total = 0;
for (Payable p : cart) {
System.out.println(p.receipt());
total += p.amount();
if (p instanceof Notifiable n) {
System.out.println(" confirmation to " + n.contact());
}
}
System.out.println("Total: Rs " + total);
}
}extends Event implements Payable, NotifiableOne parent class, two interfaces; extends comes first.public double amount()Interface methods are public, so implementations must be too.default String receipt()Both classes get it for free; it calls each object's ownamount().p instanceof Notifiable nOnly some payables can be notified; pattern matching checks safely (Lesson 7.5).
A default method calling the object's own method
Watch the frame for Payable.receipt, code that lives in the interface, call Ticket.amount.
Worked examples: real problems, solved and traced in memory
Three business problems solved with interfaces. Run each solution, then step through it: watch interface-typed variables point at objects of unrelated classes, default methods run with this set to the implementing object, and a lambda appear on the heap as an object.
Unrelated classes, one Payable total
Problem statement
A ticket and a canteen order come from different class families, but checkout must add up both. Use a Payable interface so the total loop works for anything payable.
Ticket Rs 499; CanteenOrder 2 plates × Rs 60
Total: Rs 619.0
Approach
- Declare
interface Payable { double amount(); }. TicketandCanteenOrdereach implement it in their own way.- Store both in a
Payable[]and sumamount().
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Two default footers, one decision
Problem statement
An order alert goes out by SMS and email. Both channel interfaces provide a default footer(), so the alert class must decide. It should use the SMS footer followed by the email footer.
new OrderAlert().footer()
Reply STOP to opt out | Unsubscribe link below
Approach
SmsChannelandEmailChanneleach havedefault String footer().OrderAlertimplements both, so it must overridefooter().- Inside, call
SmsChannel.super.footer()andEmailChannel.super.footer().
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
A discount rule written as a lambda
Problem statement
The pricing team keeps changing festival offers. Instead of a new class each time, define a functional interface Offer and write today's offer (20% off) as a lambda. Apply it to a Rs 1,500 cart and a Rs 4,000 bulk order.
carts Rs 1500 and Rs 4000, offer 20% off
Pay: Rs 1200.0, bulk: Rs 3200.0
Approach
@FunctionalInterface interface Offer { double apply(double total); }has one abstract method.- Write the offer as
t -> t * 0.8; Java creates an object implementing Offer. - Call
applylike any interface method and watch the lambda's code run.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Check yourself
Quick revision
Lesson 7.7 in one screen
- Interface = contract; a class
implementsany number of interfaces (after its oneextends). - Abstract methods are implicitly
public abstract; implementations must bepublic. - Fields are constants:
public static final. No constructors, no instance fields, nonew. - Java 8:
defaultmethods (inherited, overridable) andstaticmethods (call asInterface.m()). - Java 9:
privatehelper methods inside the interface. - Two clashing defaults → the class must override; reuse one with
X.super.m(). A class's method beats a default. - Interface = capability, many per class; abstract class = family with shared state, one per class. One abstract method = functional interface = lambda-friendly.
Interview and viva questions
What is the difference between an interface and an abstract class?
A class can implement many interfaces but extend only one class. Interfaces have no instance fields or constructors (only constants), and their members are public apart from private helpers; abstract classes can have state, constructors and any access level. Use an interface for a capability or contract that unrelated classes share; use an abstract class to share state and code within a family. Since Java 8, both can contain method bodies.
Why were default methods added in Java 8?
To let interfaces evolve without breaking existing implementations. Adding an abstract method to Collection would have broken every collection class ever written; adding default void forEach(...) and default Stream stream() gave all of them working implementations automatically.
How does Java solve the diamond problem with default methods?
Rules in order: (1) a method from a class or superclass wins over any interface default; (2) a more specific interface (a sub-interface) wins over its parent; (3) otherwise, if two unrelated interfaces provide the same default, the class must override the method, and can call a particular one with InterfaceName.super.method().
Can an interface extend another interface? Can it extend a class?
An interface can extend one or more interfaces: interface SmartCard extends Payable, Trackable. It cannot extend a class. A class implementing the sub-interface must implement the methods of all of them.
What is a marker interface?
An interface with no methods, used only to mark a class as having some property, such as Serializable or Cloneable. Code checks it with instanceof. Newer code often uses annotations for the same purpose.
Practice problems
In each problem, first write the interface (the promise), then the classes that keep it. Remember that implementing methods must be public. The last three are business problems.
A Printable contract
Write an interface Printable with String print(). Implement it in Invoice and MarkSheet, two unrelated classes, and print both through a Printable[].
Invoice #INV-77 Rs 2360; MarkSheet "Riya" 86%
Invoice INV-77: Rs 2360 Mark sheet: Riya, 86%
Show solution and explanation
interface Printable {
String print();
}
class Invoice implements Printable {
@Override
public String print() { return "Invoice INV-77: Rs 2360"; }
}
class MarkSheet implements Printable {
@Override
public String print() { return "Mark sheet: Riya, 86%"; }
}
public class Main {
public static void main(String[] args) {
Printable[] queue = { new Invoice(), new MarkSheet() };
for (Printable p : queue) {
System.out.println(p.print());
}
}
}How it works: Invoice and MarkSheet share no parent class, but both promise print(). The printer queue only needs that promise, so it uses the interface type.
Implementing two interfaces
A SmartPhone is both a Camera (with click()) and a Phone (with call(String)). Implement both and use the object through each interface type.
call "98200 11111", click a photo
Calling 98200 11111 Photo saved Same object? true
Show solution and explanation
interface Camera {
String click();
}
interface Phone {
String call(String number);
}
class SmartPhone implements Camera, Phone {
@Override
public String click() { return "Photo saved"; }
@Override
public String call(String number) { return "Calling " + number; }
}
public class Main {
public static void main(String[] args) {
SmartPhone s = new SmartPhone();
Phone p = s;
Camera c = s;
System.out.println(p.call("98200 11111"));
System.out.println(c.click());
System.out.println("Same object? " + (p == c));
}
}How it works: one object, two roles. Through p only call is visible, through c only click, but both variables point to the same SmartPhone.
Interface constants
Put the GST rate and the free-delivery limit as constants in an interface ShopRules. Use them from a class to compute the bill for a Rs 450 order (delivery Rs 40 below Rs 499).
order Rs 450
Order: 450.0 GST: 22.5 Delivery: 40 Total: 512.5
Show solution and explanation
interface ShopRules {
double GST = 0.05;
int FREE_DELIVERY_ABOVE = 499;
int DELIVERY_FEE = 40;
}
public class Main {
public static void main(String[] args) {
double order = 450;
double gst = order * ShopRules.GST;
int delivery = order >= ShopRules.FREE_DELIVERY_ABOVE ? 0 : ShopRules.DELIVERY_FEE;
System.out.println("Order: " + order);
System.out.println("GST: " + gst);
System.out.println("Delivery: " + delivery);
System.out.println("Total: " + (order + gst + delivery));
}
}How it works: interface fields are implicitly public static final, so they're read as ShopRules.GST and can't be changed. (For large sets of constants, a final class or an enum is usually better; see the scenarios.)
A default method on top of the contract
Interface Rateable has abstract int[] ratings() and a default average() computed from them. Implement it for a Restaurant; it should get average() without writing it.
ratings 5, 4, 4, 3, 5
Average rating: 4.2
Show solution and explanation
interface Rateable {
int[] ratings();
default double average() {
int[] r = ratings();
if (r.length == 0) return 0;
int sum = 0;
for (int x : r) sum += x;
return (double) sum / r.length;
}
}
class Restaurant implements Rateable {
@Override
public int[] ratings() { return new int[]{5, 4, 4, 3, 5}; }
}
public class Main {
public static void main(String[] args) {
Rateable r = new Restaurant();
System.out.println("Average rating: " + r.average());
}
}How it works: the default method is written once in the interface and uses the abstract ratings(), which dispatches to Restaurant. 21 / 5 = 4.2.
Static helper in an interface
Add a static method isValidPin(String) to an interface AddressCheck that returns true for a 6-digit Indian PIN code not starting with 0. Check "411001", "041001" and "4110".
"411001", "041001", "4110"
411001 valid? true 041001 valid? false 4110 valid? false
Show solution and explanation
interface AddressCheck {
static boolean isValidPin(String pin) {
if (pin.length() != 6 || pin.charAt(0) == '0') return false;
for (char c : pin.toCharArray()) {
if (!Character.isDigit(c)) return false;
}
return true;
}
}
public class Main {
public static void main(String[] args) {
String[] pins = {"411001", "041001", "4110"};
for (String p : pins) {
System.out.println(p + " valid? " + AddressCheck.isValidPin(p));
}
}
}How it works: static interface methods are utilities called on the interface name. They aren't inherited by implementing classes, so there's no confusion about which version runs.
Resolve a default-method clash
Wifi and Bluetooth both have default String connect(). A Laptop implements both. Override connect() so it uses both defaults, one after the other.
new Laptop().connect()
Wi-Fi connected, Bluetooth paired
Show solution and explanation
interface Wifi {
default String connect() { return "Wi-Fi connected"; }
}
interface Bluetooth {
default String connect() { return "Bluetooth paired"; }
}
class Laptop implements Wifi, Bluetooth {
@Override
public String connect() {
return Wifi.super.connect() + ", " + Bluetooth.super.connect();
}
}
public class Main {
public static void main(String[] args) {
System.out.println(new Laptop().connect());
}
}How it works: without the override, javac reports that Laptop "inherits unrelated defaults for connect()". Wifi.super.connect() calls a specific interface's default; this syntax works only for interfaces the class directly implements.
Functional interface with lambdas
Declare @FunctionalInterface interface TaxRule { double tax(double amount); }. Create rules for 5% and 18% GST with lambdas, and a rule for 0% on exports. Apply each to Rs 2,000.
amount Rs 2000
food: Rs 100.0 electronics: Rs 360.0 export: Rs 0.0
Show solution and explanation
@FunctionalInterface
interface TaxRule {
double tax(double amount);
}
public class Main {
public static void main(String[] args) {
TaxRule food = amt -> amt * 0.05;
TaxRule electronics = amt -> amt * 0.18;
TaxRule export = amt -> 0;
TaxRule[] rules = { food, electronics, export };
String[] names = { "food", "electronics", "export" };
for (int i = 0; i < rules.length; i++) {
System.out.println(names[i] + ": Rs " + rules[i].tax(2000));
}
}
}How it works: an interface with exactly one abstract method can be implemented by a lambda: amt -> amt * 0.05 is a short way of writing a class with a tax method. @FunctionalInterface makes javac check there is only one. Lambdas are covered fully in Module 14.
Payment gateways behind one interface
Checkout must work with any gateway. Define PaymentGateway with boolean charge(double amount) and a default String name(). Implement RazorLikeGateway (fails above Rs 1,00,000) and BankGateway (always succeeds). Route orders above Rs 50,000 to the bank gateway.
orders Rs 1,499, Rs 75,000
Rs 1499.0 via RazorLikeGateway: paid Rs 75000.0 via BankGateway: paid
Show solution and explanation
interface PaymentGateway {
boolean charge(double amount);
default String name() {
return getClass().getSimpleName();
}
}
class RazorLikeGateway implements PaymentGateway {
@Override
public boolean charge(double amount) {
return amount <= 100000;
}
}
class BankGateway implements PaymentGateway {
@Override
public boolean charge(double amount) {
return true;
}
}
public class Main {
static PaymentGateway route(double amount) {
return amount > 50000 ? new BankGateway() : new RazorLikeGateway();
}
public static void main(String[] args) {
double[] orders = {1499, 75000};
for (double amt : orders) {
PaymentGateway g = route(amt);
System.out.println("Rs " + amt + " via " + g.name() + ": " + (g.charge(amt) ? "paid" : "failed"));
}
}
}How it works:
- Checkout depends only on
PaymentGateway; the router decides which implementation to use. - The default
name()gives every gateway a label without extra code; any gateway can override it. - Adding a third gateway changes only
routeand adds one class. (Gateway names here are invented for teaching.)
Trackable shipments of different kinds
Parcels, freight containers and food orders are unrelated classes, but customers can track all of them. Define Trackable with String status() and int etaMinutes(), plus a default String summary(). Print a tracking page for one of each.
Parcel (in transit, 180 min), Container (at port, 4320 min), FoodOrder (out for delivery, 12 min)
Parcel In transit ETA 3 hour(s) Container At port, Nhava Sheva ETA 3 day(s) FoodOrder Out for delivery ETA 12 min
Show solution and explanation
interface Trackable {
String status();
int etaMinutes();
default String summary() {
int m = etaMinutes();
String eta = m >= 1440 ? (m / 1440) + " day(s)" : m >= 60 ? (m / 60) + " hour(s)" : m + " min";
return String.format("%-10s %-18s ETA %s", getClass().getSimpleName(), status(), eta);
}
}
class Parcel implements Trackable {
public String status() { return "In transit"; }
public int etaMinutes() { return 180; }
}
class Container implements Trackable {
public String status() { return "At port, Nhava Sheva"; }
public int etaMinutes() { return 4320; }
}
class FoodOrder implements Trackable {
public String status() { return "Out for delivery"; }
public int etaMinutes() { return 12; }
}
public class Main {
public static void main(String[] args) {
Trackable[] items = { new Parcel(), new Container(), new FoodOrder() };
for (Trackable t : items) {
System.out.println(t.summary());
}
}
}How it works:
- The three classes could each extend different parents; the interface still lets one tracking page handle them.
summary()is a default method built only from the contract methods, so every implementer gets consistent formatting.- 4320 minutes = 3 days; 180 minutes = 3 hours.
Employee benefits from several interfaces
Some employees get insurance, some get a fuel allowance, some get both. Model Insured (double premiumCover()) and FuelEligible (double fuelAllowance()) as interfaces. A SalesManager implements both, a Developer only Insured. Print each person's benefits using instanceof.
SalesManager "Kiran"; Developer "Neha"
Kiran: insurance Rs 500000.0, fuel Rs 6000.0/month Neha: insurance Rs 300000.0
Show solution and explanation
interface Insured {
double premiumCover();
}
interface FuelEligible {
double fuelAllowance();
}
abstract class Employee {
final String name;
Employee(String name) { this.name = name; }
}
class SalesManager extends Employee implements Insured, FuelEligible {
SalesManager(String name) { super(name); }
public double premiumCover() { return 500000; }
public double fuelAllowance() { return 6000; }
}
class Developer extends Employee implements Insured {
Developer(String name) { super(name); }
public double premiumCover() { return 300000; }
}
public class Main {
public static void main(String[] args) {
Employee[] staff = { new SalesManager("Kiran"), new Developer("Neha") };
for (Employee e : staff) {
StringBuilder sb = new StringBuilder(e.name + ":");
if (e instanceof Insured i) sb.append(" insurance Rs ").append(i.premiumCover());
if (e instanceof FuelEligible f) sb.append(", fuel Rs ").append(f.fuelAllowance()).append("/month");
System.out.println(sb);
}
}
}How it works:
- Benefits are capabilities that cut across job roles, so they're interfaces; the job hierarchy stays a single abstract class.
- A class extends one class and implements as many interfaces as apply.
- Pattern matching checks each capability independently, so a new benefit is a new interface, not a new branch of the class tree.
Real-world scenario questions (asked in company interviews)
Interfaces decide how easy a system is to change and to test. Decide your answer first, then open the model answer.
Changing the payment gateway in a weekend
An e-commerce app calls a specific gateway's classes directly in 30 places. The business wants to move to a cheaper gateway, and maybe use both depending on the amount. How should the code have been designed?
The interviewer is checking: do you know how to program to an interface?
Show a strong answer
- Define
interface PaymentGateway { PaymentResult charge(Order o); Refund refund(String txnId); }. - Wrap each vendor in its own implementing class. Checkout depends only on
PaymentGateway. - A small routing class can choose an implementation per order (amount, method), and tests can use a fake gateway.
Avoid: replacing vendor A's classes with vendor B's in 30 places. That's the same mistake again.
Adding a method to a published interface
Your team owns an SDK interface Shipment implemented by 15 partner logistics companies. You need a new method estimatedDelivery(). Adding it as an abstract method would break every partner's build. What do you do?
The interviewer is checking: do you know why default methods exist?
Show a strong answer
- Add it as a
defaultmethod with a reasonable fallback (for example, dispatch date + standard days), so existing implementations keep compiling. - Document it and let partners override it with accurate estimates.
- In the next major version, consider making it abstract with advance notice.
Avoid: putting real business state in the interface. Defaults can only use other interface methods, not fields.
Two libraries, one default method name
Your OrderAlert class implements SmsChannel from one library and EmailChannel from another. After an upgrade, both interfaces added default String footer(), and your build fails. How do you fix it, and what does the error tell you?
The interviewer is checking: do you know the default-method conflict rule?
Show a strong answer
- javac says OrderAlert "inherits unrelated defaults for footer()". It won't pick one silently.
- Override
footer()in OrderAlert and decide: reuse one withSmsChannel.super.footer(), combine both, or write your own. - Add a test that checks the footer, since the upgrade changed behaviour you rely on.
Avoid: downgrading the library forever to dodge the conflict.
Constants interface everywhere
A codebase has interface AppConstants { int MAX_RETRIES = 3; String GST_STATE = "MH"; … } with 200 constants, and many classes implements AppConstants just to use the names without a prefix. A reviewer calls it an anti-pattern. Why, and what would you use instead?
The interviewer is checking: do you understand that interfaces define types, not storage?
Show a strong answer
- Implementing an interface makes a class a subtype of it. "OrderService is an AppConstants" is meaningless, leaks into the public API and every subclass.
- Put constants in a
finalclass with a private constructor, grouped by topic, or in enums (Lesson 10.4), and useimport staticfor short names. - Values that change by environment (GST state, retry counts) belong in configuration files, not code.
Avoid: using inheritance just to save typing a prefix.