skip to content

When a simple type name could be resolved several ways, what is Java's precedence among same-package types, single-type imports, and wildcard imports?

level: middleimportance: should knowfreq 48%

answer

  1. Specific beats general: single-type import / same-package > wildcard
  2. Single import out-ranks wildcard — resolves the clash, no error
  3. Two single-type imports of same simple name = always illegal
  4. Two wildcards clash only AT the point of use
  5. Same-package/same-file type shadows even java.lang

basics

~20 s

Java looks for a name in this order of strength: a type in the same package or one you imported by name beats a wildcard import. So a single-type import always wins over *, and a wildcard never overrides an explicitly named type.

solid answer

~50 s

Java resolves a simple type name with a clear precedence. A type declared in the **current compilation unit** or **same package**, and any type brought in by a **single-type import**, take priority over wildcard (on-demand) imports. Concretely: if you `import java.awt.*;` (which contains `List`) but also `import java.util.List;`, the simple name `List` unambiguously means `java.util.List` — the single-type import wins, no error. The same is true for the package the file itself is in: a type in your own package shadows a wildcard-imported type of the same simple name. Conflicts only become **compile errors** when two sources of *equal* strength collide — e.g. two single-type imports of the same simple name (always illegal), or a simple name reachable only through two different wildcard imports. The rule of thumb: 'more specific beats less specific', and you fix an ambiguous wildcard situation by adding an explicit single-type import.

go deeper

for a junior

Can state the gist: a named (single-type) import beats *, so adding an explicit import fixes a wildcard clash.

for a middle

Lays out the full precedence (same-file/same-package & single-type imports > wildcards > java.lang) and knows when ambiguity is an error vs. fine.

for a senior

Distinguishes the two error cases (two single-type imports = always illegal; two wildcards = error only at use), and explains shadowing of java.lang by same-package/single imports.

for a principal

Reasons about how these rules interact with large codebases and package evolution — e.g. why a downstream package adding a type can turn previously-fine wildcard code into an ambiguity, making wildcard imports a hidden compatibility hazard.

## The problem A file refers to a type by its **simple name**, e.g. `List`. The compiler must decide which actual type that names. Several mechanisms can supply a `List`: 1. A type **declared in this same file** (compilation unit). 2. A type in the **same package** as this file (no import needed — same-package types are always visible by simple name). 3. A **single-type import**: `import java.util.List;`. 4. An **on-demand (wildcard) import**: `import java.awt.*;` where `java.awt.List` exists. 5. The **implicit** `import java.lang.*;` (always present) and, in newer Javadoc/module contexts, automatic ones — but `java.lang` is the relevant implicit one. ## The precedence ladder (most specific wins) The Java Language Specification defines a search order. In practical terms, strength increases like this: 1. **Weakest: wildcard imports and the implicit `java.lang.*`.** These are 'on-demand'. 2. **Stronger: types of the current package and single-type imports.** A single-type import or a same-package/same-file type **shadows** any wildcard-imported type of the same simple name. So: ```java import java.util.*; // has List import java.awt.*; // also has List import java.util.List; // single-type import // 'List' now means java.util.List — unambiguous, compiles fine ``` The single-type import is more specific than either wildcard, so it wins. Likewise, a `class List {}` you declare in the file, or a `List` class living in your own package, beats wildcards. Note a subtlety even within the implicit rules: a single-type import or same-package type can **shadow** a type from `java.lang`. If your package contains a class named `String`, your `String` (same package) is used, not `java.lang.String` — generally a terrible idea, but it shows the precedence. ## When it becomes an error Ambiguity errors occur only when **two sources of equal strength** both supply the simple name and neither is more specific: - **Two single-type imports of the same simple name** — *always* illegal, even if you never use the name. `import java.util.List; import java.awt.List;` → compile error. - **A simple name reachable only via two wildcard imports** — only an error **at the point of use**. `import java.util.*; import java.awt.*;` compiles until you actually *write* `List`; then it's 'reference to List is ambiguous'. You resolve a wildcard ambiguity by adding a single-type import (which out-ranks both wildcards), or by using the fully qualified name at the use site. ## Mental model Think: **'declared-or-named beats wildcard.'** The compiler prefers the most specific information you gave it. Wildcards are last-resort fallbacks, which is exactly why relying on them is fragile.

  • You have `import java.util.*;` and `import java.awt.*;`, both containing `List`. How do you make `List` mean `java.util.List`?
    Add `import java.util.List;`. A single-type import is more specific than either wildcard and shadows them, so `List` resolves unambiguously to `java.util.List`.
  • Is `import java.util.List; import java.awt.List;` legal if you never reference `List`?
    No. Two single-type imports of the same simple name are a compile error unconditionally — it doesn't matter whether the name is ever used.

saying these in an interview costs you the question

  • Thinking a wildcard can override an explicit single-type import
  • Believing `import java.util.*; import java.awt.*;` errors immediately rather than at use
  • Claiming two single-type imports of the same name are OK if you never use it
  • Forgetting same-package types are visible without any import

context