Loading...
Loading...
Java interview guide
Classes, inheritance, polymorphism, abstraction, interfaces and encapsulation. Every answer is short enough to say aloud, and every question links to the lesson that teaches it.
59 questionsLast updated
Inheritance couples the child to every public method of the parent, to its internal workings, and for the object's whole life. Composition couples me only to the methods I call, lets me hide what does not fit, and lets me swap the part at run time through an interface. It also avoids the one-parent limit and the subclass explosion.
Lesson: Composition vs inheritance: choosingIntern extends Employee?No, because an object can never change its class; I would have to create a new object and copy its data, and every reference to the old one would be stale. I would give Employee a PayRule field and swap it in promote(). The changing part becomes a delegate.
I write the requirements as short sentences, then pick out the nouns as candidate classes or fields and the verbs as methods. For each pair of classes I decide the relationship: IS-A, composition, aggregation, association, or an interface delegate if behaviour varies. I sketch a class diagram and then code the small classes first.
Lesson: Design classes from a real problemA god class is one huge class that holds most of a program's data and does most of its jobs, so every change touches it and its data easily gets out of step. A FoodApp with arrays of names, prices and orders is the classic example. I split it by job into classes such as Restaurant, Order and Payment.
Lesson: Design classes from a real problemA CountingList that extends a list and overrides both add and addAll to count items. The parent's addAll calls add internally, so my overridden add runs too and every bulk add is counted twice. Making the list a private field and delegating fixed it, because the inner list calls its own add.
ParkingLot creates its own Slot objects, so slots are composition. park takes the first free slot or refuses when full; leave frees the slot and asks a FeeRule interface for the charge. Because fees are a delegate, a weekend or EV rule can be plugged in without changing the lot.
Object. The compiler adds extends Object for any class without an extends clause, so class Pen {} and class Pen extends Object {} mean the same thing.
Object o = new Student();, what does o.getClass() return? Is it Object?It returns the Student class, not Object. getClass() looks at the real object at run time, while the reference type Object only matters to the compiler.
toString() print the text or return it? Why?Return it. The caller decides what to do with the text: print it, join it, or write it to a log. A void method that prints cannot even override toString(), because the return type must be String.
toString() without repeating the parent's fields?Call super.toString() and add only the new fields, like return super.toString() + ", roll " + roll;. If the parent uses getClass().getSimpleName(), the class name is also right for every child.
==?No. == on references is true only when both point to one object, so objects made by two new calls are never ==, whatever their fields hold. Only a copied reference, like Student c = a;, makes a == c true.
equals()?When two separate objects with the same data should count as the same thing, like two Student objects with the same roll number. Without overriding, equals() from Object only checks ==, so searches and comparisons by data fail.
equals() return when the argument is null? Why not just let it throw?It must return false. Callers use equals() freely, often on values that may be null, and a comparison should never crash the program. The recipe checks obj == null early, and Objects.equals handles null fields.
hashCode() and what is it used for?It returns an int computed from the object. Hash-based collections like HashSet and HashMap use it to pick a bucket, so they only compare an object with the few objects in that bucket instead of all of them.
hashCode()? Which fields do you use?I use exactly the fields that equals() compares and combine them with Objects.hash(roll, name). By hand I would write something like 31 * roll + name.hashCode(). A field that equals() ignores must never be in hashCode().
Customer objects with == and it returns false for the same customer. What would you tell them?== checks whether both references point to one object, and these are two objects. To compare data they should call equals(), and Customer must override equals() (and hashCode()) to compare the customer id.
Product whose price changes every day?By its product id only: a final int id used in both equals() and hashCode(). The product with a new price is still the same product, and its hash code never changes, so it is safe in hash-based collections.
Aliasing means two or more variables point to the same object, which is what b = a gives you with object variables. Only the reference is copied, so a change made through one name is visible through every other name.
current = backup;. It works once and then fails. Why?After current = backup; both variables point to the backup object, so the next edit changes the backup itself. Restore with a new copy each time, for example current = new Profile(backup.name, backup.city);, so the backup is never edited.
Because the field list then lives in one place. If a field is added, I update one constructor instead of hunting for every copy in the code. It can also read private fields, which outside code cannot.
The first line is super(other), which lets the parent's copy constructor copy the parent's fields. That works because a child object can be passed where a parent is expected. Then I copy the child's own fields, cloning any arrays.
When every shared field is a primitive, an immutable object like String, an enum constant, or an object shared on purpose. If nothing shared can change, or a shared change is what we want, a shallow copy is correct and cheaper.
It costs more memory and time, and it can be wrong. If a Course points to a shared Teacher and I copy the teacher, I get two "Prof. Rao" objects, and a phone number update reaches only one. I copy what the object owns and share what it only points to.
clone() but forget implements Cloneable?The code compiles, but super.clone() throws CloneNotSupportedException at run time, with the class name in the message. Adding implements Cloneable to the class header fixes it.
clone() on any object, like student.clone(), from another class?Because Object.clone() is protected. Code outside the class only sees it after the class overrides it as public; otherwise the compiler says clone() has protected access in Object. Arrays are the exception: their clone() is already public.
That every field is copied, ideally by chaining to the main constructor with this(...). That arrays and owned objects get their own copies, while Strings, enums and parts shared on purpose are simply assigned. And that it reads from other, not from the new object's own fields.
clone() or a copy constructor?A copy constructor, usually with a copyOf factory. It needs no marker interface, cast or checked exception, runs the constructor's checks, and works with final fields. I would use clone() mainly where the code already relies on it, and I use array.clone() freely.
Yes. After UpiPayment u = new UpiPayment(); Payment p = u; Object o = u; there is one object and three views of it, so u == p is true. Each view allows a different set of calls, but the object type stays UpiPayment for its whole life.
I use the widest type that still declares every member the method uses. If the method only needs amount and mode(), a Payment parameter accepts every kind of payment, now and later. I narrow it to a child type only when the method really needs a child-only member.
(Dog) a compile even when a points to a Cat?The compiler only knows the reference type. An Animal variable could hold a dog, so the cast might work, and javac allows it. The real check happens at run time, when the JVM sees the object is a Cat and throws ClassCastException.
null?Casting null to any reference type works and gives null; there is no ClassCastException. The problem comes later: calling a method on that null reference throws a NullPointerException.
instanceof?Pattern matching for instanceof is a type test that also declares a variable, as in if (a instanceof Dog d). When the test is true, Java casts the object and stores it in the pattern variable d, so no separate cast is written. It needs Java 16 or newer.
instanceof always bad design, then?No. It is the right tool when you truly do not know the type, like in equals(Object o), or when only some objects have an optional extra feature. The smell is a long chain that picks behaviour by type, which overriding does better.
Parent p = new Child(); where both have a field x and Child overrides getX(), what do p.x and p.getX() return?p.x returns Parent's x, because fields follow the reference type. p.getX() runs Child's override, which reads Child's x. So the two can be different values for the same object.
Keep fields private in the parent and never redeclare them in the child. If the child needs a different starting value, pass it with super(value). If the value is computed differently per type, expose it through a method and override that method.
Integer is immutable, how does i++ work on an Integer variable?Java unboxes the value, adds 1, and boxes the result into a new Integer object. Then the variable i points to that new object. Any other variable that pointed to the old Integer still sees the old value.
An immutable class is a class whose objects can never change after construction. I declare it final, make every field private final, write no setters, check the values in the constructor, copy mutable inputs and outputs such as arrays, and make every "change" method return a new object.
In the constructor, because it is the only place where fields get their values. If every "change" method also goes through the constructor, like return new Rupees(amount - other.amount);, every object that exists has passed the check. The rest of the program can trust it without checking again.
A record is a special kind of class for immutable data, declared like record Student(String name, int marks) { }. From its components Java writes private final fields, a constructor, accessors, equals(), hashCode() and toString(). Records arrived in Java 16.
I would not use a record when the object must change over time, like a bank account or a cart, when I need inheritance, or when some data should stay hidden, because accessors and toString() expose every component. I also avoid arrays in records, since equals() compares them by reference and the accessor leaks them.
A static nested class belongs to the outer class, needs no outer object (new Outer.Nested()), and cannot read instance fields directly. An inner class object is tied to one outer object (outer.new Inner()) and can read and change that object's fields, even private ones. I make nested classes static unless they really need the outer object.
The anonymous object keeps its own copy of the variable's value, and it may run later, after the method has changed things. If the variable could change, the copy and the original would disagree. Java avoids that confusion by allowing only variables that never change; lambdas follow the same rule.
Lesson: Nested classes: static nested, inner and anonymousClassCastException in real code?First, by not needing the cast: put the behaviour in an overridden method and call it through the parent type. When a cast is truly needed, I check first with if (x instanceof Dog d), which tests and casts in one step. I do not catch ClassCastException to hide a wrong assumption.
instanceof a code smell?Not by itself. It is fine in equals(Object o) and for optional features only some objects have. It becomes a smell when long chains pick behaviour by type in many places; then overriding is cleaner and safer.
is-a shows up as extends (or implements for an interface): a SavingsAccount is an Account. has-a shows up as a field of another class type: an Order has a Customer field. If a class only receives another object as a method parameter, it just uses it for a moment.
Fields first. They tell me what the object remembers, its state, and which other objects it holds. Then the constructors show what it needs to be created, and the methods show what it does with that state.
Lesson: Read an unfamiliar OOP programthis(...) or super(...) be the first statement in a constructor? Can a constructor have both?The parent part, or the full constructor of the same class, must finish setting up the object before any other code touches it. So Java 17 requires the call on the first line, and that means only one of them. If I need both, I chain with this(...) to one full constructor, and that one calls super(...).
Order a unique ID automatically, without the caller passing it?I keep a private static int nextId counter in Order and a private final int id field. In the constructor, or as a field initializer, I write id = nextId++;. The counter is shared by all orders, and each order keeps its own ID that cannot change later.
No. A private method is not visible in the child, so a method with the same name there is a new, separate method; the parent keeps calling its own. A final method is visible but locked: overriding it is a compile error.
Lesson: Trace inheritance and polymorphismA code smell is a sign in working code that the design is weak: the program compiles and gives the right output, but changing it later is hard or risky. Two examples: a god class that does everything, and an instanceof chain that must be edited for every new type.
class Car extends Engine to reuse start(). What would you say?A car is not an engine, it has one, so this fails the is-a test. It lets a Car be passed anywhere an Engine is expected and stops us from swapping the engine. I would give Car a private Engine field and a start() that delegates to engine.start().
It happens when I use . on a reference that is null, usually a field of object type that was never set: a constructor forgot it, or shadowing like customer = customer; hid it. I prevent it by setting every required field in every constructor, making it final so javac checks that, and rejecting null early with an exception that has a clear message.
null for a name you clearly set in the constructor. What is your first guess, and how do you confirm it?My first guess is shadowing: name = name; inside the constructor, where both sides mean the parameter. I confirm it by reading the constructor, or by printing this.name at its end. The fix is this.name = name;.
If the types are truly the same kind of thing and share fields or code, I use an abstract class. If unrelated classes only share an ability, like being refundable or chargeable, I use an interface, since a class can implement many interfaces but extend only one class. Often I use both: an interface for the ability and an abstract class for shared code.
Lesson: Design classes from requirementsIn my movie-booking project: encapsulation, a Seat keeps booked private and changes it only through book(). Inheritance, ReclinerSeat extends Seat. Polymorphism, a Booking adds up seat.price() and each seat type returns its own price. Abstraction, Booking works with a Discount interface and does not care which offer it is.
A class should have one job, so only one kind of change touches it. If a Student class stores marks, prints the report card and sends SMS, a new SMS format means editing the same class that holds the marks rules. I would split it into Result, ReportCardPrinter and ParentSms.
UnsupportedOperationException from half its methods. What is wrong?The interface is too fat, which breaks interface segregation, and callers of that interface may also hit Liskov-style surprises. I would split the interface into smaller ones by ability, like Printer and DocScanner, so each class implements only what it really supports.
By job: canteen.model for menu items and students, canteen.payment for the wallet and its exception, canteen.order for orders, offers and checkout, and canteen.app for main. This makes classes easy to find and shows which parts depend on which. Only what other packages use is public; the rest stays package-private or private.
Mostly the edges: main and the printing in Canteen would move to the new interface, and storing orders would go in a new class. The core classes, MenuItem, Wallet, Order and OfferRule, hold the rules and do not print or store anything, so they stay the same. That is why I keep rules separate from input and output.
Each lesson has quizzes, practice and more interview questions on the same topic.
Open the first lesson