Part 7 is mostly about threads and the core language: wait() and notify(), thread states, object locks, abstract methods, nested classes, String versus StringBuffer and the % operator. A few legacy items (Canvas, BorderLayout, Dictionary) are still here, answered briefly with what replaced them.
If your interview is close, give most of your time to Q2, Q6, Q10 and Q12. Those four come up again and again, and interviewers like to follow them with "why" questions, so make sure you can explain the reasoning and not just the one-line answer.
Q1. Can you use commas in the first and third parts of a for loop header?
Yes. In the initialisation part you can declare several variables of the same type separated by commas, and in the update part you can write several expressions separated by commas. This is handy for two-pointer loops.
char[] s = "level".toCharArray();
boolean ok = true;
for (int i = 0, j = s.length - 1; i < j; i++, j--) {
if (s[i] != s[j]) { ok = false; break; }
}
System.out.println(ok); // true
Note that Java has no general comma operator. The comma only works in these two places of a for header, not in the condition and not in ordinary expressions.
Q2. Why do wait(), notify() and notifyAll() exist, and how do they work?
They let threads co-ordinate around a shared object without burning CPU in a busy loop. A thread that cannot continue yet (say, a queue is empty) calls wait() on the shared object. It releases that object's lock and sleeps. Another thread that changes the state calls notify() to wake one waiting thread, or notifyAll() to wake all of them. A woken thread must get the lock back before it continues.
Two rules people forget: you must hold the object's lock (be inside synchronized on that object) when calling these methods, or you get IllegalMonitorStateException, and you should always call wait() inside a while loop that re-checks the condition, because threads can wake up spuriously.
synchronized void waitForData() throws InterruptedException {
while (!ready) {
wait();
}
System.out.println("got data");
}
synchronized void publish() {
ready = true;
notifyAll();
}
In real projects you would usually reach for java.util.concurrent instead: BlockingQueue, CountDownLatch, or Condition objects from a ReentrantLock.
Q3. What do we mean by an abstract method?
An abstract method has a signature but no body. It says "every concrete subclass must provide this". A class containing one must be declared abstract, and it cannot be instantiated. Abstract methods cannot be private, static or final, since all of those would stop a subclass from overriding them.
Methods declared in an interface without a body are abstract too, even if you do not write the keyword.
Q4. What are the rules for naming a .java source file?
A file can contain at most one top-level public class (or interface, enum or record), and if it has one, the file must be named after it exactly, including case. So public class Invoice goes in Invoice.java. Otherwise javac reports that the class "should be declared in a file named Invoice.java".
If the file has no public top-level type, you can name it anything you like. A file Helper.java containing two package-private classes Alpha and Beta compiles fine and produces Alpha.class and Beta.class. In practice, teams still keep one top-level class per file with a matching name, because it makes code easy to find.
Q5. How are AWT's Canvas and Graphics classes related?
Canvas is a blank component you draw on. You subclass it and override paint(Graphics g). The AWT painting system calls paint() and passes in a Graphics object, which is the drawing context you use to draw lines, shapes, text and images onto that canvas.
Today, custom drawing in Swing is done by overriding paintComponent(Graphics g) in a JPanel, and JavaFX has its own Canvas with a GraphicsContext.
Q6. What states can a Java thread be in?
Older books describe four broad states: ready, running, waiting and dead. The JDK itself defines six, in the enum Thread.State, which is what interviewers expect now:
- NEW: created, start() not called yet.
- RUNNABLE: running or ready to run (the JVM does not separate the two).
- BLOCKED: waiting to acquire a monitor lock to enter a synchronized block.
- WAITING: waiting with no timeout, for example in wait(), join() or LockSupport.park().
- TIMED_WAITING: waiting with a timeout, for example sleep(500) or wait(500).
- TERMINATED: run() has finished.
You can read the current state with thread.getState().
Q7. What does read() return once the end of the file is reached?
It returns -1. That is why InputStream.read() and Reader.read() return an int instead of a byte or char: valid data is 0 to 255 for bytes (or 0 to 65535 for chars), so -1 can safely mean "no more data". The usual loop is while ((c = in.read()) != -1).
BufferedReader.readLine() is different: it returns null at end of stream.
Q8. Is it possible to cast a Byte object to a double?
Before Java 5, no, because you cannot cast an object reference to a primitive. Since Java 5, writing (double) b where b is a Byte compiles: the compiler unboxes the Byte to a byte, then widens it to double. Calling b.doubleValue() does the same thing and is clearer.
There is one trap. If the variable's declared type is Object, then (double) obj compiles but means "cast to Double, then unbox", so it throws ClassCastException when the object is actually a Byte.
Q9. How does a static nested class differ from a non-static inner class?
A non-static inner class instance is always tied to an instance of the outer class. It holds a hidden reference to that outer object, so it can use the outer object's fields directly, and you create it with outer.new Inner(). A static nested class has no such link. It behaves like a normal top-level class that just lives inside another class for grouping, and you create it with new Outer.Nested().
A practical tip: prefer static nested classes unless you really need the outer instance. The hidden reference in an inner class can keep a large outer object alive longer than you expect.
Q10. What is the difference between String and StringBuffer?
String is immutable. Methods like concat() or toUpperCase() return a new String and leave the original unchanged. StringBuffer is a mutable sequence of characters, so append(), insert() and reverse() change the same object. StringBuffer's methods are synchronized, which makes it thread-safe but slower.
Java 5 added StringBuilder, which has the same API without synchronization. For building strings in one thread, which is almost always the case, use StringBuilder.
String s = "Java";
String t = s.concat(" 21");
System.out.println(s + " | " + t); // Java | Java 21
StringBuilder sb = new StringBuilder("Java");
sb.append(" 21").reverse();
System.out.println(sb); // 12 avaJ
Q11. Where can a private field be used?
Only inside the body of the top-level class that declares it. That includes code in nested and inner classes of the same top-level class, which can read each other's private members. Subclasses, other classes in the package and everything outside cannot see it.
The usual pattern is to keep fields private and expose behaviour through methods, or to use a record when the class is just a data carrier.
Q12. What is an object's lock (monitor), and which objects have one?
Every Java object has an intrinsic lock, also called its monitor. A thread acquires it when entering a synchronized instance method of that object or a synchronized (obj) block, and releases it on exit, even if an exception is thrown. While one thread holds it, other threads trying to enter code synchronized on the same object are BLOCKED.
Every object has one, and so does every class, through its Class object. A static synchronized method locks on MyClass.class, not on any instance. Java's intrinsic locks are re-entrant: a thread that already holds a lock can enter another block synchronized on the same object.
Q13. What was the Dictionary class?
java.util.Dictionary is an abstract class from Java 1.0 for storing key-value pairs, with methods like put(), get(), keys() and elements(). Hashtable extends it.
It is obsolete. Its own documentation says new code should implement the Map interface instead, so use HashMap, TreeMap or ConcurrentHashMap.
Q14. How does BorderLayout arrange components?
It divides a container into five regions: NORTH, SOUTH, EAST, WEST and CENTER. Each region holds at most one component. North and south get their preferred height and stretch across the width; east and west get their preferred width; center takes all the remaining space. It is the default layout for Frame and for a JFrame's content pane.
The same five-region idea lives on in JavaFX as BorderPane.
Q15. What does the % operator do?
% is the remainder operator. a % b gives what is left after dividing a by b. In Java the result takes the sign of the left operand, which surprises people who expect a mathematical modulo. It also works on double and float.
System.out.println(7 % 3); // 1
System.out.println(-7 % 3); // -1
System.out.println(7 % -3); // 1
System.out.println(Math.floorMod(-7, 3)); // 2
System.out.println(5.5 % 2); // 1.5
Use Math.floorMod() when you need a result that is never negative, for example when wrapping an index around a circular array.
Quick revision
- Call wait() and notify() only while holding the lock, and always wait() inside a while loop.
- Thread.State has six values: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.
- A public top-level class must live in a file with the same name; otherwise the file name is free.
- String is immutable; use StringBuilder for building text, StringBuffer only if you truly share it across threads.
- Every object and every class has a monitor; static synchronized locks on the Class object.
- In Java, -7 % 3 is -1; use Math.floorMod for a non-negative result.
Frequently asked questions
Should I learn wait/notify if java.util.concurrent exists?
Yes, at least well enough to explain it. Interviewers use it to check that you understand locks and thread states. Then say what you would use in production, such as a BlockingQueue, which shows you know both levels.
What follow-up questions come after String vs StringBuffer?
Expect "why is String immutable" (security, caching of hash codes, the string pool), "what is the string pool", and "what does + do in a loop". Practise all three together.
How do I remember the thread states?
Draw them as a diagram once: NEW to RUNNABLE on start(), RUNNABLE to BLOCKED on a lock, to WAITING or TIMED_WAITING on wait/sleep/join, and back, then TERMINATED. Drawing it yourself beats memorising a list.
Comments
Post a Comment