What is the difference between a raw type, a parameterized type, and Box<Object>, and why does using a raw type defeat the purpose of generics?
answer
- Raw = no angle brackets (Box); checking OFF; unchecked warning
- Parameterized = Box<String>; checking ON
- Box<Object> is parameterized, NOT raw — checking stays on
- Raw assignable to any Box<...> (the safety hole); Box<Object> != Box<String>
- Want 'any type' safely? use wildcard Box<?>, not raw
basics
~20 sA raw type is using a generic class with no type argument, like Box. A parameterized type supplies one, like Box<String>. A raw Box turns off generic type checking and forces casts, bringing back the runtime errors generics were meant to prevent, so the compiler warns against it. Box<Object> still keeps type checking on.
solid answer
~50 sA raw type is a generic class used without any type argument: just Box. A parameterized type supplies the argument: Box<String>. Raw types exist only for backward compatibility with pre-generics (Java 4) code; using one switches off generic type checking for that reference, so the compiler stops enforcing what you put in and requires casts coming out — reintroducing the ClassCastException risk generics removed. You also get an 'unchecked' warning. Box<Object> is *not* the same as raw Box: it is a fully parameterized type where the element type is Object, so type checking stays on. The key practical difference is assignment compatibility and method signatures — passing a raw Box anywhere a Box<String> is expected compiles with a warning and can corrupt type safety, whereas Box<Object> and Box<String> are unrelated parameterized types the compiler keeps strictly separate. Rule of thumb: never use raw types in new code.
go deeper
Recognizes that Box with no <> is a raw type and Box<String> is the proper form, and that raw types produce warnings.
Clearly distinguishes raw vs Box<Object> vs Box<String>, explains why raw defeats safety, and knows to use Box<?> for 'any type'.
Explains assignment compatibility (raw assignable to any Box<...>; invariance keeps Box<Object> separate from Box<String>) and that raw usage erases even unrelated generic signatures.
Sets policy (treat unchecked as errors, ban raw types in new code, wildcard guidance) and reasons about safe interop with legacy pre-generics APIs at module boundaries.
## Three things people confuse For `class Box<T> { ... }` there are three distinct ways the name `Box` can appear, and conflating them is a classic source of bugs and warnings. ### 1. Parameterized type — `Box<String>` You supply a concrete **type argument**. The compiler enforces it everywhere: `set` only accepts `String`, `get` returns `String` with no cast. This is the normal, intended usage. ### 2. Raw type — `Box` You use the generic class with **no** angle brackets at all: ```java Box b = new Box(); // raw type b.set("hi"); b.set(42); // compiles! no type checking Object o = b.get(); // returns Object; you must cast to use it ``` A **raw type** is a generic type used without type arguments. It exists *only* for backward compatibility: code written before generics (Java 1.4 and earlier) used `Box` with no parameters, and that code still had to compile after generics were added in Java 5. Using a raw type **turns off generic type checking** for that reference. The compiler emits an **unchecked warning** because it can no longer guarantee type safety. ### 3. `Box<Object>` — a parameterized type, NOT raw This is the subtle one. `Box<Object>` is a *fully parameterized* type whose argument happens to be `Object`. Type checking is **still on**: ```java Box<Object> b = new Box<>(); b.set("hi"); // ok, String is an Object b.set(42); // ok, Integer is an Object (autoboxed) Object o = b.get(); // returns Object — but checking was never disabled ``` The difference from raw is visible in **assignment and signatures**: ```java void takesStringBox(Box<String> b) { ... } Box raw = new Box(); // raw Box<Object> objBox = new Box<>(); Box<String> strBox = new Box<>(); takesStringBox(raw); // compiles, with an UNCHECKED WARNING (unsafe) takesStringBox(objBox); // COMPILE ERROR: Box<Object> is not Box<String> takesStringBox(strBox); // ok ``` A raw `Box` is assignable (with a warning) to *any* `Box<...>`, which is exactly how it punches a hole in type safety. `Box<Object>` is a distinct parameterized type and the compiler keeps it strictly separate from `Box<String>` — generics are **invariant**, so `Box<Object>` is *not* a supertype of `Box<String>`. ## Why raw types defeat the purpose Generics exist to move type errors from **runtime** (`ClassCastException`) to **compile time**. A raw type opts out of that: ```java List raw = new ArrayList(); // raw List raw.add("hello"); raw.add(42); List<String> strings = raw; // unchecked warning String s = strings.get(1); // ClassCastException at RUNTIME — the bug generics were meant to catch ``` The whole investment in generics — compile-time safety, no casts — is thrown away the moment you use a raw reference, and the danger can propagate to other, properly-typed code through assignment. ## How the compiler treats raw types When you use a raw type, the compiler erases **all** the generics in that type's methods, not just the missing argument — so even methods that didn't mention `T` lose their generic signatures. This is why raw usage is more dangerous than it looks. ## Practical guidance - **Never** introduce raw types in new code. If you truly mean "any type," use a **wildcard** `Box<?>` (which keeps type safety: you can read as `Object` but cannot put non-null values in) rather than raw `Box`. - Reserve `Box<Object>` for when you genuinely want a box of arbitrary objects *and* you want to insert into it. - Treat unchecked warnings as errors in your build where possible. ## Why it matters Knowing the raw / `Box<?>` / `Box<Object>` distinction is the difference between safely interoperating with legacy code and silently reintroducing the runtime cast failures generics were designed to eliminate.
- If you want a method that accepts a Box of any element type, what should the parameter be?Box<?> (an unbounded wildcard), not raw Box. Box<?> keeps type safety: you can read elements as Object and call type-independent methods, but the compiler forbids inserting anything except null, preventing the corruption a raw type allows. Raw Box would compile away all checks.
- Why is Box<String> not assignable to Box<Object> even though String is an Object?Generics are invariant: parameterized types do not inherit along their type argument's hierarchy. If Box<String> were a Box<Object>, you could call set(42) through the Box<Object> view and corrupt the String box. Invariance prevents that; use wildcards (? extends/? super) when you need controlled variance.
saying these in an interview costs you the question
- Treating Box<Object> as equivalent to raw Box — Box<Object> keeps type checking
- Assuming Box<Object> is a supertype of Box<String> (generics are invariant)
- Thinking raw types are fine 'because they compile' — they only warn, and reintroduce runtime ClassCastException
- Using raw Box to mean 'any type' instead of the safe wildcard Box<?>