Concepts / Packages and Full Class Names

Packages and Full Class Names

An import directive lets you write a simple class name in the rest of a Java file instead of the full name, but it does not change the class or its type.

  • Programming

Why Full Names Get Heavy

Suppose you want to use the Color class from the java.awt package in a program. Its full name is java.awt.Color, and that full name is what Java needs in order to identify the class exactly. Writing the full name everywhere is precise but heavy. A program that uses several classes from several packages quickly becomes hard to read. Java offers a way to keep the precision while writing shorter names in the body of your code. This article looks at that mechanism, and at one of the most common wrong ideas people form about it.

What do you think happens?

If you write import java.*; at the top of a file, which classes become usable by their simple names? Commit to an answer before reading on.

  • Every class under java, including classes in nested packages such as java.util

  • Only the classes placed directly in the java package itself, and not those in subpackages such as java.util

  • No classes at all, because the star is not allowed at the package level

Reveal answer
Answer:

Only the classes directly in the named package are matched. The wildcard does not reach into subpackages, so import java.* does not bring in the contents of java.util or java.awt.

Many learners assume a star written high in the package tree is a broad, recursive gesture. Java's wildcard is narrower: it matches every class in the named package, and it does not match subpackages.

Where the Import Directive Goes

Although people often call an import line a statement, the source says it is more properly called an import directive, because it is not a statement in the ordinary sense. The directive has a fixed place. It appears at the start of the file, after the package statement if the file has one, and it sits outside any class. Its scope is the whole file, so once you place it, every later use of the simple name in that file is covered.

java
Notes on the code
  • The package statement comes first, if the file has one
  • The import directive follows the package statement and sits outside the class
  • The class body uses the simple name Color, which the directive connects to java.awt.Color
  • The declaration itself is a type name, a variable name, and a semicolon

How a Simple Name Gets Connected

The clearest way to see the effect is to compare two versions of the same declaration. Without an import, the type of a variable has to be written as the full name of the class, such as java.awt.Color rectColor; The source uses a variable named rectColor of type Color as its illustration. With the import directive in place, the body of the file can use the simple name Color instead. The only item that changes is the name written in the body of the file. The class being declared stays the same.

Colorsimple name in the bodyjava.awt.Colorfull name of the classScannersimple name, no import yetno entrynothing connects itimport java.awt.Color;no import directive
When the compiler sees the simple name Color in the body of the file, which full name does it use, and how does the import directive connect the two?

Read the diagram as a lookup table. The import directive adds a row that maps the simple name to the full name for the rest of that file. Without that row, the simple name has nothing to resolve to. The directive does not change the class or its type. Notice what it does not do: it does not make the class available under a different identity, and it does not change the type of rectColor. It only allows the shorter spelling in the file where the directive appears.

Before
public class PaintBox {
    java.awt.Color rectColor;
}

The full name java.awt.Color is written at the point of use

After
import java.awt.Color;

public class PaintBox {
    Color rectColor;
}

The import connects the simple name Color to java.awt.Color; the class and the type of rectColor are unchanged

What a Wildcard Import Matches

An import directive does not have to name one class. The source also shows a wildcard form, in which an asterisk stands in for the class name. The wildcard matches every class in the named package, so you can abbreviate many class names at once without writing one import line per class. Its reach is precise, and it is easy to misjudge. The next two sections of the source explain why.

java
Notes on the code
  • The star stands for every class in the java.util package
  • Scanner is a class directly inside java.util, so the simple name resolves
  • Classes in the subpackage java.util.concurrent are not covered by this line
javatop-level packageutilimported with java.util.*Scannermatched by the starConcurrentHashMapstill needs its own importawtnot covered by this importconcurrentsubpackage, not matchedcontainscontainscontainscontainscontains
Does import java.util.* bring in classes from subpackages such as java.util.concurrent, or only the classes directly inside java.util?

The tree shows the rule. A wildcard reaches the classes that sit directly inside the named package, and stops there. The star on java.util covers Scanner, but not the classes inside java.util.concurrent. Each subpackage needs its own import. The same logic applies to java.*: it does not import the contents of all subpackages of java, so the wildcard at the top level is not a recursive gesture.

Finding Where a Name Stops Resolving

When a program breaks after you switch to a simple class name, the cause is usually one specific thing: the simple name has not been connected to a full name at the point where it is used. Read the file from top to bottom and ask, at each line, whether the name has been connected yet. The execution trace below follows a short program through these stages. Hold one question in mind: where does the result first diverge from what you expected?

Code walkthrough
package com.example.shapes;

import java.awt.Color;

public class PaintBox {
    Color rectColor;
    Scanner input;
}
  1. 1
    Line 1 the package statement comes first, placing the file in com.example.shapes
  2. 2
    Line 3 the import directive connects the simple name Color to java.awt.Color for the whole file
  3. 3
    Line 5 the class declaration begins outside any import
  4. 4
    Line 6 Color resolves, because the import above covers it
  5. 5
    Line 7 Scanner has no import directive in this file, so the simple name cannot be connected to java.util.Scanner, and the compiler reports an error here
  • The failing line is the first use of a name with no connection
  • The declaration itself is correctly formed; the missing piece is the import
Read the packagelinepackage com.example.shapesRead import linesimport java.awt.ColorUse of Color?line 6Color resolvesjava.awt.ColorUse of Scanner?line 7Scanner unresolvedno import forjava.util.Scannernextnextyesnextno connection
Walking through the short file step by step, at which line does a simple class name fail to resolve, and why?

Mistakes That Break Simple Names

When a program breaks after you switch to a simple class name, the cause is usually one of a few specific things. Use this list as a checklist when you read the output of a failed build.

  • Common mistake

    Placing the import directive inside the class body

    What it looks like
    public class PaintBox { import java.awt.Color; Color rectColor; }
    Why it fails

    The directive has a fixed place: at the start of the file, after the package statement, and outside any class.

    Do this instead

    Move the import line above the class declaration, after the package line if there is one.

  • Common mistake

    Assuming a wildcard import reaches subpackages

    What it looks like
    import java.util.*; followed by a use of ConcurrentHashMap from java.util.concurrent
    Why it fails

    A wildcard matches every class in the named package, but it does not match subpackages.

    Do this instead

    Import the subpackage class explicitly, or use a wildcard on the subpackage itself, such as java.util.concurrent.*.

  • Common mistake

    Believing the import changes the class

    Why it fails

    The import only allows the shorter spelling in the file where it appears. It does not change the class or its type.

    Do this instead

    Treat the simple name as a spelling convenience and keep the class identity in mind when you read errors.

  • Common mistake

    Using a simple name in a file where its directive is missing

    What it looks like

    Scanner input; in a file that has no import for java.util.Scanner

    Why it fails

    A name spelled correctly still fails if the directive it depends on is missing or misplaced.

    Do this instead

    Check whether the simple name has an import directive in this same file before suspecting the declaration.

Practice Tracing the Lookup

MEDIUM

A file begins with the package line package com.example.game; and then has import java.util.Scanner; followed by a class that declares Color rectColor; and Scanner input;. Without looking back at the walkthrough, trace each simple name from top to bottom and state which name fails to resolve and on which line. Then state the fix.

Hints
  • Ask at each line whether the simple name has been connected to a full name in this file
  • Check whether an import line exists for java.awt.Color
  • The fix is a single import directive placed after the package line and outside the class

Taking Away the Core Rules

  1. 1
    An import directive lets you write a simple class name in the rest of the file, instead of the full name, and it does not change the class or its type.
  2. 2
    The directive goes at the start of the file, after the package statement if present, and outside any class; its scope is the whole file.
  3. 3
    A wildcard import matches every class directly in the named package, but it does not match subpackages, so java.* does not import the contents of java.util or java.awt.
  4. 4
    When a simple name fails, check where the import directive sits and which package it names before suspecting the declaration itself.

Key Takeaways

  • An import directive lets you write a simple class name in the rest of the file instead of the full name, but it does not change the class or its type.
  • The import directive belongs at the start of the file, after the package statement if present, and outside any class.
  • A wildcard import matches every class in the named package but not its subpackages, so java.* does not import the contents of all subpackages of java.
  • When a simple name fails, check where the import directive sits and which package it names before suspecting the declaration itself.