What Java wildcard does Kotlin's star-projection (`List<*>`) map to, and how does it differ from a raw type?
answer
- `<*>` = Java `<?>` unbounded wildcard
- out-param star = out UpperBound; in-param star = in Nothing
- star-projection is SAFE; raw type is NOT
- Kotlin has no raw types
- Map<*, *> projects each param independently
basics
~10 sList<*> maps to Java's unbounded wildcard List<?>. It means 'a list of some specific but unknown type'. Unlike a raw type List, it stays type-safe: you can read Any? but can't add elements.
solid answer
~40 sKotlin's star-projection `Foo<*>` corresponds to Java's unbounded wildcard `Foo<?>`. For `out`-parameters it means `Foo<out UpperBound>` (you read the declared upper bound, e.g. `Any?`); for `in`-parameters it becomes `Foo<in Nothing>` (you cannot pass anything in). The critical distinction from a Java **raw type** (`List` with no type argument) is that `List<*>` / `List<?>` remains type-checked: the compiler still tracks that there IS a type argument, just unknown, so unsafe writes are rejected. Raw types disable generics entirely and only generate unchecked-warning escape hatches. In bytecode, `List<*>` compiles to `List` after erasure but the source-level wildcard preserves the safety guarantees the raw type throws away.
code
kotlin · 5 linesfun describe(c: Collection<*>) {
println("size = ${c.size}") // OK
val any: Any? = c.firstOrNull() // OK: reads Any?
// c.add("x") // compile error: unknown element type
}go deeper
Knows <*> maps to Java <?> and that you can't add to it.
Explains the projection to out UpperBound / in Nothing and the safety contrast with raw types.
Notes erasure equivalence yet compile-time safety difference, and how Kotlin treats Java raw types as platform star-projections.
Reasons about API ergonomics of accepting <*> vs a concrete projection and the migration story from raw-type Java code.
## What star-projection means `Foo<*>` is Kotlin's way of saying "`Foo` of *some* specific type, but I don't know or care which." It is safe because the compiler enforces what you can do without knowing the exact argument. For a declaration `interface Foo<out T : TUpper>`: - `Foo<*>` is equivalent to `Foo<out TUpper>` — reads yield `TUpper` (often `Any?`). For `interface Bar<in T>`: - `Bar<*>` is equivalent to `Bar<in Nothing>` — you cannot safely *write* anything, because the real type could be anything. ## Mapping to Java `Foo<*>` maps to Java's **unbounded wildcard** `Foo<?>`. Both mean "unknown type argument, type-safe." ```kotlin fun printSize(list: List<*>) = println(list.size) // Java: List<?> fun firstOrNull(list: List<*>): Any? = list.firstOrNull() // reads Any? ``` You can read `Any?` out, but `list.add(x)` is rejected — the unknown element type might not accept `x`. ## Difference from a Java raw type A **raw type** is a generic class used with NO type arguments at all — `List` instead of `List<String>` or `List<?>`. Java keeps raw types only for backward compatibility with pre-generics code. | | `List<?>` / `List<*>` | raw `List` | |---|---|---| | Type-checked | Yes | No (generics suppressed) | | `add(x)` | Compile error (safe) | Allowed with unchecked warning (unsafe) | | Reading | Returns `Any?` / `Object`, tracked | Returns `Object`, untracked | | Intent | "unknown but real type" | "opt out of generics" | Kotlin has **no raw types** — when consuming a Java raw type, Kotlin sees it as a `(Mutable)List<*>!` platform type. So star-projection is the principled, safe alternative the raw type lacks. ## Erasure At the JVM level both `List<*>` and raw `List` erase to `java.util.List`. The difference is entirely a *source/compile-time* safety contract — erasure doesn't carry the wildcard. ## Multiple parameters Each type parameter is projected independently: `Map<*, *>` = `Map<?, ?>`, and you can mix — `Map<String, *>` = `Map<String, ?>`.
- Why does `MutableList<*>.add(x)` fail to compile?The real element type is unknown; it could be `List<Int>`, so accepting any `x` would be unsafe. The `in` position is projected to `Nothing`.
- What platform type does Kotlin assign to a Java raw `List`?It is seen as `(Mutable)List<*>!` — a flexible/platform type with a star-projected argument.
A sealed mystery box labeled 'contains exactly one kind of thing' (star) vs. an open box with the label torn off (raw type).
saying these in an interview costs you the question
- Equating star-projection with a raw type
- Claiming you can add elements to a `List<*>`
- Saying `<*>` maps to `? extends Object` always (it depends on declared bounds/variance)
- Thinking erasure distinguishes `List<*>` from raw `List` at runtime