Concepts / Using Classes from Packages

Using Classes from Packages

A specific import names one class using its fully qualified name, in the form import package_name.ClassName;

  • Programming

Predicting an Import Program's Output

This lesson begins with a program rather than a set of rules. Read the program below, predict what it prints, and then compare your prediction with the real output. Pay attention to which lines of the program produce each line of output. The explanation of how import statements work comes after you have seen the program behave.

java
Output
Count: 2
[Ada, Grace]
Notes on the code
  • Line 1: a specific import that names one class using its fully qualified name
  • Line 5: the short name ArrayList is usable here only because of the import on line 1
  • Line 8: prints the number of items stored in the list
  • Line 9: prints the list contents

What do you think happens?

If the import line on line 1 were deleted, what would happen when the program is compiled?

Reveal answer
Answer:

The program would fail to compile, because the short name ArrayList cannot be resolved without a matching import.

The short class name ArrayList only has meaning in the file if an import makes it available. Without the import, the compiler has no way to connect the name ArrayList to the class in the java.util package, so compilation fails.

Tracing Each Line to Its Effect

Now trace the program one line at a time. The goal is to connect each line of code to the output it produces, and to notice which line makes each step possible. This habit is what you will rely on later when a result is not what you expected.

  1. 1
    Line 1 makes the class ArrayList from the java.util package available to this file under its short name.
  2. 2
    Line 5 uses the short name ArrayList to create an empty list of strings. The name works only because line 1 made it available.
  3. 3
    Line 6 adds the string Ada to the list, so the list now holds one item.
  4. 4
    Line 7 adds the string Grace, so the list now holds two items.
  5. 5
    Line 8 asks the list for its size, which is 2, and prints it together with the text Count: .
  6. 6
    Line 9 prints the list itself, which shows its items in the order they were added.

The Fully Qualified Name in a Specific Import

Definition

A specific import names exactly one class using its fully qualified name, which is the package name, a dot, and the class name. The general form is import package_name.ClassName; and the source gives import java.awt.Color; as its example.

Read the example import java.awt.Color; from left to right. The word import starts the statement. The segment java.awt is the package, which is a path of names separated by dots. The final segment Color is the class being imported. Because the package path and the class name are separated only by the last dot, the statement identifies one specific class without any ambiguity about which one is meant.

java
Notes on the code
  • The import names java.awt.Color, so the short name Color is usable in this file
  • Color.RED refers to a constant from the Color class

A specific import records a dependency explicitly. A reader of this file can look at the top of the file and see that it depends on Color and nothing else from java.awt. That visibility is one of the main reasons specific imports are used.

Wildcard Imports and the Packages They Reach

Definition

A wildcard import uses an asterisk in place of a class name. Written as the package name, a dot, and an asterisk, followed by a semicolon, it makes all the classes in that package available to the file. The source gives the example import java.util.*; as its form.

java
Output
[Linus]
Notes on the code
  • One wildcard line makes ArrayList and Scanner both usable by short name
  • The file never states which classes it uses, so a reader must read the body to find out

The contrast with the specific form is the key point. A wildcard import records only the package, not the individual classes. Nothing at the top of the file says that ArrayList is used, so a reader has to scan the rest of the file to learn what it depends on.

A wildcard import reaches the classes that sit directly inside the named package. It does not reach packages nested beneath it. The diagram below shows the package tree for this example, with java.util containing a nested package called concurrent.

javautilwildcard applies hereArrayListreached by java.util.*ConcurrentHashMapnot reachedScannerreached by java.util.*concurrentnested package, not reachedcontainscontainscontainscontainscontains
After import java.util.*; which classes are usable by short name, and why is ConcurrentHashMap still missing?

Choosing Between Specific and Wildcard Imports

Both forms make a class's short name usable in the file. They differ in how much they bring in and in how clearly the file states its dependencies. The table below compares them side by side.

QuestionSpecific importWildcard import
Formimport package_name followed by a dot and the class nameimport package_name followed by a dot and an asterisk
What it brings inExactly one named classAll classes directly inside the named package
What the file revealsEach class the file depends on, listed at the topOnly the package; the classes used must be found in the body
Nested packagesNot relevant, since one class is namedNot included; nested packages need their own import
Good fitA file that uses a few classes and should document themA file that uses many classes from one package and where a short list would be repetitive

Specific versus wildcard imports

Best practice

When in doubt, prefer the specific form. It shows each dependency at the top of the file, so a reader can see what the file needs without reading every line. Reach for the wildcard form when a file uses many classes from one package and listing each one would add little information.

Resolving a Bare Class Name

When the compiler meets a short class name such as ArrayList, it has to decide which class that name refers to. The decision depends on which imports are present. The flowchart below follows that decision for a single use of a bare name. Read it from the top, answering each question in turn.

Bare name used incodeSpecific import forthis name?Use the named classExactly one matchUse that classWildcard importsproviding it?Two or more matchesAmbiguity errorNo matching importname cannot be resolvedcheck firstyesnofoundone classfoundclashnot found
When a file has several imports that could supply the same short name, which one is used, and when is an ambiguity error reported?

The flowchart reflects the general rule that a specific import names one class directly and therefore settles the question without competition from wildcard imports. Two wildcard imports that both provide a class with the same short name compete with each other, and the program cannot decide which one is meant when that name is used. The source material does not cover this case in detail, so treat the flowchart as a guide to the reasoning rather than a complete list of compiler rules, and confirm the exact behavior by compiling a small test file.

java
Notes on the code
  • The specific import of java.util.Date names the class directly
  • The wildcard on java.sql also contains a class called Date, which is the potential clash
  • The specific import is the one this file's name Date is meant to refer to, so the reasoning above applies

Locating Where a Result Diverges

When an import-related program does not behave as you expected, the most useful question is where its result first differs from your prediction. Step through the program, line by line, and compare the effect of each line with what you expected it to do. The first point where the expected and actual results disagree is the place to investigate. For an import problem, that is usually the import line itself, or the first line that uses the class name.

Debugging

Suppose a student expects the program below to print Count: 2 but instead gets a compile error. Following the divergence rule, compare each line against the prediction. Line 1 has no import, so the first line that uses the name ArrayList, line 5, is where the result first differs from what the student expected. The fix is to add the missing import on line 1, and the compile error disappears.

  • Common mistake

    Forgetting the import and expecting the short class name to work

    What it looks like

    Using ArrayList in a file with no import of java.util.ArrayList or java.util.*

    Why it fails

    Without a matching import, a short class name such as ArrayList cannot be resolved, so compilation fails.

    Do this instead

    Add a specific import for the class, or a wildcard import for its package.

  • Common mistake

    Expecting a wildcard import to bring in classes from nested packages

    What it looks like

    Writing import java.util.*; and then using ConcurrentHashMap, which lives in java.util.concurrent

    Why it fails

    The wildcard covers the classes directly in java.util. The nested package java.util.concurrent is not included.

    Do this instead

    Add an import that names the nested package, such as a specific import of java.util.concurrent.ConcurrentHashMap.

  • Common mistake

    Assuming a wildcard import shows which classes a file uses

    What it looks like

    Reading import java.util.*; at the top and concluding the file only uses one class

    Why it fails

    A wildcard records only the package, so the actual classes used must be found by reading the body of the file.

    Do this instead

    When readability matters, replace the wildcard with specific imports for the classes the file really uses.

  • Common mistake

    Searching for the bug at the end of the program instead of at the first point where the output diverges

Practice: Predict, Then Check the Imports

MEDIUM

Read the following program. Before you compile it, predict whether it compiles, and if it does not, identify the line responsible. Then decide whether a specific import or a wildcard import would be the better choice for this file, and explain why.

import java.util.Scanner;
import java.awt.*;
public class Check {
    public static void main(String[] args) {
        Scanner input = null;
        ArrayList<String> items = new ArrayList<>();
        System.out.println(items);
    }
}
Hints
  • Check each name used in the body: Scanner and ArrayList. Ask whether a matching import exists for each one.
  • The wildcard on java.awt brings in the classes directly inside java.awt, not classes in java.util.
  • Trace the first line that uses a name without a matching import, since that is where the result first diverges from a successful compile.
  • Consider how many classes this file actually uses from each package when you judge which form is the better fit.

Key Takeaways

  • A specific import names one class using its fully qualified name in the form import package_name.ClassName;, and makes that class's short name usable in the file.
  • A wildcard import in the form import package_name.*; makes all classes directly inside the named package available, but records only the package rather than the classes actually used.
  • Without a matching import, a short class name such as ArrayList cannot be resolved and compilation fails.
  • Choose a specific import when a file should document its dependencies, and a wildcard import when a file uses many classes from one package.
  • When a result is unexpected, find the first point where it diverges from your prediction, which is usually the import line or the first line that uses the class name.