Java • Functions and Program Structure

Imports & Qualified Names — Import classes and use fully qualified names when needed

Learn how Java organizes thousands of classes into packages and how import statements give your code clean, readable access to them.

Java programming emblem with a coffee cup, code braces, and terminal
Inside this lesson 10 sections 5 questions 5 figures

SECTION 1

Historical Context & Motivation

As programming languages matured through the 1980s and 1990s, projects grew from a few hundred lines of code to millions. Developers quickly realized they needed a way to organize classes into logical groups, much like organizing files into folders on your computer. Without such a system, two programmers on the same project could accidentally give different classes the same name, causing conflicts that were painful to resolve.

When James Gosling and the team at Sun Microsystems designed Java in the early 1990s, they borrowed the concept of packages from earlier languages like Modula-2 and Ada. Packages give every class a unique address—its fully qualified name—so that name collisions become virtually impossible. The import statement was introduced as a convenience so that programmers wouldn't have to type out long package paths every single time they used a class.

1970s • Modular Programming Emerges

Languages like Modula-2 introduce the idea of modules—separate, self-contained units of code that can be imported into other programs.

1995 • Java 1.0 Released

Java launches with a built-in package system and the import keyword. The standard library ships with packages like java.lang, java.util, and java.io.

2004 • Java 5 — Static Imports

Java 5 adds 'import static', allowing programmers to import individual static methods and constants without qualifying them with the class name.

2017 • Java 9 — Module System

Project Jigsaw introduces modules, a higher-level grouping above packages. Imports and qualified names remain the everyday mechanism for accessing classes.

The fundamental question Java's package-and-import system addresses is: How do you give every class a unique identity while still keeping your code short and readable? Understanding imports and qualified names is the answer to that question, and it's a skill you'll use in every Java program you write.

SECTION 2

Core Principles & Definitions

Before you can use a class from the Java standard library—or from any external library—you need to tell the compiler where to find it. Java provides two main approaches: writing the class's full package path every time (its fully qualified name), or declaring an import at the top of your file so you can use just the short class name. Let's define the key ideas you'll need.

1

Package

A namespace that groups related classes together. For example, java.util contains utility classes like ArrayList and HashMap. Think of a package as a folder in a file system.
2

Fully Qualified Name (FQN)

The complete path to a class, including its package. For example, java.util.ArrayList is the FQN for ArrayList. It's like a full mailing address—city, street, and house number.
3

Import Statement

A declaration at the top of a Java file that tells the compiler which class you want to use by its short name. Writing import java.util.ArrayList; lets you type just ArrayList everywhere in the file.
4

Wildcard Import

Using import java.util.*; imports all classes from a package at once. It's convenient but can sometimes cause ambiguity if two packages share a class name.
5

java.lang — The Automatic Import

Classes in java.lang (like String, Math, Integer, and System) are automatically imported in every Java file. You never need to write an import for them.
✦

KEY TAKEAWAY

Think of a fully qualified name like a phone number with the country code and area code included—it always works but is long to dial. An import statement is like saving that number as a contact: once saved, you just tap the name. Both reach the same class; imports simply save you typing.

SECTION 3

Visual Explanation — How Packages & Imports Connect

The diagram below shows how a Java source file relates to the package tree. On the left you see the package hierarchy, and on the right you see how your code references classes from those packages through either an import statement or a fully qualified name.

Package Hierarchy → Import → UsagePACKAGE TREEjavajava.utiljava.ioArrayListScannerFileYOUR SOURCE FILE (MyApp.java)import java.util.ArrayList;import java.util.Scanner;// no import needed for java.lang.Stringpublic class MyApp {ArrayList<String> list;// ↑ short name (via import)Scanner sc = new Scanner(...);// ↑ short name (via import)java.io.File f = new java.io.File("x");// ↑ fully qualified name (no import)}
The package tree (left) shows classes organized under java.util and java.io. The source file (right) uses import statements for ArrayList and Scanner, enabling short names. The File class is used with its fully qualified name because there is no import for it.

Notice how the dashed arrows connect each class in the package tree to where it appears in the source code. The cyan arrows represent classes brought in through import statements, while the amber arrow shows a class accessed through its fully qualified name. Both methods work correctly—the choice depends on how often you use the class and whether you want cleaner code or more explicit references.

SECTION 4

How Imports & Qualified Names Work Under the Hood

It's important to understand that import statements do NOT load or copy code into your file. They are purely a convenience for the compiler. When you write import java.util.ArrayList;, you're telling the compiler: "Whenever I write ArrayList, I mean java.util.ArrayList." The compiled bytecode is identical whether you use an import or the fully qualified name.

The Three Forms of Class Reference

Java gives you three syntactic approaches to reference a class from another package. Each has its place.

1. Single-Type Import

The single-type import imports exactly one class. This is the most common and recommended form. You write import java.util.ArrayList; at the top of your file, and then use ArrayList by itself anywhere in the file. It makes your code clear because anyone reading it can see exactly which classes you depend on.

2. Wildcard Import

The wildcard import uses an asterisk to import every class from a package: import java.util.*;. This is convenient when you need many classes from the same package. However, it does NOT import sub-packages. Writing import java.*; does not give you classes from java.util or java.io.

3. Fully Qualified Name (Inline)

You can skip the import entirely and use the fully qualified name right in the code: java.io.File myFile = new java.io.File("data.txt");. This is most useful when you only use a class once or twice, or when two packages contain classes with the same name and you need to disambiguate.

⚠

Common Pitfall: Name Collisions

Both java.util and java.sql contain a class called Date. If you wildcard-import both packages, the compiler won't know which Date you mean. The fix: use a single-type import for the one you use most, and the fully qualified name for the other.

SECTION 5

Syntax Details & Classification

Let's look at every type of import statement side by side, with syntax rules and key notes. The table below serves as a quick-reference guide you can return to while coding.

Import TypeSyntax ExampleWhat It DoesWhen to Use
Single-typeimport java.util.ArrayList;Imports one specific classDefault choice; clear and precise
Wildcardimport java.util.*;Imports all classes in a packageWhen using many classes from one package
Staticimport static java.lang.Math.PI;Imports a static field or methodWhen using constants/methods from a utility class repeatedly
Fully Qualifiedjava.io.File f = ...;No import; uses full path inlineRare usage or resolving name collisions
Auto-imported(no statement needed)java.lang.* is always availableString, Math, System, Integer, etc.

Summary of all import types in Java

Anatomy of a Java Source FileMyApp.javapackage com.school.myproject;← ① Package declimport java.util.ArrayList;← ② Importsimport java.util.Scanner;import static java.lang.Math.sqrt;← ③ Static import← ④ Class bodypublic class MyApp {ArrayList<String> names;// short name ✓double val = sqrt(16);// static import ✓java.io.File f = new java.io.File("x");// FQN ✓}
A Java source file has a strict ordering: ① package declaration (optional), then ② import statements, then ④ class definitions. You cannot place imports inside a class or after it.
ℹ

Rule of File Structure

The order inside a Java file is always: package → imports → class. The package declaration (if present) must be the very first non-comment line. Imports come next. The class definition follows. Violating this order causes a compile error.

SECTION 6

Worked Example — Building a Student Roster Program

Let's walk through a realistic example. Suppose you're writing a program that reads student names from the keyboard, stores them in a list, sorts them alphabetically, and writes the result to a file. You'll need classes from multiple packages.

Creating a Sorted Student Roster

  1. 1

    Step 1 — Identify the Classes You Need

    Think about what operations you'll perform. Reading keyboard input requires java.util.Scanner. Storing a dynamic list of names requires java.util.ArrayList. Sorting requires java.util.Collections. Writing to a file requires java.io.PrintWriter.
    Four classes needed from two packages: java.util and java.io
  2. 2

    Step 2 — Write the Import Statements

    Since you need three classes from java.util, you could use three single-type imports or one wildcard import. Since you only need one class from java.io, a single-type import is clearest. Your imports would look like this: import java.util.ArrayList;, import java.util.Collections;, import java.util.Scanner;, and import java.io.PrintWriter;.
    Four import statements placed before the class definition
  3. 3

    Step 3 — Use Short Names in the Class Body

    Inside your class, you can now write Scanner input = new Scanner(System.in); and ArrayList<String> roster = new ArrayList<>(); without any package prefixes. Notice that String and System don't need imports because they're in java.lang.
    Short names like Scanner, ArrayList, and PrintWriter work everywhere in the file
  4. 4

    Step 4 — Sort and Write Output

    After collecting names in a loop, call Collections.sort(roster); to sort alphabetically. Then create a PrintWriter out = new PrintWriter("roster.txt"); and loop through the roster to write each name. Close the writer with out.close();.
    Complete program uses four imported classes cleanly, with no fully qualified names needed
💡

Alternative Approach

You could replace the three java.util imports with a single import java.util.*;. The compiled program behaves identically. However, many coding style guides (and AP CS conventions) prefer single-type imports because they make dependencies more explicit.

SECTION 7

Comparing Import Strategies

Each approach to referencing classes has trade-offs. The table below summarizes the strengths and limitations of each strategy so you can make informed decisions in your own projects.

StrategyStrengthsLimitations
Single-type importExplicit; easy to see dependencies; avoids name collisions; preferred by most style guidesCan lead to long import lists in large programs
Wildcard importShorter import section; convenient when using many classes from one packageCan cause ambiguity if two wildcarded packages share a class name; harder to see what's actually used
Fully qualified nameNo import needed; unambiguous; resolves name collisions instantlyVery verbose; clutters code if used repeatedly
Static importReduces repetitive class prefixes for utility methods and constants (e.g., Math.PI becomes PI)Overuse can make it unclear where a method or constant comes from

Trade-offs of each import strategy in Java

✦

KEY TAKEAWAY

Think of single-type imports like a grocery list that names every item: it's clear and organized. Wildcard imports are like writing "everything from the dairy aisle"—faster to write but vague. Fully qualified names are like giving the full GPS coordinates every time—always accurate but tedious. Use the right tool for the situation: single-type imports for most cases, fully qualified names for name collisions, and wildcards sparingly.

SECTION 8

Connection to Advanced Concepts

The import system you've learned is the daily workhorse of Java programming, but it sits within a larger ecosystem that you'll encounter as you advance. Understanding how imports connect to more sophisticated features will prepare you for AP Computer Science topics and college-level Java development.

Concept You LearnedAdvanced ExtensionWhy It Matters
Packages group related classesJava Modules (Java 9+) group related packagesModules add a higher level of access control and dependency management
Import resolves short names at compile timeClass loading loads bytecode at runtimeThe JVM's ClassLoader dynamically finds and loads .class files when they're first needed
Wildcard imports can cause name collisionsDependency management tools like Maven and GradleBuild tools automatically manage which library JARs are available, preventing classpath conflicts at scale
Static imports for utility methodsFramework annotations and dependency injectionFrameworks like Spring use annotations and automatic scanning to wire classes together, going beyond manual imports

How today's concepts connect to advanced Java development

For now, focus on mastering single-type imports and knowing when to reach for a fully qualified name. These fundamentals will carry you through AP Computer Science A and beyond. As your projects grow, tools like IDEs (Integrated Development Environments) such as IntelliJ IDEA and Eclipse can automatically manage your import statements, but understanding what they do behind the scenes is essential for debugging and writing code on exams.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

Explain why String can be used in any Java file without an import statement, but ArrayList cannot. What is special about the package that String belongs to?
Show answer
String belongs to the java.lang package, which Java automatically imports into every source file. This is the only package that receives this special treatment. ArrayList, on the other hand, belongs to java.util, which is not auto-imported. Because java.lang contains the most fundamental classes (String, System, Math, Integer, etc.), the language designers decided to always import it so that every program could use these essentials without extra boilerplate.

Question 2: BASIC

Write the import statement(s) needed so that the following code compiles. Do NOT use wildcard imports. public class Quiz { public static void main(String[] args) { HashMap<String, Integer> scores = new HashMap<>(); Scanner kb = new Scanner(System.in); } }
Show answer
You need two single-type import statements: import java.util.HashMap; and import java.util.Scanner;. Both HashMap and Scanner are in the java.util package. String and System don't need imports because they're in java.lang. Integer also doesn't need an import for the same reason. These two import statements should be placed before the class definition.

Question 3: INTERMEDIATE

A student writes the following code and gets a compile error saying "reference to Date is ambiguous." Explain why the error occurs and provide two different ways to fix it. import java.util.*; import java.sql.*; public class Report { Date today = new Date(); }
Show answer
The error occurs because both java.util and java.sql contain a class named Date. When both packages are wildcard-imported, the compiler doesn't know which Date you mean. Fix 1: Replace one wildcard with a single-type import. For example, keep import java.sql.*; but change the other to import java.util.Date;. The single-type import takes precedence over the wildcard. Fix 2: Use the fully qualified name in the code itself: java.util.Date today = new java.util.Date();. Both solutions eliminate the ambiguity.

Question 4: APPLIED

You're writing a program that reads numbers from a file, sorts them, and writes statistics. You need java.io.File, java.io.PrintWriter, java.util.Scanner, java.util.ArrayList, and java.util.Collections. Write the complete set of import statements. Would a wildcard import for java.util be reasonable here? Justify your answer.
Show answer
Using single-type imports: import java.io.File;, import java.io.PrintWriter;, import java.util.ArrayList;, import java.util.Collections;, import java.util.Scanner;. A wildcard import for java.util.* would be reasonable here because you're using three classes from that package, which is a significant number. It would reduce five import lines to three. However, if your project also uses java.sql, the wildcard could introduce ambiguity with shared class names like Date. In this case, since no other packages conflict, the wildcard is acceptable.

Question 5: CRITICAL THINKING

A classmate argues: "Wildcard imports are always better because they're shorter, and they don't affect performance since imports don't load code." Evaluate this argument. Is it entirely correct, partially correct, or wrong? Explain at least two factors the classmate is overlooking.
Show answer
The classmate is partially correct. It's true that imports (wildcard or not) have zero runtime performance impact—they're resolved at compile time and don't cause extra classes to be loaded. However, the argument overlooks at least two important factors. First, readability and maintainability: single-type imports act as documentation, showing exactly which classes a file depends on. A developer reading the code can quickly see the dependencies without scanning the entire file. Second, name collision risk: wildcard imports from multiple packages can cause ambiguous reference errors if packages share class names (like java.util.Date and java.sql.Date). A third consideration is that modern IDEs manage imports automatically, so the "shorter to type" advantage is largely irrelevant in practice. The best approach balances conciseness with clarity.

SUMMARY

Lesson Summary

Summary

Java organizes classes into packages—logical namespaces that prevent name collisions and keep large codebases orderly. Every class has a fully qualified name (FQN) that includes its package path (like java.util.ArrayList). To avoid typing the full path repeatedly, you place import statements at the top of your file. A single-type import (e.g., import java.util.Scanner;) is the clearest and most recommended form. A wildcard import (e.g., import java.util.*;) brings in all classes from a package at once but can cause ambiguity.

Classes in java.lang (like String, Math, and System) are auto-imported and never need an import statement. When two packages contain a class with the same name, use the FQN inline or a single-type import to resolve the conflict. Remember that imports are a compile-time convenience only—they don't affect performance or load extra code. A Java file follows a strict structure: package declaration → imports → class definition.

Varsity Tutors • Java • Imports & Qualified Names