Concepts / Package Statements in Java Source Files

Package Statements in Java Source Files

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 it is 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. That mechanism is the import directive. This article looks at how it works, where it has to sit in a file, how far its wildcard form reaches, and how to spot the point where a simple name stops working.

What do you think happens?

Before reading on: if you import java.awt.Color, does the class itself change, or does only the way you write its name change?

  • The class changes into a new class

  • Only the way the name is written in the file changes

  • The class moves into the current package

Reveal answer
Answer:

Only the way the name is written in the file changes.

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

Tracing Where a Simple Name Fails

Follow a short program from top to bottom. The first line is the package statement. The class body declares a variable named rectColor of type Color, written as a simple name. Without any import directive, the simple name Color has no link to a full name at that point in the file, so the declaration cannot be resolved as intended.

Package linepackage demo;Import directiveabsent in this versionClass bodyColor rectColor declaredColor imported?Name fails to resolveResolves tojava.awt.Colornext linenext linecheck namenoyes, with import
Without an import directive between the package line and the class body, the simple name Color has no full name to connect to, so the lookup fails at the declaration.

Read the diagram as a trace. The program is correct up to the declaration. The failure is not in the class body as such. It happens because the simple name at the declaration has not been connected to a full name. Adding an import directive between the package line and the class body changes the answer at the decision point, and the same declaration then resolves.

What the Import Directive Actually Does

Definition

An import directive lets you write a simple class name in the rest of a Java file instead of the full name. It does not change the class or its type. Although people often call an import line a statement, it is more properly called an import directive, because it is not a statement in the ordinary sense.

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

The type is written as the full name java.awt.Color.

After
import java.awt.Color;

public class Demo {
    Color rectColor;
}

The type is written as the simple name Color, and the import line connects it to java.awt.Color.

Look closely at what changed between the two versions. Only the name written in the body of the file changed. The class being declared stays the same, the type of rectColor stays the same, and the import only allows the shorter spelling in the file where the directive appears. Keeping this distinction clear helps when you read errors later, because a correctly spelled name can still fail if the directive it depends on is missing or misplaced.

Placing the Directive in a File

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.

package demo;optional package statement,firstimportjava.awt.Color;import directive, outsideany classpublic class Democlass declarationColor rectColor;simple name used inside thebodythenthencontains
The package statement comes first when present, then the import directive, both outside any class. The declaration that uses the simple name sits inside the class body.
java
Notes on the code
  • The package statement is first, if the file has one.
  • The import directive sits after the package statement and before the class.
  • The simple name Color inside the class body is covered by the import for the whole file.

How Far a Wildcard Import Reaches

An import directive does not have to name one class. The wildcard form uses an asterisk in place of the class name, written after the dot in the package name. The wildcard matches every class in the named package, so one line abbreviates many class names at once without a separate import line for each class.

java
Notes on the code
  • The wildcard covers classes directly inside java.util.
  • It does not cover classes inside subpackages of java.util.
javatop-level packageutiljava.utilScannerdirectly inside java.utilFunctioninside java.util.functionawtjava.awtfunctionjava.util.functionconcurrentjava.util.concurrentcontainscontainsmatchedcontainsnot matchedcontains
The wildcard matches Scanner, which sits directly in java.util. It does not match Function, which sits in the subpackage java.util.function, even though that subpackage is nested under java.util.

The wildcard is precise, and it is easy to misjudge. Many learners first assume a star written at the java level is a broad, recursive gesture that brings in every class beneath it, including classes in every nested package. The source rejects that reading. A wildcard import matches every class in the named package, but it does not match subpackages. So java.* does not import the contents of all subpackages of java, and java.util.* does not import java.util.function or java.util.concurrent.

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

    Suspecting the declaration first when a simple name fails

    Why it fails

    The declaration is often correct. The failure usually comes from the import directive being missing, misplaced, or naming the wrong package.

    Do this instead

    Check where the import directive sits and which package it names before you change the declaration.

  • Common mistake

    Placing the import inside the class body

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

    The directive has a fixed place outside any class.

    Do this instead

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

  • Common mistake

    Expecting a wildcard to reach subpackages

    What it looks like
    import java.util.*;  then using Function from java.util.function
    Why it fails

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

    Do this instead

    Add a separate import for the subpackage, such as an import for the Function class in java.util.function.

  • Common mistake

    Believing the import changes the class

    Why it fails

    The import does not make the class available under a different identity or change its type.

    Do this instead

    Treat the import as a change to how the name is written in this file only.

Worked Example: Finding the Failing Line

Worked example

Locating where a simple name stops resolving

A file contains the package line, a class Demo, and the declaration Color rectColor inside the class body, with no import directive. Where does the simple name stop resolving, and how is it fixed?

  1. 1
    Read the file from the top

    The package statement is the first line, and it is valid. Nothing has yet connected the simple name Color to a full name.

  2. 2
    Reach the declaration

    The declaration Color rectColor appears in the class body. The simple name Color is used here, and no import directive has appeared earlier in the file to supply the full name.

  3. 3
    Identify the failing point

    The name stops resolving at the declaration, not at the package line. The problem is the missing link between the simple name and java.awt.Color.

  4. 4
    Add the directive in the right place

    Insert import java.awt.Color; after the package statement and before the class declaration. The declaration itself does not need to change.

  5. 5
    Confirm the result

    Now the simple name Color is covered by the directive for the whole file. The class and the type of rectColor are unchanged.

Result

The name fails at the declaration because no import connects Color to its full name. Adding the directive after the package statement and outside the class fixes it without changing the class.

Practice: Predicting Wildcard Reach

MEDIUM

A file contains import java.util.*; and the class body uses the simple name Scanner. Then the same file uses the simple name Function, which lives in java.util.function. Without any other import, predict which name resolves and explain why, using the rule about subpackages.

Hints
  • Ask whether Scanner is directly inside java.util.
  • Ask whether Function is directly inside java.util or inside a subpackage of it.
  • Remember that a wildcard matches every class in the named package but not its subpackages.

Key Takeaways

  • 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.
  • The directive belongs at the start of the file, after the package statement if present, and outside any class, and it covers the whole file.
  • A wildcard import with an asterisk matches every class in the named package but does not match 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.