Concepts / Static Variables and Static Methods

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.

  • Programming

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.

java
Output
4.0
5.0
Notes on the code
  • The static import on the first line makes the simple name sqrt valid in this file
  • Math.sqrt on the fourth line still works in its compound form
  • System.out is 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?

  • Only the line that calls sqrt(16.0)

  • Only the line that calls Math.sqrt(25.0)

  • Both square root lines

  • No line stops compiling

Reveal answer
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.

sqrtsimple name at the callsiteimport staticjava.lang.Math.sqrtimport line in this fileMath.sqrtmember stays defined inMathlooked up innames
When the compiler sees the simple name sqrt, the static import line supplies the class that owns it. The member itself remains defined inside Math, so the simple and compound spellings refer to one method.

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.

import staticfixed opening wordsjava.langpackage nameMathclass that owns the membersqrtstatic member name thatchangesthenthenthen
In the single-member form, the words import static and the package and class names are fixed in shape, and only the final member name changes. Replacing that member name with the star character gives the wildcard form, which imports every static member of the class.
java
Notes on the code
  • The single-member form names exactly one static member
  • The wildcard form brings every static member of the class into simple-name use
FormShape of the directiveWhat it imports
Single-memberimport static package.Class.member;One named static member, such as sqrt
Wildcardimport 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.

Code walkthrough
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);
    }
}
  1. 1
    Line 1 is the static import. It makes the simple name sqrt valid everywhere in this file, not only inside main.
  2. 2
    Line 3 declares the class. It contributes nothing to the meaning of sqrt, because the import has already handled that name.
  3. 3
    Line 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.
  4. 4
    Line 6 calls Math.sqrt(25.0). This name is compound, so it is resolved through the class Math directly and produces 5.0.
  5. 5
    Lines 7 and 8 print the stored values. System.out is not statically imported, so these lines keep their compound names.
Output
4.0
5.0

Static 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.

importjava.util.Scannerimport staticjava.lang.Math.sqrtScannerclass name becomes simplesqrtmember name becomes simplemakes simplemakes simple
An ordinary import makes a class name simple, so Scanner can be written alone. A static import makes a static member name simple, so sqrt can be written alone. Each directive changes only the one kind of name it targets.
QuestionOrdinary importStatic import
Which name becomes simple?A class name, such as ScannerA static member name, such as sqrt
Where does the name's owner appear?Written once in the import lineSupplied 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 directiveNot 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 fails

    The 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 instead

    Think 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 like

    Deleting import static java.lang.Math.sqrt; while leaving sqrt(16.0) in the code

    Why it fails

    The 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 instead

    Either 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 like
    import static sqrt;
    Why it fails

    Both 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 instead

    Write 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 like

    Keeping only import static java.lang.Math.sqrt; and expecting System.out to be written as out

    Why it fails

    A static import applies to the named member or members only. System.out is a different static member and was not imported.

    Do this instead

    Use 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 fails

    The 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 instead

    Check whether the directive contains the word static before deciding which kind of name it affects.

Practice Reading an Import Block

MEDIUM

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.sqrt in 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.