Java packages help organize classes, but organization alone is not enough. In real applications, a class often needs to use another class that belongs to a different package. The import statement provides a convenient way to refer to those classes without repeatedly writing their fully qualified names.
You can think of an import statement as telling Java, "I want to use this type by its simple name in this source file." It improves readability and makes code easier to maintain.
Why Is the Import Statement Needed?
Suppose a class named Student belongs to the package com.example.school. Another class in a different package wants to create a Student object.
Without an import statement, the complete class name must be written:
com.example.school.Student student =
new com.example.school.Student();
This is valid, but repeating a long package name makes the code unnecessarily noisy. An import statement allows the class to be referenced simply as Student.
import com.example.school.Student; Student student = new Student();
Basic Syntax
The basic syntax of an import statement is:
import packageName.ClassName;
For example:
import com.example.school.Student;
After this import, the Student class can be referenced using its simple name within the source file.
Complete Example
Consider a Student class in one package:
package com.example.school;
public class Student {
public void display() {
System.out.println("Student details");
}
}
Now suppose another class belongs to the com.example.app package and wants to use Student.
package com.example.app;
import com.example.school.Student;
public class Main {
public static void main(String[] args) {
Student student = new Student();
student.display();
}
}
The package declaration identifies where Main belongs, while the import statement makes Student available by its simple name.
Position of an Import Statement
A Java source file generally follows this order:
package packageName;
import packageName.ClassName;
public class ClassName {
// class body
}
The package declaration comes first, followed by import declarations, and then the type declarations such as classes or interfaces.
Important: An import statement cannot be placed inside a class, method, or constructor. It belongs at the source-file level, after the package declaration and before type declarations.
Importing Multiple Classes
A source file can import multiple classes from different packages.
import java.util.ArrayList; import java.util.HashMap; import java.time.LocalDate;
Each imported type has its own import declaration. This makes it clear which external types the source file uses.
Importing All Types from a Package
Java also supports wildcard imports using an asterisk.
import java.util.*;
This allows types directly inside the java.util package to be referenced by their simple names.
Remember: The wildcard * imports types directly from the specified package. It does not recursively import types from subpackages.
Example of a Wildcard Import
import java.util.*;
public class Main {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
HashMap<Integer, String> students = new HashMap<>();
}
}
Both ArrayList and HashMap belong directly to java.util, so the wildcard import makes their simple names available.
Importing from Subpackages
Packages and subpackages are separate namespaces. Importing a package does not automatically import its subpackages.
import java.util.*; java.time.LocalDate date = java.time.LocalDate.now();
The wildcard import for java.util does not make java.time available by simple name.
Importing a Static Member
Java also provides static imports for static fields and methods. For example:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
public class Main {
public static void main(String[] args) {
double radius = 5;
double area = PI * radius * radius;
System.out.println(sqrt(25));
System.out.println(area);
}
}
Static imports are useful when a static member is used frequently and its owning class name would otherwise add unnecessary repetition. However, they should be used carefully because excessive static imports can make the source of a method or constant less obvious.
Importing a Class vs Using a Fully Qualified Name
An import statement is not mandatory. Java allows a class to be referenced using its fully qualified name.
public class Main {
public static void main(String[] args) {
java.time.LocalDate today =
java.time.LocalDate.now();
System.out.println(today);
}
}
The same code can be made cleaner with an import.
import java.time.LocalDate;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println(today);
}
}
When Two Classes Have the Same Name
A common situation in larger applications is having two classes with the same simple name but different packages.
com.school.Student com.college.Student
You cannot simply import both and then use Student, because Java would not know which type you mean.
import com.school.Student; import com.college.Student;
Instead, import one class and use the fully qualified name for the other when necessary.
import com.school.Student;
public class Main {
public static void main(String[] args) {
Student schoolStudent = new Student();
com.college.Student collegeStudent =
new com.college.Student();
}
}
Important: An import declaration does not rename a class. Java does not provide an alias syntax such as import package.Class as Alias.
Importing from the Same Package
A class does not need to explicitly import another class that belongs to the same package.
package com.example.school;
public class Student {
}
package com.example.school;
public class Main {
public static void main(String[] args) {
Student student = new Student();
}
}
Since both classes belong to com.example.school, the Student type can be referenced directly.
java.lang Does Not Need Explicit Import
Java automatically makes the types in the java.lang package available to every source file. That is why classes such as String, System, and Math can normally be used without writing explicit imports.
public class Main {
public static void main(String[] args) {
String message = "Hello";
System.out.println(message);
}
}
Conceptually, Java provides automatic access to the standard java.lang package, so developers do not have to add imports for its commonly used types.
Import Statements Do Not Copy Classes
One of the most important things to understand is that an import statement does not copy a class into your project or physically move it into another package.
It simply allows the compiler to resolve a type name using a shorter form.
import com.example.school.Student; Student student = new Student();
The Student class still belongs to com.example.school. The import only lets this source file refer to it using the simple name.
Common Beginner Mistakes
- Placing an import statement inside a class or method.
- Assuming that import java.util.* imports subpackages.
- Trying to import two classes with the same simple name and expecting Java to choose automatically.
- Thinking that an import physically copies a class into the current package.
- Adding unnecessary imports for classes already available from the same package or automatically available packages.
Best Practices
- Prefer clear, explicit imports when they make dependencies easier to understand.
- Avoid unnecessary wildcard imports in codebases where explicit dependencies improve readability.
- Use fully qualified names when two imported types have the same simple name.
- Keep imports organized according to the conventions used by your project or IDE.
- Use static imports selectively rather than importing many static members without a clear reason.
Interview Insight
A common interview question is, "What is the purpose of the import statement?" A strong answer is: An import statement allows a Java source file to refer to a type from another package using its simple name instead of repeatedly writing its fully qualified name. It improves source-code readability but does not copy or move the imported type.
Interview Tip: Another useful point is that importing a class does not make its private members accessible. Access control is still determined by Java's access modifiers and package rules.
Quick Revision
| Concept | Key Point |
|---|---|
| import | Allows a type to be referenced by its simple name. |
| Syntax | import packageName.ClassName; |
| Wildcard | packageName.* imports types directly in that package, not subpackages. |
| Same package | Classes in the same package do not need explicit imports for each other. |
| java.lang | Its types are automatically available without explicit imports. |
| Duplicate names | Use a fully qualified name when two required types have the same simple name. |
| Purpose | Improves readability and simplifies references to types from other packages. |
The import statement is a small feature with a major impact on everyday Java code. It keeps source files readable while allowing classes to remain properly organized across packages. Once normal imports are clear, the next step is understanding static imports, which provide a different way to access static methods and fields directly.
