Creating Custom Packages in Java
Creating Custom Packages in Java
You understood what packages are — namespaces that organise classes and prevent naming conflicts. Now the practical question: how do you actually create one? The answer involves three things working together: the folder structure on disk, the package declaration at the top of your source file, and the way you compile and run the code. Get all three aligned and everything works. Misalign any one of them and the compiler tells you exactly what is wrong.
This article walks through creating packages from scratch, organising multi-package projects, compiling from the command line, the standard Maven/Gradle layout, and packaging into a JAR — the complete practical workflow.
The Three Things That Must Align
1. Folder on disk must match the package name:
package com.devstackflow.service;
│
└── file must live at: .../.../com/devstackflow/service/FileName.java
2. Package declaration must be the first statement:
package com.devstackflow.service; ← line 1
import java.util.List; ← imports after
public class OrderService { ... } ← class after imports
3. Compile from the source root (not from inside the package folder):
Correct: javac com/devstackflow/service/OrderService.java (from src/)
Wrong: javac OrderService.java (from inside the folder)
Step 1 — Create the Folder Structure
Start with a source root directory. Everything below it maps to package names. The directory name itself is not part of the package — only the path below the source root is.
Project layout (manual / command-line):
myproject/ ← project root
└── src/ ← source root
└── com/
└── devstackflow/
├── model/
│ ├── Student.java → package com.devstackflow.model
│ └── Course.java → package com.devstackflow.model
├── service/
│ └── StudentService.java → package com.devstackflow.service
└── Main.java → package com.devstackflow
To create these folders from the terminal:
mkdir -p src/com/devstackflow/model
mkdir -p src/com/devstackflow/service
Step 2 — Write the Source Files
Each source file must declare a package that matches its folder location.
1// File: src/com/devstackflow/model/Student.java
2
3package com.devstackflow.model;
4
5public class Student {
6
7 private final String studentId;
8 private final String name;
9 private double gpa;
10
11 public Student(String studentId, String name, double gpa) {
12 this.studentId = studentId;
13 this.name = name;
14 this.gpa = gpa;
15 }
16
17 public String getStudentId() { return studentId; }
18 public String getName() { return name; }
19 public double getGpa() { return gpa; }
20 public void setGpa(double gpa) { this.gpa = gpa; }
21
22 @Override
23 public String toString() {
24 return String.format("Student{id=%s, name=%s, gpa=%.2f}",
25 studentId, name, gpa);
26 }
27}1// File: src/com/devstackflow/model/Course.java
2
3package com.devstackflow.model;
4
5public class Course {
6
7 private final String courseId;
8 private final String title;
9 private final int credits;
10
11 public Course(String courseId, String title, int credits) {
12 this.courseId = courseId;
13 this.title = title;
14 this.credits = credits;
15 }
16
17 public String getCourseId() { return courseId; }
18 public String getTitle() { return title; }
19 public int getCredits() { return credits; }
20
21 @Override
22 public String toString() {
23 return String.format("Course{id=%s, title=%s, credits=%d}",
24 courseId, title, credits);
25 }
26}1// File: src/com/devstackflow/service/StudentService.java
2
3package com.devstackflow.service;
4
5import com.devstackflow.model.Course; // import from sibling package
6import com.devstackflow.model.Student; // import from sibling package
7
8import java.util.ArrayList;
9import java.util.Comparator;
10import java.util.List;
11import java.util.stream.Collectors;
12
13public class StudentService {
14
15 private final List<Student> students = new ArrayList<>();
16 private final List<Course> courses = new ArrayList<>();
17
18 public void enroll(Student student) {
19 students.add(student);
20 System.out.println("Enrolled: " + student.getName());
21 }
22
23 public void addCourse(Course course) {
24 courses.add(course);
25 }
26
27 public List<Student> getTopStudents(double minGpa) {
28 return students.stream()
29 .filter(s -> s.getGpa() >= minGpa)
30 .sorted(Comparator.comparingDouble(Student::getGpa).reversed())
31 .collect(Collectors.toList());
32 }
33
34 public void printRoster() {
35 System.out.println("═".repeat(45));
36 System.out.println(" ENROLLED STUDENTS");
37 System.out.println("═".repeat(45));
38 System.out.printf("%-12s %-20s %6s%n", "ID", "Name", "GPA");
39 System.out.println("-".repeat(45));
40 students.forEach(s ->
41 System.out.printf("%-12s %-20s %6.2f%n",
42 s.getStudentId(), s.getName(), s.getGpa()));
43 System.out.println("═".repeat(45));
44 }
45}1// File: src/com/devstackflow/Main.java
2
3package com.devstackflow;
4
5import com.devstackflow.model.Course;
6import com.devstackflow.model.Student;
7import com.devstackflow.service.StudentService;
8
9public class Main {
10
11 public static void main(String[] args) {
12
13 StudentService service = new StudentService();
14
15 service.addCourse(new Course("CS101", "Java Programming", 4));
16 service.addCourse(new Course("CS102", "Data Structures", 4));
17 service.addCourse(new Course("CS103", "Database Management", 3));
18
19 service.enroll(new Student("S001", "Priya Sharma", 8.9));
20 service.enroll(new Student("S002", "Rohan Mehta", 7.6));
21 service.enroll(new Student("S003", "Sneha Rao", 9.2));
22 service.enroll(new Student("S004", "Karan Singh", 6.8));
23 service.enroll(new Student("S005", "Ananya Iyer", 8.5));
24
25 System.out.println();
26 service.printRoster();
27
28 System.out.println("\nTop students (GPA >= 8.5):");
29 service.getTopStudents(8.5)
30 .forEach(s -> System.out.println(" " + s));
31 }
32}Step 3 — Compile the Package
Compile from the source root — the directory that contains the top-level package folder (com). Use -d to specify where the compiled .class files go.
Terminal commands (run from myproject/ directory):
# Compile all files — -d out puts .class files into the out/ directory
javac -d out src/com/devstackflow/model/Student.java
javac -d out src/com/devstackflow/model/Course.java
javac -d out src/com/devstackflow/service/StudentService.java
javac -d out src/com/devstackflow/Main.java
# Or compile everything at once using a wildcard (Linux/Mac):
javac -d out src/com/devstackflow/model/*.java \
src/com/devstackflow/service/*.java \
src/com/devstackflow/Main.java
# Windows:
javac -d out src\com\devstackflow\model\*.java ^
src\com\devstackflow\service\*.java ^
src\com\devstackflow\Main.java
After compilation, the out/ directory mirrors the package structure:
out/
└── com/
└── devstackflow/
├── model/
│ ├── Student.class
│ └── Course.class
├── service/
│ └── StudentService.class
└── Main.class
Step 4 — Run the Program
Run from the directory containing the compiled classes, specifying the fully qualified main class name.
# Run from the out/ directory cd out java com.devstackflow.Main # Or run without changing directories using -cp (classpath) java -cp out com.devstackflow.Main
Output:
Enrolled: Priya Sharma
Enrolled: Rohan Mehta
Enrolled: Sneha Rao
Enrolled: Karan Singh
Enrolled: Ananya Iyer
═════════════════════════════════════════════
ENROLLED STUDENTS
═════════════════════════════════════════════
ID Name GPA
---------------------------------------------
S001 Priya Sharma 8.90
S002 Rohan Mehta 7.60
S003 Sneha Rao 9.20
S004 Karan Singh 6.80
S005 Ananya Iyer 8.50
═════════════════════════════════════════════
Top students (GPA >= 8.5):
Student{id=S003, name=Sneha Rao, gpa=9.20}
Student{id=S001, name=Priya Sharma, gpa=8.90}
Student{id=S005, name=Ananya Iyer, gpa=8.50}
Standard Maven / Gradle Project Layout
In real projects, build tools like Maven and Gradle manage compilation automatically. They enforce a standard folder layout that maps directly to packages.
Maven / Gradle standard layout:
myproject/
├── pom.xml ← Maven build file (or build.gradle for Gradle)
└── src/
├── main/
│ ├── java/ ← SOURCE ROOT — package paths start here
│ │ └── com/
│ │ └── devstackflow/
│ │ ├── model/
│ │ │ └── Student.java
│ │ └── service/
│ │ └── StudentService.java
│ └── resources/ ← config files, SQL, application.properties
│ └── application.properties
└── test/
└── java/ ← TEST SOURCE ROOT — mirrors main structure
└── com/
└── devstackflow/
└── service/
└── StudentServiceTest.java
Maven pom.xml (minimal):
<project>
<groupId>com.devstackflow</groupId>
<artifactId>student-app</artifactId>
<version>1.0.0</version>
</project>
mvn compile → compiles src/main/java → target/classes/
mvn test → compiles and runs src/test/java/
mvn package → creates target/student-app-1.0.0.jar
With Maven or Gradle you never run javac manually. Just write the source files in the correct folder and let the build tool handle the rest.
Creating and Running a JAR File
A JAR (Java ARchive) bundles compiled .class files and resources into one distributable file. Packages must be set up correctly for the JAR to work.
Creating a JAR from the compiled output:
# First, create a manifest file specifying the main class
echo "Main-Class: com.devstackflow.Main" > manifest.txt
# Create the JAR
jar cfm student-app.jar manifest.txt -C out .
# Run the JAR
java -jar student-app.jar
# Or without manifest — specify main class explicitly
jar cf student-app.jar -C out .
java -cp student-app.jar com.devstackflow.Main
JAR internal structure (same as package structure):
student-app.jar
├── META-INF/
│ └── MANIFEST.MF
└── com/
└── devstackflow/
├── model/
│ ├── Student.class
│ └── Course.class
├── service/
│ └── StudentService.class
└── Main.class
Packages in the Same Directory — When to Use Separate Files
Every public class must be in its own file named exactly after the class. One file can contain multiple classes, but only one can be public.
1// File: src/com/devstackflow/model/OrderModels.java
2// One file, multiple package-private classes — acceptable for tightly related small types
3
4package com.devstackflow.model;
5
6// Only one public class per file — it must match the filename
7public class OrderItem {
8 private final String productId;
9 private final int quantity;
10 private final double price;
11
12 public OrderItem(String productId, int quantity, double price) {
13 this.productId = productId;
14 this.quantity = quantity;
15 this.price = price;
16 }
17
18 public double getLineTotal() { return price * quantity; }
19
20 @Override
21 public String toString() {
22 return productId + " x" + quantity + " @ Rs." + price;
23 }
24}
25
26// Package-private class — visible only within com.devstackflow.model
27class OrderStatus {
28 static final String PLACED = "PLACED";
29 static final String CONFIRMED = "CONFIRMED";
30 static final String SHIPPED = "SHIPPED";
31 static final String DELIVERED = "DELIVERED";
32 static final String CANCELLED = "CANCELLED";
33}1// File: src/com/devstackflow/model/OrderStatusDemo.java
2
3package com.devstackflow.model;
4
5public class OrderStatusDemo {
6
7 public static void main(String[] args) {
8
9 // OrderStatus is package-private — accessible here because we are in the same package
10 System.out.println("PLACED : " + OrderStatus.PLACED);
11 System.out.println("DELIVERED : " + OrderStatus.DELIVERED);
12
13 OrderItem item = new OrderItem("PROD-001", 2, 599.0);
14 System.out.println("Item : " + item);
15 System.out.println("Total : Rs." + item.getLineTotal());
16 }
17}Output:
PLACED : PLACED
DELIVERED : DELIVERED
Item : PROD-001 x2 @ Rs.599.0
Total : Rs.1198.0
Real-World Example — Payment Module Package Structure
The Business Problem
A payment processing backend at a company like PhonePe or Razorpay organises its payment-related code into a structured package hierarchy. Creating this package structure correctly — with all files in their right folders, all declarations matching, and clean imports between packages — is the day-one task for any Java developer joining such a team.
1// Package: com.phonepay.payment.model
2
3// File: src/com/phonepay/payment/model/PaymentRequest.java
4package com.phonepay.payment.model;
5
6public class PaymentRequest {
7
8 private final String paymentId;
9 private final String merchantId;
10 private final String customerId;
11 private final double amount;
12 private final String currency;
13
14 public PaymentRequest(String paymentId, String merchantId,
15 String customerId, double amount) {
16 this.paymentId = paymentId;
17 this.merchantId = merchantId;
18 this.customerId = customerId;
19 this.amount = amount;
20 this.currency = "INR";
21 }
22
23 public String getPaymentId() { return paymentId; }
24 public String getMerchantId() { return merchantId; }
25 public String getCustomerId() { return customerId; }
26 public double getAmount() { return amount; }
27 public String getCurrency() { return currency; }
28
29 @Override
30 public String toString() {
31 return String.format("PaymentRequest[%s | merchant=%s | customer=%s | Rs.%.2f]",
32 paymentId, merchantId, customerId, amount);
33 }
34}1// File: src/com/phonepay/payment/model/PaymentResult.java
2package com.phonepay.payment.model;
3
4public class PaymentResult {
5
6 public enum Status { SUCCESS, FAILED, PENDING }
7
8 private final String paymentId;
9 private final Status status;
10 private final String message;
11 private final String transactionRef;
12
13 public PaymentResult(String paymentId, Status status,
14 String message, String transactionRef) {
15 this.paymentId = paymentId;
16 this.status = status;
17 this.message = message;
18 this.transactionRef = transactionRef;
19 }
20
21 public String getPaymentId() { return paymentId; }
22 public Status getStatus() { return status; }
23 public String getMessage() { return message; }
24 public String getTransactionRef(){ return transactionRef; }
25
26 @Override
27 public String toString() {
28 return String.format("PaymentResult[%s | status=%s | ref=%s | %s]",
29 paymentId, status, transactionRef, message);
30 }
31}1// File: src/com/phonepay/payment/util/PaymentIdGenerator.java
2package com.phonepay.payment.util;
3
4import java.time.LocalDateTime;
5import java.time.format.DateTimeFormatter;
6import java.util.concurrent.atomic.AtomicInteger;
7
8public class PaymentIdGenerator {
9
10 private static final AtomicInteger counter = new AtomicInteger(1000);
11 private static final DateTimeFormatter formatter =
12 DateTimeFormatter.ofPattern("yyyyMMddHHmm");
13
14 public static String generate() {
15 String timestamp = LocalDateTime.now().format(formatter);
16 return "PAY-" + timestamp + "-" + counter.getAndIncrement();
17 }
18}1// File: src/com/phonepay/payment/service/PaymentService.java
2package com.phonepay.payment.service;
3
4import com.phonepay.payment.model.PaymentRequest;
5import com.phonepay.payment.model.PaymentResult;
6import com.phonepay.payment.model.PaymentResult.Status;
7import com.phonepay.payment.util.PaymentIdGenerator;
8
9import java.util.ArrayList;
10import java.util.List;
11
12public class PaymentService {
13
14 private final List<PaymentResult> ledger = new ArrayList<>();
15
16 public PaymentResult process(PaymentRequest request) {
17
18 // Basic validation — real systems call bank APIs here
19 if (request.getAmount() <= 0) {
20 return new PaymentResult(
21 request.getPaymentId(), Status.FAILED,
22 "Invalid amount", null);
23 }
24
25 if (request.getMerchantId() == null || request.getMerchantId().isBlank()) {
26 return new PaymentResult(
27 request.getPaymentId(), Status.FAILED,
28 "Merchant ID required", null);
29 }
30
31 // Simulate success
32 String txnRef = PaymentIdGenerator.generate();
33 PaymentResult result = new PaymentResult(
34 request.getPaymentId(), Status.SUCCESS,
35 "Payment processed successfully", txnRef);
36
37 ledger.add(result);
38 return result;
39 }
40
41 public void printLedger() {
42 System.out.println("═".repeat(70));
43 System.out.printf("%-20s %-10s %-30s%n", "Payment ID", "Status", "Transaction Ref");
44 System.out.println("-".repeat(70));
45 ledger.forEach(r ->
46 System.out.printf("%-20s %-10s %-30s%n",
47 r.getPaymentId(), r.getStatus(), r.getTransactionRef()));
48 System.out.println("═".repeat(70));
49 }
50}1// File: src/com/phonepay/PaymentApp.java
2package com.phonepay;
3
4import com.phonepay.payment.model.PaymentRequest;
5import com.phonepay.payment.model.PaymentResult;
6import com.phonepay.payment.service.PaymentService;
7
8public class PaymentApp {
9
10 public static void main(String[] args) {
11
12 System.out.println("╔══════════════════════════════════════════╗");
13 System.out.println("║ PHONEPAY PAYMENT MODULE DEMO ║");
14 System.out.println("╚══════════════════════════════════════════╝\n");
15
16 PaymentService service = new PaymentService();
17
18 PaymentRequest[] requests = {
19 new PaymentRequest("P001", "MID-123", "CUST-501", 1299.50),
20 new PaymentRequest("P002", "MID-123", "CUST-502", 499.00),
21 new PaymentRequest("P003", "", "CUST-503", 2499.00), // invalid merchant
22 new PaymentRequest("P004", "MID-456", "CUST-504", -100.00), // invalid amount
23 new PaymentRequest("P005", "MID-456", "CUST-505", 5999.00),
24 };
25
26 System.out.println("Processing payments:");
27 System.out.println("─".repeat(70));
28
29 for (PaymentRequest req : requests) {
30 System.out.println(" Request : " + req);
31 PaymentResult result = service.process(req);
32 System.out.println(" Result : " + result);
33 System.out.println();
34 }
35
36 System.out.println("Successful Transactions:");
37 service.printLedger();
38 }
39}Output:
╔══════════════════════════════════════════╗
║ PHONEPAY PAYMENT MODULE DEMO ║
╚══════════════════════════════════════════╝
Processing payments:
──────────────────────────────────────────────────────────────────────
Request : PaymentRequest[P001 | merchant=MID-123 | customer=CUST-501 | Rs.1299.50]
Result : PaymentResult[P001 | status=SUCCESS | ref=PAY-202401151030-1000 | Payment processed successfully]
Request : PaymentRequest[P002 | merchant=MID-123 | customer=CUST-502 | Rs.499.00]
Result : PaymentResult[P002 | status=SUCCESS | ref=PAY-202401151030-1001 | Payment processed successfully]
Request : PaymentRequest[P003 | merchant= | customer=CUST-503 | Rs.2499.00]
Result : PaymentResult[P003 | status=FAILED | ref=null | Merchant ID required]
Request : PaymentRequest[P004 | merchant=MID-456 | customer=CUST-504 | Rs.-100.00]
Result : PaymentResult[P004 | status=FAILED | ref=null | Invalid amount]
Request : PaymentRequest[P005 | merchant=MID-456 | customer=CUST-505 | Rs.5999.00]
Result : PaymentResult[P005 | status=SUCCESS | ref=PAY-202401151030-1002 | Payment processed successfully]
Successful Transactions:
══════════════════════════════════════════════════════════════════════
Payment ID Status Transaction Ref
----------------------------------------------------------------------
P001 SUCCESS PAY-202401151030-1000
P002 SUCCESS PAY-202401151030-1001
P005 SUCCESS PAY-202401151030-1002
══════════════════════════════════════════════════════════════════════
Five packages collaborating through clean imports: com.phonepay (entry), com.phonepay.payment.model (data), com.phonepay.payment.service (logic), com.phonepay.payment.util (helpers). Each class is in exactly the right folder. Each import statement names its source package explicitly.
Best Practices
Create a dedicated source root and never mix source files with compiled output. In bare projects, src/ holds .java files and out/ or target/ holds .class files. Mixing them makes version control messy, makes cleaning a manual chore, and confuses IDE tools. javac -d out keeps this separation automatic.
Name every package segment in lowercase with no underscores. com.devstackflow.orderservice is correct. com.DevStackFlow.OrderService and com.devstackflow.order_service both violate convention. IDEs and build tools generate warnings for uppercase package names.
Keep one public class per file, named exactly after the file. The compiler enforces this for public classes. Non-public classes can share a file but should not if they are large — give each class its own file even if it is package-private. One class, one file makes navigation, version control diffs, and code reviews dramatically easier.
Add the package declaration before writing anything else — including imports. The most common beginner mistake is adding an import at the top and then the package declaration below it. The compiler rejects this instantly. package must be the very first non-comment line.
Common Mistakes
Mistake 1 — Package Declaration Does Not Match Folder
File saved at: src/com/devstackflow/model/ProductService.java
Package says: package com.devstackflow.service;
Compiler error:
error: class ProductService is public,
should be declared in a file named ProductService.java
(and the file is not in the correct package location)
Fix: either move the file to src/com/devstackflow/service/
or change the declaration to: package com.devstackflow.model;
Mistake 2 — Compiling From Inside the Package Folder
Wrong — run from inside src/com/devstackflow/service/: javac StudentService.java → Error: cannot find symbol for com.devstackflow.model.Student Correct — run from the source root (src/): javac -d ../out com/devstackflow/service/StudentService.java Or add the source root to the classpath: javac -sourcepath . -d ../out com/devstackflow/service/StudentService.java
Mistake 3 — Forgetting to Import Classes From Other Packages
1// Wrong — using Student without importing it
2package com.devstackflow.service;
3
4public class StudentService {
5 public void enroll(Student s) { } // compile error: cannot find symbol 'Student'
6}
7
8// Correct — add the import
9package com.devstackflow.service;
10import com.devstackflow.model.Student; // explicit import required
11
12public class StudentService {
13 public void enroll(Student s) { } // now compiles
14}Classes in the same package do not need an import. Classes in any other package — including sub-packages — always need one.
Mistake 4 — Uppercase Letters in Package Names
1// Wrong — violates Java naming convention
2package com.DevStackFlow.Model;
3
4// Correct — all lowercase
5package com.devstackflow.model;Uppercase letters in package names do not cause a compile error but violate the universal convention, break IDE autocompletion expectations, and cause warnings in static analysis tools like Checkstyle and SonarQube.
Interview Questions
Q1. How do you create a custom package in Java?
Three steps must align. First, create a folder whose path matches the intended package name — com/myapp/service/ for com.myapp.service. Second, add package com.myapp.service; as the first statement in every source file that belongs to that package. Third, compile from the source root — the directory that contains the com folder — using javac -d outputDir path/to/SourceFile.java. The -d flag tells the compiler where to place compiled .class files and automatically creates the matching folder structure.
Q2. What happens if the package declaration does not match the file's folder location?
The compiler reports an error. For a public class, the error is typically "class X is public, should be declared in a file named X.java" — or a more specific message about the package path not matching the source location. The Java compiler requires that a public class's source file location matches its package declaration exactly. Non-public classes generate a similar mismatch warning. Either move the file to the correct folder or update the package declaration to match the file's current location.
Q3. What is the difference between the source root and the package folder?
The source root is the top-level directory whose contents map to the root of the package namespace. In Maven projects, src/main/java is the source root. The com folder inside it is the first segment of the package name. The source root itself is not part of the package name. When compiling, the JVM and build tools look for classes relative to the source root. Running java com.myapp.Main from the directory containing compiled classes works because the JVM resolves com.myapp.Main relative to the classpath root.
Q4. Can two classes in the same package be in different files?
Yes — and this is the standard practice. Each public class must be in its own file named exactly after the class. All files that belong to the same package simply declare the same package statement. When compiled, all their .class files end up in the same output folder. The compiler treats them as members of the same package regardless of how many source files that package spans.
Q5. How does the Maven layout relate to Java packages?
In Maven, src/main/java is the source root. Packages map to subdirectories below this root. A class with package com.myapp.service must live at src/main/java/com/myapp/service/ClassName.java. Maven compiles all source files found below src/main/java and places the compiled .class files in target/classes, preserving the package folder structure. Running mvn compile handles all of this automatically without needing manual javac commands.
Q6. What is the classpath and why does it matter when running packaged classes?
The classpath tells the JVM where to look for compiled .class files. When you run java com.myapp.Main, the JVM looks for com/myapp/Main.class relative to each entry on the classpath. If the compiled classes are in an out/ directory, you specify it with java -cp out com.myapp.Main. For JAR files, you specify the JAR: java -cp myapp.jar com.myapp.Main. Without the correct classpath, the JVM throws ClassNotFoundException even if the class exists — it just cannot find it.
FAQs
Can a package contain both source files and compiled class files?
Yes, technically — the compiler does not prevent it — but you should always keep them separate. Source files belong in src/, compiled files in out/ or target/. Mixing them makes the project hard to clean, confuses version control (you do not want to commit .class files to Git), and breaks IDE analysis in some configurations.
Can you have an empty package — a package declaration with no classes?
The package exists as long as the folder exists, but you cannot declare package com.myapp.empty; in a file without putting at least one class in it. An empty folder on disk does not constitute a usable package in the Java classpath sense. The folder is just a folder until a .class file from a matching package lives in it.
Can the same class name exist in two different packages?
Yes — this is one of the primary purposes of packages. com.amazon.cart.Order and com.flipkart.order.Order can both exist on the classpath simultaneously. When both are needed in the same file, import one by simple name and reference the other by its FQCN (fully qualified class name).
Does every class in a package have to be in the same JAR file?
No. A single package can span multiple JAR files on the classpath. The JVM collects all .class files for a package from all classpath entries when resolving class references. This is called a split package and while it works, the Java 9 module system discourages it — modules require each package to belong to exactly one module.
What is the difference between package and module in Java 9+?
A package is a namespace that groups classes. A module (introduced in Java 9) is a higher-level grouping that contains packages and explicitly declares which packages it exports and which modules it depends on. A module is defined by a module-info.java file at the source root. Packages existed before modules and still exist inside modules. For most standard Java development — without module-info.java — the module system is not involved and packages work exactly as they always have.
Summary
Creating a custom package requires three things to align: the folder path on disk must match the package name, the package declaration must be the first statement in the file, and compilation must happen from the source root with -d directing compiled output to a separate directory. Get these right and Java's package system handles everything else — visibility, import resolution, and classpath mapping.
In real projects, Maven and Gradle automate compilation entirely. The developer only needs to place files in the correct src/main/java/com/company/... folder and declare the matching package. The build tool compiles, packages into a JAR, and manages the classpath. The folder structure is the package structure — the two are inseparable.
What to Read Next
Learn how to use classes from another package.