Back to Class Loading & Compilation
Q4Question 4 of 4

What are packages and how do imports work?

Key Concepts
  • A package is a namespace that organizes classes: com.bank.core, com.bank.service
  • Package declaration must be the first statement in the file
  • import lets you use a class by simple name instead of fully qualified name
  • import java.util.List; or import java.util.*; (wildcard)
  • java.lang is auto-imported – String, System, Object need no import
  • Static import: import static java.lang.Math.sqrt; → use sqrt() directly

Definition

Packages organize classes into namespaces. Imports let you use classes by simple name instead of the full package path. java.lang is auto-imported.

Package and import rules:

  • Package declaration: package com.bank.core; – first line, matches directory structure.
  • Import: import java.util.List; – use List instead of java.util.List.
  • Wildcard: import java.util.*; – imports all classes in the package.
  • Auto-import: java.lang.* (String, System, Object, Math) is always imported.
  • Static import: import static java.lang.Math.PI; – use PI directly.

Packages are like departments in a bank: com.bank.core (core domain), com.bank.service (business logic), com.bank.api (REST controllers). Imports are like putting shortcuts on your desk so you do not have to walk to the other department every time.

Understanding the Concepts

Package declaration

Every Java source file can have at most one package declaration, and it must be the very first statement in the file (before any import or class declaration). The package name must match the directory structure on disk.

JAVA
package com.bank.core;  // must be the first statement

public class Account {
    // class body
}

The file must be stored at com/bank/core/Account.java (matching the package). If the directory structure does not match, the compiler reports an error.

Import types

Java provides four forms of import. Specific imports bring in one class. Wildcard imports bring in all classes from one package. Static imports bring in static members of a class. You can also use a fully qualified name inline without any import.

JAVA
import java.util.List;              // specific class import
import java.util.ArrayList;
import java.util.*;                  // wildcard: all classes in java.util
import static java.lang.Math.sqrt;  // static: use sqrt() without Math.
import static java.lang.Math.*;     // all static members of Math

Specific imports are preferred over wildcard imports because they make dependencies explicit and avoid name conflicts.

What java.lang gives you for free

The java.lang package is automatically imported into every Java source file. You never need to write import java.lang.String or import java.lang.System.

JAVA
// No import needed for any of these:
String name = "Rajesh";              // java.lang.String
System.out.println(name);            // java.lang.System
Object obj = new Object();           // java.lang.Object
int max = Integer.MAX_VALUE;         // java.lang.Integer
double pi = Math.PI;                 // java.lang.Math
NullPointerException npe;            // java.lang.NullPointerException

Common naming conventions in banking projects

Package names follow the reverse domain convention. In a banking application, packages organize code by responsibility.

DIAGRAM
com.bank.core       → domain models (Account, Transaction, Customer)
com.bank.service    → business logic (TransferService, InterestService)
com.bank.repository → data access (AccountRepository, TransactionRepository)
com.bank.api        → REST controllers (AccountController, TransferController)
com.bank.config     → configuration (AppConfig, SecurityConfig)
com.bank.util       → utility classes (AccountNumberGenerator, CurrencyFormatter)
com.bank.exception  → custom exceptions (InsufficientFundsException)

How do import conflicts work?

When two packages contain classes with the same name, a wildcard import creates ambiguity. The compiler cannot decide which class you mean. You must use either a specific import or the fully qualified name.

JAVA
package com.bank.report;

import java.util.Date;      // java.util.Date
import java.sql.Date;       // COMPILE ERROR: Date is ambiguous

// Fix 1: import one, qualify the other
import java.util.Date;

public class AuditReport {
    Date createdDate = new Date();                       // java.util.Date
    java.sql.Date sqlDate = java.sql.Date.valueOf("2024-01-15"); // fully qualified
}

This conflict is common in banking applications that mix utility dates with JDBC query dates.

What about static imports?

Static imports let you use static methods and constants without the class name prefix. They are useful for test assertions and mathematical operations.

JAVA
package com.bank.service;

import java.math.BigDecimal;
import static java.math.BigDecimal.ZERO;
import static java.math.RoundingMode.HALF_UP;

public class InterestCalculator {
    public BigDecimal calculateMonthlyInterest(BigDecimal balance, BigDecimal annualRate) {
        if (balance.compareTo(ZERO) <= 0) {  // ZERO from static import
            return ZERO;
        }
        return balance.multiply(annualRate)
                      .divide(new BigDecimal("1200"), 2, HALF_UP);  // HALF_UP from static import
    }
}

Use static imports sparingly. Overusing them makes code harder to read because the reader cannot tell where a name comes from.

What should a senior engineer know?

  • Wildcard imports do not import sub-packages. import java.util.* does NOT import java.util.concurrent.*. Each package must be imported separately.
  • Module system (Java 9+) adds module-info.java with requires and exports declarations. Modules control which packages are visible to other modules, adding a layer beyond just public/private access.
  • Import conflicts with same class name: always prefer specific imports and use fully qualified names for the second class.
  • IDE auto-import handles most import management. IntelliJ can be configured to use specific imports or wildcard imports based on a threshold (typically 5 classes from the same package).
  • No runtime cost. Imports are a compile-time convenience. Wildcard imports do not load extra classes into memory. The JVM loads classes only when they are first used.

Visual Overview

DIAGRAM
  package com.bank.core;
  import java.util.List;
  import java.math.BigDecimal;

  public class Account {
    List<String> txns;        ← uses List (from import)
    BigDecimal balance;       ← uses BigDecimal (from import)
    String name;              ← uses String (auto-imported from java.lang)
  }

  Directory: com/bank/core/Account.java

Key Takeaway

Packages organize classes into namespaces matching the directory structure. Imports let you use classes by simple name. java.lang is auto-imported. Static imports let you use static members without the class name.

One sentence to remember: package declares the namespace, import provides shortcuts, java.lang is always available.

---

Share
Use ← → arrow keys to navigate