Java Full Course: Mastering the Language Packages in Java

Packages in Java

1. What is a Package?

A package is a namespace that groups related classes, interfaces, enums, and annotations. It serves two main purposes:

  • Organization – Keeps code structured and makes it easier to locate related types.
  • Access control – Provides a visibility level (package‑private) that is accessible only within the same package.

Packages also help avoid naming conflicts. For example, you can have a com.example.Customer class and a com.other.Customer class without collision.

2. Creating Packages

a) The package Statement

To declare a class inside a package, you use the package keyword at the very top of the source file (before any imports or class definitions).

package com.example.myapp; public class MyClass { // ... }
  • The package statement must be the first line (except comments).
  • Only one package statement per source file.
  • If omitted, the class belongs to the default package (no package name). Using the default package is discouraged for anything beyond trivial examples.

b) Directory Structure

The Java compiler and runtime map package names to directory structures. A class com.example.myapp.MyClass must be stored in a directory hierarchy: com/example/myapp/MyClass.java (or .class).

Example structure:

src/ com/ example/ myapp/ MyClass.java AnotherClass.java utils/ Helper.java

When compiling from the root of the source tree:

javac com/example/myapp/*.java

The compiled .class files will be placed in corresponding directories, preserving the package structure.

c) Multiple Classes in One File

A single .java file can contain only one public class (with the same name as the file), but it can contain additional non‑public classes. All classes in that file belong to the same package.

3. Importing Packages

Once classes are organized in packages, you need a way to refer to them from other packages. Java provides the import statement to avoid writing fully qualified names repeatedly.

a) Fully Qualified Name

You can always use the full package path:

com.example.myapp.MyClass obj = new com.example.myapp.MyClass();

This becomes cumbersome for frequently used classes.

b) Import Statement

The import statement allows you to use the simple name of a class or interface.

import com.example.myapp.MyClass; import com.example.myapp.AnotherClass; public class Test { public static void main(String[] args) { MyClass obj = new MyClass(); // no need for full package AnotherClass another = new AnotherClass(); } }

c) Importing All Classes from a Package

Use * to import all classes from a package (but not sub‑packages).

import com.example.myapp.*; // imports MyClass, AnotherClass, etc.

This does not cause performance overhead; it simply makes all public types in that package available by simple name.

d) Static Imports (Java 5+)

Static import allows you to import static members (fields and methods) so you can use them without the class name.

import static java.lang.Math.PI; import static java.lang.Math.sqrt; public class Circle { public static void main(String[] args) { double area = PI * 5 * 5; // instead of Math.PI double root = sqrt(25); // instead of Math.sqrt } }

You can also import all static members:

import static java.lang.Math.*;

e) Implicitly Imported Packages

  • java.lang is automatically imported for every class (so you can use String, System, Math, etc.).
  • No other packages are automatically imported.

f) Import Ambiguity

If two packages have a class with the same name, you cannot import both with * and use the simple name. You must either:

  • Use fully qualified names for the conflicting classes.
  • Import one class explicitly and use fully qualified for the other.
import java.util.Date; // import java.sql.Date; // would conflict // Instead, use fully qualified for java.sql.Date: java.sql.Date sqlDate = new java.sql.Date(...);

4. Package Naming Conventions

Java has well‑established naming conventions to ensure uniqueness and readability.

  • a) Reverse Domain Name: To create globally unique package names, developers are encouraged to use a reversed internet domain name (which is unique). For example, if your domain is example.com, package names start with com.example.
    • com.example.myapp
    • org.apache.commons.lang3
  • b) Lowercase Letters: Package names should be entirely lowercase. Avoid underscores and other characters; if a natural separator is needed, use another word (e.g., myapp not my_app).
  • c) Hierarchical Structure: Packages often reflect the module or component structure. For example: com.example.project.module.submodule
  • d) Standard Prefixes:
    • java.*: core Java packages (reserved)
    • javax.*: extension packages (formerly optional)
    • org.*: for organizations
    • com.*: for commercial entities
  • e) Avoid Default Package: Never put classes in the default package (no package statement) for anything beyond quick experiments. It leads to naming collisions and prevents proper access control.

5. Access Protection with Packages

Access modifiers (public, protected, default, private) interact with packages to define visibility.

ModifierSame ClassSame PackageSubclass (different package)Any Class
private
(default / package‑private)
protected
public
  • default (no modifier) – also called package‑private. Only accessible within the same package. This is the key access level tied to packages.
  • protected – accessible within same package and also in subclasses (even if the subclass is in a different package).
  • public – accessible everywhere.
  • private – accessible only in the same class.

a) Example of Package‑Private Access

// File: com/example/alpha/A.java package com.example.alpha; class A { // package‑private class int x; // package‑private field void m() {} // package‑private method }
// File: com/example/alpha/B.java package com.example.alpha; public class B { void test() { A a = new A(); // OK – same package a.x = 5; // OK a.m(); // OK } }
// File: com/example/beta/C.java package com.example.beta; public class C { void test() { // Error – A is not public // com.example.alpha.A a = new com.example.alpha.A(); } }

b) Protected and Inheritance

protected members are accessible in subclasses even across packages.

// com/example/alpha/Parent.java package com.example.alpha; public class Parent { protected void show() { System.out.println("Parent"); } }
// com/example/beta/Child.java package com.example.beta; import com.example.alpha.Parent; public class Child extends Parent { public void demo() { show(); // OK – inherited protected method Parent p = new Parent(); // p.show(); // Not allowed – protected not accessible via reference } }

c) Why Package‑Private Matters

Package‑private allows you to keep internal implementation details hidden from outside packages while still allowing close collaboration among classes within the same package. This is often used for internal utility classes or for frameworks where certain classes are meant to be used only within the module.

6. Complete Example

Below is a small example that demonstrates packages, imports, and access protection.

Directory structure:

src/ com/ example/ geometry/ Shape.java // abstract class Circle.java Rectangle.java app/ Main.java

File: com/example/geometry/Shape.java

package com.example.geometry; public abstract class Shape { // package‑private field – accessible only within geometry package String color; public Shape(String color) { this.color = color; } public abstract double area(); // package‑private method – for internal use only void displayColor() { System.out.println("Color: " + color); } }

File: com/example/geometry/Circle.java

package com.example.geometry; public class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } public void show() { displayColor(); // OK – same package System.out.println("Radius: " + radius); } }

File: com/example/geometry/Rectangle.java

package com.example.geometry; public class Rectangle extends Shape { private double width, height; public Rectangle(String color, double width, double height) { super(color); this.width = width; this.height = height; } @Override public double area() { return width * height; } public void show() { displayColor(); // OK – same package System.out.println("Width: " + width + ", Height: " + height); } }

File: com/example/app/Main.java

package com.example.app; import com.example.geometry.Circle; import com.example.geometry.Rectangle; import com.example.geometry.Shape; // we import Shape even though it's abstract public class Main { public static void main(String[] args) { Circle c = new Circle("Red", 5); Rectangle r = new Rectangle("Blue", 4, 6); c.show(); System.out.println("Area: " + c.area()); r.show(); System.out.println("Area: " + r.area()); } }

7. Key Points to Remember

Note

[!NOTE]

  • package statement defines the package; must be the first line (except comments).
  • Package names should be lowercase.
  • The directory structure must mirror the package hierarchy.
  • import statements let you use simple class names; import static imports static members.
  • java.lang is automatically imported.
  • Default (package‑private) access restricts visibility to classes within the same package.
  • protected adds inheritance across packages.
  • Avoid the default package; always place code in named packages for large projects.
Hi! Need help with studies? 👋
AI