Import and Static Import in Java — Complete Guide

Import and Static Import in Java — Complete Guide

Import and Static Import in Java

Import lets you use a short class name instead of its full package path. Static import goes one step further and lets you use a class's static members without the class name. This guide covers both, their ambiguity problems, resolution rules, and when to use (or avoid) each.

Part 1 — The Import Statement

Why we need it

Without an import, using a class from another package by its short name fails:

class Test {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
    }
}

Error: cannot find symbol — class ArrayList.

One fix is the fully qualified name (FQN) everywhere:

java.util.ArrayList<String> names = new java.util.ArrayList<>();

That gets long and noisy. The import statement lets you write the short name:

import java.util.ArrayList;

class Test {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("Asha");
        System.out.println(names);   // [Asha]
    }
}

In short: import is a typing shortcut. Source file order is always: package → import statements → class declaration.

Explicit vs implicit import

Explicit import java.util.ArrayList; ArrayList Only this class Implicit (on demand) import java.util.*; ArrayList HashMap Date … Every class in the package
Implicit import covers classes directly in the package, not its sub-packages.
  • Explicit — recommended. Dependencies are visible at the top of the file, so large projects stay readable.
  • Implicit — shorter to type, but you can't tell which classes are actually used. Fine for quick experiments; avoid it in big codebases.

Which import statements are valid?

StatementResult
import java.util.ArrayList;Valid (explicit)
import java.util.*;Valid (implicit)
import java.util.ArrayList.*;Compiles, but pointless: it imports only nested types of ArrayList, not ArrayList itself
import java.util;Error: util is a package, not a class
import java.lang.Math.sqrt;Error: sqrt is a method, not a type
import java.lang;Error: package name without .*

Rule: a normal import names a type (class, interface, enum) or uses .* on a package. Members like methods and fields need a static import (Part 2).

Fully qualified names need no import

class Report {
    java.time.LocalDate created = java.time.LocalDate.now();   // no import needed
}

Using an FQN means no import is needed, and having an import means you don't need the FQN.

The ambiguity problem

Date exists in both java.util and java.sql; List exists in both java.util and java.awt. Wildcard-importing both packages is ambiguous:

import java.util.*;
import java.sql.*;

class Test {
    public static void main(String[] args) {
        Date d = new Date();   // which Date?
    }
}

Compile-time error: reference to Date is ambiguous.

Two fixes:

// Fix 1: explicit import for the one you want
import java.util.Date;
import java.sql.*;

// Fix 2: FQN for the clashing class
java.util.Date now = new java.util.Date();
java.sql.Date  sqlDate = new java.sql.Date(now.getTime());

The error only appears when the ambiguous name is actually used; importing both packages alone is fine.

Resolution precedence

When a short name could refer to several classes, the compiler picks in this order:

  1. Explicit class import
  2. A class in the same package (the current directory, if it's the default package)
  3. Implicit (on-demand) import
import java.util.Date;
import java.sql.*;

class Test {
    public static void main(String[] args) {
        Date d = new Date();
        System.out.println(d.getClass().getName());
    }
}

Output: java.util.Date — the explicit import beats java.sql.*.

Sub-packages are not included

java.util ArrayList Date java.util.regex Pattern Matcher
import java.util.*; reaches ArrayList and Date, but not Pattern.
To use PatternWorks?
import java.*;No
import java.util.*;No
import java.util.regex.*; (or java.util.regex.Pattern)Yes
No importNo

What needs no import

  • Everything in java.lang (String, Math, System, Integer …)
  • Classes in the same package as the current class

Import is compile-time only

More imports mean slightly more work for the compiler, but have no effect on runtime performance. Also, unlike C's #include, which pulls in header contents up front, a Java import loads nothing; a .class file is loaded on demand the first time the class is actually used.


Part 2 — The Static Import Statement

Static import was added in Java 1.5, alongside the for-each loop, var-args, autoboxing, generics, covariant return types, annotations and enums. It lets you use static members (fields, methods, nested types) of a class without writing the class name.

Without and with static import

// Without
class Geometry {
    public static void main(String[] args) {
        double r = 2;
        System.out.println(Math.PI * Math.pow(r, 2));
        System.out.println(Math.sqrt(Math.pow(3, 2) + Math.pow(4, 2)));
    }
}
// With
import static java.lang.Math.*;

class Geometry {
    public static void main(String[] args) {
        double r = 2;
        System.out.println(PI * pow(r, 2));              // 12.566370614359172
        System.out.println(sqrt(pow(3, 2) + pow(4, 2))); // 5.0
    }
}

Understanding System.out.println()

  • System — the class
  • out — a static variable of type PrintStream inside System
  • println() — a method of PrintStream

Since out is static, it can be statically imported:

import static java.lang.System.out;

class Test {
    public static void main(String[] args) {
        out.println("hello");
        out.println("hi");
    }
}

Same idea for your own static members: with class Config { static String env = "prod"; }, the expression Config.env.length() reads as class → static variable (a String) → method of String.

Where static import actually earns its keep

import static java.util.stream.Collectors.toList;

List<String> upper = names.stream()
                          .map(String::toUpperCase)
                          .collect(toList());

Well-known constants and builder-style helpers (Collectors.toList(), assertion methods in test frameworks) read better with it. Overusing it hides where a name comes from.

Good to know: import static java.lang.Math.max; imports all overloads of max. Static import only works for static members; instance members can't be imported this way.

The ambiguity problem

Both Integer and Byte define MAX_VALUE. Wildcard-importing both is ambiguous when the name is used:

import static java.lang.Integer.*;
import static java.lang.Byte.*;

class Test {
    public static void main(String[] args) {
        System.out.println(MAX_VALUE);
    }
}

Compile-time error: reference to MAX_VALUE is ambiguous.

Ambiguity is rare with normal import (two packages with an identically named class) but common with static import (many classes share member names like MAX_VALUE, valueOf, parse…).

Resolution precedence

  1. The current class's own static members
  2. Explicit static import
  3. Implicit (wildcard) static import

Case 1 — own member wins

import static java.lang.Integer.MAX_VALUE;
import static java.lang.Byte.*;

class Test {
    static int MAX_VALUE = 999;
    public static void main(String[] args) {
        System.out.println(MAX_VALUE);   // 999
    }
}

Output: 999

Case 2 — explicit static import wins (remove the class's own MAX_VALUE)

import static java.lang.Integer.MAX_VALUE;
import static java.lang.Byte.*;

class Test {
    public static void main(String[] args) {
        System.out.println(MAX_VALUE);   // Integer.MAX_VALUE
    }
}

Output: 2147483647

Case 3 — only the implicit import is left (also remove the explicit import)

import static java.lang.Byte.*;

class Test {
    public static void main(String[] args) {
        System.out.println(MAX_VALUE);   // Byte.MAX_VALUE
    }
}

Output: 127

Which static import statements are valid?

StatementResult
import static java.lang.Math.*;Valid
import static java.lang.Math.sqrt;Valid
import static java.lang.Math.sqrt();Error: no parentheses allowed
import static java.lang;Error: needs a class, not a package
import static java.lang.*;Error: java.lang is a package; name a class

Syntax and comparison

Normal importStatic import
Explicitimport java.util.ArrayList;import static java.lang.Math.sqrt;
Implicitimport java.util.*;import static java.lang.Math.*;
ImportsClasses and interfaces of a packageStatic members of a class or interface
Lets you skipThe package nameThe class name
AmbiguityRare (same class name in two packages)Common (same member name in two classes)
PrecedenceExplicit → same package → implicitOwn member → explicit → implicit

Conclusion

Import is purely a compile-time convenience: an FQN always works without it, and it never changes runtime behavior. Prefer explicit imports in real projects, remember that wildcards skip sub-packages, and resolve clashes like java.util.Date vs java.sql.Date with an explicit import or an FQN.

Static import trims code that leans on one utility class, but hides where a name comes from and is far more prone to ambiguity. Use it where it clearly improves readability, not as a habit.

0 Comments