Static Variables and Static Methods
A static import lets a static member of a class be referred to by its simple name, which removes the need for compound names such as Math.sqrt.
Why Square Root Calls Carry a Prefix
Earlier in the import material, a class such as java.util.Scanner could be written with its simple name, Scanner, once an import directive brought it into view. Static members behave differently. A static member variable such as System.out, or a static method such as Math.sqrt, still has to be written with a compound name that begins with the class name. Every call to the square root function therefore carries the prefix Math, and every print statement carries the prefix System.out.
This repetition is what a static import is designed to remove. A static import lets a static member of a class be referred to by its simple name, so that a call can be written as sqrt(x) instead of Math.sqrt(x). This article follows that idea from the question of why the prefix is needed, through the two directive forms, to a line-by-line trace of a real program and a comparison with the ordinary import you already know.
Predicting What the Import Line Controls
Before reading the explanation, consider the small program below. The first line is a static import for the sqrt method. The second line uses the compound form Math.sqrt on its own. Think about what each line of the program depends on before you read on.
4.0
5.0- The static import on the first line makes the simple name sqrt valid in this file
Math.sqrton the fourth line still works in its compound formSystem.outis not statically imported, so it keeps its compound name
What do you think happens?
If the first line, import static java.lang.Math.sqrt;, is deleted, which line of the program stops compiling?
Reveal answer
Only the line that calls sqrt(16.0)
Without the static import, the simple name sqrt is no longer something the compiler can resolve in this file. The compound form Math.sqrt names its class directly, so it does not depend on the import line. The System.out lines are unaffected because they never used the import.
What a Static Import Actually Does
A static import does not create a new method and does not copy one. The member itself stays where it was defined, inside its class. What the import changes is how a name is written at the point of use. It tells the compiler that a particular simple name, when it appears in this file, should be read as a static member of a named class.
Think of the import line as a declaration of intent that is recorded for the whole file. When the compiler meets sqrt(x), it looks up the import line to learn which class's static member sqrt refers to, and then treats the call as if the programmer had written Math.sqrt(x). The two spellings describe the same call. Only the written form differs.
The same reasoning explains the compound form. Math.sqrt names the class directly on the line where the call is written, so it does not need any import line to be understood. This is why the second line of the demonstration program in the prediction section still compiles even when the first line is removed.
The Two Directive Forms
The source gives two forms of the static import directive. Both begin with the words import static, followed by a package name and a class name. What comes after the class name decides how much is imported. The single-member form imports one named static member. The wildcard form, written with the star character in the position of the member name, makes every static member of the class available by its simple name.
- The single-member form names exactly one static member
- The wildcard form brings every static member of the class into simple-name use
| Form | Shape of the directive | What it imports |
|---|---|---|
| Single-member | import static package.Class.member; | One named static member, such as sqrt |
| Wildcard | import static package.Class.*; | Every static member of the class, available by simple name |
The two forms of the static import directive
Tracing the Program Line by Line
Now trace the demonstration program from the prediction section. The trace follows each line in order and asks one question at each step: which line makes this name valid? The answer tells you where the program gets its meaning, and it is the habit you need when reading a file with several import lines.
import static java.lang.Math.sqrt;
public class SquareRootDemo {
public static void main(String[] args) {
double a = sqrt(16.0);
double b = Math.sqrt(25.0);
System.out.println(a);
System.out.println(b);
}
}- 1Line 1 is the static import. It makes the simple name sqrt valid everywhere in this file, not only inside main.
- 2Line 3 declares the class. It contributes nothing to the meaning of sqrt, because the import has already handled that name.
- 3Line 5 calls sqrt(16.0). The compiler resolves sqrt through line 1, so the call is read as
Math.sqrt(16.0)and produces 4.0. - 4Line 6 calls
Math.sqrt(25.0). This name is compound, so it is resolved through the class Math directly and produces 5.0. - 5Lines 7 and 8 print the stored values.
System.outis not statically imported, so these lines keep their compound names.
4.0
5.0Static Import Versus Ordinary Import
An ordinary import and a static import look alike on the page, and they answer different questions. The ordinary import answers the question of how a class name can be written simply. The static import answers the question of how a static member name can be written simply. The same keyword combination of import and a dotted path can therefore do two different jobs, depending on whether the word static appears.
| Question | Ordinary import | Static import |
|---|---|---|
| Which name becomes simple? | A class name, such as Scanner | A static member name, such as sqrt |
| Where does the name's owner appear? | Written once in the import line | Supplied by the import line at each use |
| What does a simple use look like? | Scanner input = new Scanner(System.in); | sqrt(16.0) |
| Does System.out become simple? | Not by this directive | Not unless System or out is named by a static import |
Comparing ordinary and static import directives
The table makes one contrast explicit. An ordinary import of java.util.Scanner does not make the static member System.out simple, and a static import of sqrt does not make the class Math simple for other purposes. Each directive has a narrow target, and that narrowness is what keeps the two kinds of import from being confused once you know which question each one answers.
Mistakes Beginners Make with Static Imports
Common mistake Believing the static import copies the method into the file
Why it failsThe source is explicit that a static import does not create a new method or copy one. The member stays inside its class, and the import only changes how the name is read at the point of use.
Do this insteadThink of the import as a rule for resolving a simple name, not as a second definition of the method.
Common mistake Removing the import line and expecting the simple call to keep working
What it looks likeDeleting import static java.lang.Math.sqrt; while leaving sqrt(16.0) in the code
Why it failsThe simple name sqrt is valid only because the import line supplies its class. Without that line, the simple name has no owner to resolve to.
Do this insteadEither restore the import line or change the call to the compound form Math.sqrt(16.0).
Common mistake Writing the import without its package and class name
What it looks likeimport static sqrt;Why it failsBoth forms of the directive begin with import static, followed by a package name and a class name. The member name alone does not say which class it belongs to.
Do this insteadWrite the full path, such as import static java.lang.Math.sqrt;
Common mistake Assuming one static import makes every compound name unnecessary
What it looks likeKeeping only import static java.lang.Math.sqrt; and expecting System.out to be written as out
Why it failsA static import applies to the named member or members only.
System.outis a different static member and was not imported.Do this insteadUse simple names only for members that a static import names, and keep compound names for everything else.
Common mistake Confusing the ordinary import with the static import because they look alike
Why it failsThe ordinary import makes a class name simple, while the static import makes a static member name simple. The word static is the difference.
Do this insteadCheck whether the directive contains the word static before deciding which kind of name it affects.
Practice Reading an Import Block
Given the lines below, state which simple names are valid in the file without any further prefix, and identify which line makes each one valid. Then say what changes if the wildcard line is replaced by the single-member form for sqrt.
import static java.lang.Math.*;
class Area {
double circle(double r) { return PI * r * r; }
double root(double x) { return sqrt(x); }
}Hints
- Ask first which form of the directive each import line uses.
- The wildcard form makes every static member of the class available by its simple name, so consider whether PI and sqrt are both covered.
- If the wildcard is replaced by the single-member form for sqrt, check whether PI is still available by its simple name.
Key Takeaways
- A static import lets a static member of a class be referred to by its simple name, removing the need for compound names such as
Math.sqrtin code that imports it. - The single-member form, import static package.Class.member;, imports one named static member, while the wildcard form, import static package.Class.*;, imports every static member of the class.
- A static import does not create or copy a method; it tells the compiler how to read a simple name in the file, and the member stays defined inside its class.
- An ordinary import makes a class name simple, while a static import makes a static member name simple, so the two directives answer different questions even though they look alike.
- When tracing a program, the import line is the one that makes a simple name valid, and removing it stops that simple name from resolving while compound names keep working.