Using Classes from Packages
A specific import names one class using its fully qualified name, in the form import package_name.ClassName;
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.
Count: 2
[Ada, Grace]- Line 1: a specific import that names one class using its fully qualified name
- Line 5: the short name
ArrayListis 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
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.
- 1Line 1 makes the class
ArrayListfrom thejava.utilpackage available to this file under its short name. - 2Line 5 uses the short name
ArrayListto create an empty list of strings. The name works only because line 1 made it available. - 3Line 6 adds the string Ada to the list, so the list now holds one item.
- 4Line 7 adds the string Grace, so the list now holds two items.
- 5Line 8 asks the list for its size, which is 2, and prints it together with the text Count: .
- 6Line 9 prints the list itself, which shows its items in the order they were added.
The Fully Qualified Name in a Specific Import
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.
- 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
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.
[Linus]- One wildcard line makes
ArrayListand 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.
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.
| Question | Specific import | Wildcard import |
|---|---|---|
| Form | import package_name followed by a dot and the class name | import package_name followed by a dot and an asterisk |
| What it brings in | Exactly one named class | All classes directly inside the named package |
| What the file reveals | Each class the file depends on, listed at the top | Only the package; the classes used must be found in the body |
| Nested packages | Not relevant, since one class is named | Not included; nested packages need their own import |
| Good fit | A file that uses a few classes and should document them | A file that uses many classes from one package and where a short list would be repetitive |
Specific versus wildcard imports
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.
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.
- The specific import of
java.util.Datenames the class directly - The wildcard on
java.sqlalso 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.
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 likeUsing ArrayList in a file with no import of java.util.ArrayList or java.util.*
Why it failsWithout a matching import, a short class name such as
ArrayListcannot be resolved, so compilation fails.Do this insteadAdd 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 likeWriting import java.util.*; and then using ConcurrentHashMap, which lives in java.util.concurrent
Why it failsThe wildcard covers the classes directly in
java.util. The nested packagejava.util.concurrentis not included.Do this insteadAdd 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 likeReading import java.util.*; at the top and concluding the file only uses one class
Why it failsA wildcard records only the package, so the actual classes used must be found by reading the body of the file.
Do this insteadWhen 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
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.awtbrings in the classes directly insidejava.awt, not classes injava.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
ArrayListcannot 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.