16 programming language interview questions on Java, each with the correct answer and a full explanation.
What does this print?
String a = "hi";
String b = new String("hi");
System.out.println((a == b) + " " + a.equals(b));
Show answer
Answer
false true
== compares references and new String always creates a new object. equals compares characters. Literals are interned, which is why == sometimes seems to work.
On a default HotSpot JVM (no AutoBoxCacheMax flag), what does this print?
Integer p = 127, q = 127;
Integer r = 128, s = 128;
System.out.println((p == q) + " " + (r == s));
Show answer
Answer
true false
The JLS guarantees that boxing values from -128 to 127 reuses the same object, so p and q are identical. 128 is outside the default cache, so it boxes to new objects. Always compare boxed values with equals.
static int f() {
int x = 1;
try {
return x;
} finally {
x = 2;
}
}
Show answer
Answer
1
The return value is evaluated and saved before finally runs. Changing the local afterwards does not affect it. A return inside finally would override it.
Java integer division truncates toward zero and % takes the sign of the dividend. Python floors instead and prints -4 1. This matters for negative indexes and hashing into buckets: use Math.floorMod.
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
list.remove(1);
System.out.println(list);
Show answer
Answer
[1, 3]
remove(int index) is a more specific match than remove(Object) for an int literal, so it removes index 1, which holds 2. Use remove(Integer.valueOf(1)) to remove by value.
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
for (String s : list) {
if (s.equals("a")) list.remove(s);
}
Show answer
Answer
ConcurrentModificationException
The for each loop uses an iterator, and removing through the list bumps its modification count, so the next call to next() fails fast. Use list.removeIf or Iterator.remove.
In Java, a class overrides equals but not hashCode. Two equal instances are added to a HashSet. What is set.size() most likely to be?
Show answer
Answer
2
HashSet looks up the bucket by hashCode first. Without an override, the identity hash puts equal objects in different buckets, so both are kept. The Object contract requires equal objects to have equal hash codes.
A lazy singleton uses double checked locking. What makes it correct under the Java memory model?
Show answer
Answer
Declaring the instance field volatile
Without volatile, another thread can see a non null reference to an object whose constructor writes are not yet visible. volatile adds the happens before edge. A holder class idiom avoids the pattern entirely.
In Java, many threads count words into a shared map. Which update is thread safe and loses no counts?
Show answer
Answer
counts.merge(word, 1, Integer::sum) on a ConcurrentHashMap
ConcurrentHashMap makes single operations atomic, and merge does the read and write as one. A separate get then put can interleave and lose updates even on a concurrent map. volatile only covers the field reference.
In Java, an instance method marked synchronized updates a static counter, and each thread uses its own instance. Is the counter safe?
Show answer
Answer
No, each call locks a different instance
A synchronized instance method locks this. Different instances mean different locks, so the static field races. Use a static synchronized method, a shared lock or an AtomicInteger.