library
intermediateVarargs & Heap Pollution
Understand variable-length arguments, their array backing, and the safety concerns with generic varargs.
Type... lets a method take any number of arguments. The compiler builds an array at the call site.
Varargs = a box that can hold any number of items. But if the box label says 'Strings Only' (generic), the actual box material is 'Any Object' (erasure) — someone could sneak in an Integer.
Key Concepts
1
int sum(int... nums) {
int t = 0;
for (int n : nums) t += n;
return t;
}2
sum(1, 2, 3); // compiled as sum(new int[]{1, 2, 3})
sum(); // an empty array, not null
sum(new int[]{1, 2}); // passing an array directly also works3
The rules.
one varargs parameter per method
it must be last
varargs is the last phase of overload resolution4
That last point matters.
void f(int a, int b) { print("two"); }
void f(int... a) { print("varargs"); }5
f(1, 2); // "two" -- the exact match wins6
So adding a varargs overload never steals calls from an existing method, which is why printf could be
added safely.
printf
7
Heap pollution is the generic case. Because of erasure, a T... parameter is really an Object[]:
T...Object[]
8
@SafeVarargs
static <T> List<T> listOf(T... items) { return Arrays.asList(items); }9
Without @SafeVarargs, the compiler warns at every call site, because the array's real type is Object[]
and nothing stops unsafe writes into it.
@SafeVarargsObject[]
10
Here is how it actually breaks:
static <T> T[] toArray(T... args) { return args; }11
String[] s = toArray("a", "b"); // ClassCastException at runtime12
The array created was Object[], and assigning it to String[] fails — at the assignment, with no cast in
sight.
Object[]String[]
13
So @SafeVarargs is a promise, not a fix. Only apply it when the method merely reads the array. Never
when it stores the array, returns it, or hands it to anything else. It is allowed on static, final and
private methods, because those cannot be overridden by something unsafe.
@SafeVarargsstaticfinalprivate
14
Common examples: List.of(E...), String.format(String, Object...),
Collections.addAll(Collection, T...).
List.of(E...)String.format(String, Object...)Collections.addAll(Collection, T...)
15
What the interviewer is probing.1. "What is heap pollution and how do generic varargs cause it?" Probing: whether you
understand the warning rather than suppressing it. Stalls: "It is just a warning." Moves up:
erasure makes a T... parameter an Object[] at runtime, so the array can be given values of the wrong
type and a later read throws from a line with no cast.
16
2. "When is @SafeVarargs actually safe to apply?" Probing: whether it is a promise or a fix.
Stalls: "When the warning is annoying." Moves up: only when the method just reads the array —
never when it stores it, returns it, or passes it on.
17
3. "Given f(int, int) and f(int...), which does f(1, 2) call?" Probing: where varargs sits in
overload resolution. Stalls: "The varargs one." Moves up: the fixed-arity method — varargs is
the last phase, which is why adding one never steals existing calls.
18
4. "Why can a varargs parameter only be last?" Probing: parsing. Stalls: "Style." *Moves
up:* the compiler could not tell where the variable-length list ended and the next parameter began.