Import Statement
The import statement is Java's way of letting you use a short class name instead of typing its full package path every time. This post covers why it exists, the difference between explicit and implicit imports, the ambiguity problems they can cause, and how Java resolves them.
Why We Need It
Without any import, referencing a class from another package by its short name fails:
class Test {
public static void main(String... args) {
ArrayList arr = new ArrayList();
}
}
Compile-time error: cannot find symbol: class ArrayList
location: class Test
One fix is to use the fully qualified name every time:
java.util.ArrayList arr = new java.util.ArrayList();
The problem: doing this everywhere makes the code longer and harder to read. The import statement solves that — once imported, you can use the short name directly.
import java.util.ArrayList;
class Test {
public static void main(String... args) {
ArrayList arr = new ArrayList();
}
}
In short: the import statement is a typing shortcut.
Case 1 — Types of Import Statements
There are two types of class imports: explicit and implicit.
Explicit Class Import
- Highly recommended — it makes the code's dependencies clear and improves readability.
- Best suited for large projects, where readability matters most.
Implicit Class Import
- Not generally recommended — it reduces readability since it's unclear exactly which classes are in use.
- Best suited for quick, small programs where typing speed matters more than clarity.
Case 2 — Which Import Statements Are Meaningful?
| Statement |
|---|
import java.util.ArrayList; |
import java.util.ArrayList.*; |
import java.util.*; |
import java.util; |
Of these, only import java.util.ArrayList; (explicit, targeting a class) and
import java.util.*; (implicit, targeting a package) are meaningful.
ArrayList.* tries to wildcard-import members of a class, which isn't how
normal import works, and a bare import java.util; doesn't name a class or
use a wildcard, so it doesn't import anything.
Case 3 — Fully Qualified Names Skip the Import
This compiles fine with no import statement at all, because the fully qualified name is used directly:
class MyObj extends java.rmi.UnicastRemoteObject {
}
Note: whenever you use a fully qualified name, you don't need an import statement for that class — and whenever you write an import statement, you don't need to use the fully qualified name.
Case 4 — The Ambiguity Problem
Date exists in both java.util and java.sql.
Wildcard-importing both creates a genuine conflict — the same issue can happen with
List, which exists in both java.util and java.awt.
import java.util.*;
import java.sql.*;
class Test {
public static void main(String[] args) {
Date date = new Date();
}
}
Compile-time error: reference to Date is ambiguous
Case 5 — Resolution Precedence
When resolving a class name, the compiler gives precedence in this order:
- Explicit class import
- Class present in the current working directory (default package)
- Implicit class import
import java.util.Date;
import java.sql.*;
class Test {
public static void main(String... args) {
Date d = new Date();
System.out.print(d.getClass().getName());
}
}
Output: java.util.Date
Here, the explicit import of java.util.Date wins over the implicit java.sql.* import.
Case 6 — Sub-Packages Aren't Included Automatically
Importing a package makes every class and interface in that package available — but not the classes in its sub-packages. To use a class from a sub-package, you need an import statement that reaches down to that sub-package specifically.
To use the Pattern class (in java.util.regex), which import statement is required?
| Statement | Works? |
|---|---|
import java.*; | No |
import java.util.*; | No |
import java.util.regex.*; | Yes — correct |
| No import | No |
Case 7 — Packages Available Without Any Import
Every class and interface in these is available to every Java program automatically:
java.langpackage- The default package (your current working directory)
Case 8 — Import Is a Compile-Time Concept
More imports mean more work for the compiler, so compile time increases slightly — but imports have no effect on runtime (execution) performance.
Case 9 — C's #include vs. Java's import
In C, #include loads all referenced headers at the very start of
compilation — a static include.
In Java, no .class file is loaded upfront. A class's .class
file is only loaded the first time that class is actually used — a dynamic include,
loaded on demand.
Conclusion
The import statement exists purely to save typing — a fully qualified name always
works without one, and an import never changes runtime behavior, only what you're
allowed to type at compile time. The main things to watch for: explicit imports read
better and are worth the extra line in real projects; wildcard (implicit) imports
don't reach into sub-packages; and importing two classes that share a name (like
Date or List) will force a compile-time ambiguity error
unless the compiler's precedence rules resolve it for you.
1 Comments