Java Packages, Imports, and the API
A package organizes names; an import shortens the names you can write; an API contract tells you how a call behaves. Learn all three, then move a working helper from one file into a small packaged project.
Before you start: review access boundaries, arrays and copying, and static method calls. All Run code examples are complete single-file Java 21 programs. The separately labeled local project requires a JDK and two files; it is not executable in the current website runner.
What you will be able to do
- Distinguish a package declaration from an import and a dependency installation.
- Use explicit imports and fully qualified names without name conflicts.
- Explain java.lang, wildcard imports, and static imports.
- Read API signatures, mutation rules, return values, and preconditions.
- Organize two public classes into package-aligned source files.
- Compile to a classpath root and launch a fully qualified main class.
A package gives a type an organized, unambiguous name
As a program grows, a short name such as Main, Date, or Item can appear in more than one place. A package groups related types and contributes to their qualified names. java.util.Arrays identifies the Arrays type in java.util; the package name is part of the identity, not a descriptive comment.
For your own code, choose lowercase package segments such as org.sovrancode.learning.app and org.sovrancode.learning.tools. Reverse-domain naming is a convention for reducing collisions, not a requirement to contact a website. The namespace in this exercise performs no network request and does not install anything.
Keep two environments separate while learning: browser examples run as one Main.java in the unnamed package, while the local project below declares real packages across two files. The website runner does not offer a multi-file editor or a configurable packaged entry point; a package declaration cannot simply be pasted into its current Main runner.
An import makes a type's short name usable in this source file
import java.util.Arrays lets this source file refer to Arrays instead of repeating java.util.Arrays. It does not create an Arrays object or execute its methods. The call Arrays.toString(scores) is the separate operation that produces a readable representation of the array.
Imports belong after an optional package declaration and before top-level type declarations. They apply to the compilation unit containing them, not automatically to every file in the project. Another file using Arrays needs its own import or the fully qualified name.
Importing a name also does not download a library. Java's standard Arrays class is available in the JDK used here. An external library would first need to be available to the compiler and runtime through the project configuration; writing an import alone cannot provide a missing dependency.
Main.java · Import one type and keep the owner visible
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
[40, 10, 20]
Use a fully qualified name when a simple name would be unclear
java.util.Date and java.sql.Date are different classes that happen to share the short name Date. The example spells out both qualified names, so the compiler and reader can distinguish them. It uses a fixed epoch value and a fixed date string to keep output deterministic; the SQL date is a value object here, not a database connection.
Two explicit imports of different types with the same simple name cannot both define Date for one source file. Java does not support an import-as alias syntax. A practical repair is to import one type and fully qualify the other, or fully qualify both as the example does.
A fully qualified name still has to refer to an available, accessible type. It is not a way around private members, package access, or missing dependencies. Name resolution, access control, and having the required compiled code available are related checks, but they are not the same check.
Main.java · Two different Date classes need distinct names
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Epoch millis: 0
SQL date: 2026-10-21
Some type names are already available without imports
Public types in java.lang, such as String, StringBuilder, System, and Math, are implicitly imported. That is why earlier lessons could print and use strings without an explicit import. This does not mean every java package is imported automatically.
Accessible types in the same package can also be referenced without an import. ShelfLabel later in this lesson shares the unnamed package with Main and is declared in the same file. In a named project, same-package types can live in separate files; the compiler still needs their source or compiled definitions to be available.
Package names are not inherited access relationships. org.sovrancode.learning.app and org.sovrancode.learning.app.internal are distinct packages; a child-looking name does not grant access to package-private members in its parent-looking package. Use deliberate public boundaries instead of assuming folder nesting changes the rule.
Main.java · java.lang types need no explicit import
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Java API
7
Read wildcard and static imports as two different shortcuts
import java.util.* makes eligible accessible types directly in that package available by simple name when needed. It does not import subpackages, and it does not mean the program eagerly loads every class. For example, it does not make java.util.function.Predicate available as Predicate.
An explicit type import usually tells a beginner more clearly where a name comes from. Multiple wildcard imports can make a used simple name ambiguous when several packages contain it. A wildcard also does not import static methods as bare method names; Arrays.sort still keeps its type qualifier.
import static java.lang.Math.max is a different declaration: it permits calling the static member as max(...). The example below keeps Arrays qualified; a later runnable example compares the two Math spellings. Use static imports sparingly when removing the owner makes a call harder to understand.
Main.java · A wildcard makes eligible type names available
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
[1, 3]
Read the API as a contract, not a list of names to memorize
For Arrays.sort(int[]), the parameter is an int array and the return type is void. The method sorts the supplied array rather than returning a new one. For Arrays.copyOf(int[], int), the return type is int[] and the method creates a new array of the requested length. Those details determine whether your helper preserves its input.
Open the Java 21 Arrays API documentation, select the exact overload, and read the description, parameters, return value, and exceptions. Similar method names may have different contracts or element types. Do not infer copying, null handling, or mutation solely from a familiar-looking method name.
The example copies at the original length, then sorts the copy. It therefore keeps original unchanged while producing a sorted result. These arrays contain primitive ints, so the copy has independent element storage; this is not a general claim that copying an array of mutable objects clones every object inside it.
Main.java · Copy first because sort mutates its argument
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Original: [40, 10, 20]
Sorted: [10, 20, 40]
Use a four-question API reading checklist
- Which overload accepts the types I actually have?
- Does the method change its input, create a result, or both?
- What does it return, including missing or empty cases?
- Which preconditions and documented errors must the caller handle?
Try answering these for copyOf, sort, and binarySearch before running the lab.
A search result is useful only when its preconditions hold
Arrays.binarySearch(int[], int) requires the array to be sorted in the appropriate ascending order. Searching an unsorted array has undefined results according to its API contract; it is not a supported shortcut that you can validate with one lucky output. Our helper sorts a copy before the lab searches it.
For the sorted array [10, 20, 40], searching for 20 returns index 1. Searching for 30 returns -3, encoding an insertion point of 2 using -(insertion point) - 1. A negative result is not an index that can be used directly to access the array.
When duplicate values exist, the API does not promise which matching index it returns. Test that a nonnegative index contains the target instead of demanding the first duplicate. Empty arrays and missing values are useful contract tests because they expose code that assumes every search succeeds.
Main.java · Read the return contract before indexing
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Found index: 1
Missing result: -3
Insertion point: 2
Decode the missing result by hand
Thirty belongs after twenty and before forty, at index two. The API encodes that insertion point as -(2) - 1, giving -3. Checking for a negative result before decoding avoids treating a missing value as an ordinary array index.
Package declarations, source folders, and classpath roots work together
In the local project, package org.sovrancode.learning.tools is the first non-comment declaration in ScoreTools.java, followed by its imports and its public class. The matching source path under src is org/sovrancode/learning/tools/ScoreTools.java. Main.java has its own app package and imports the public tools class.
With this ordinary file-based javac setup, each public top-level class belongs in the file with its matching name. The public class ScoreTools, its public sortedCopy method, and a valid import are all needed for the app package to call the helper. An import cannot make a package-private tools class publicly accessible.
javac -d out places compiled files below out in their package directories. java -cp out org.sovrancode.learning.app.Main then launches the qualified class name, not a source path or a .class filename. out is the classpath root above org, not the app subfolder. This exercise uses the classpath, not a module-info.java module setup.
Main.java · A same-file helper needs no import
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Learning shelf
A shorter member name does not change its behavior
Both max(3, 7) and Math.max(3, 7) in this example resolve to the same standard static operation. The static import changes which spelling is permitted in this file, not the implementation or the meaning of the arguments.
Do not confuse a static import with creating a utility object or inheriting from Math. No Math instance is constructed, and Main does not gain a new implementation of max. The import is a source-level naming convenience.
For a teaching helper such as ScoreTools.sortedCopy, retaining the class qualifier often communicates responsibility more clearly than a bare sortedCopy call. Choose one consistent style in a small project and use qualified names when they help resolve real ambiguity.
Main.java · A static import shortens a member name
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
7
7
Diagnose the stage that failed instead of adding random imports
A cannot-find-symbol error may mean a missing import, a misspelled type or member, or a type unavailable to the compilation. A package-does-not-exist message can mean the package or dependency is absent. Check the declaration and the build inputs rather than assuming every error needs a wildcard.
An access error is different: a type or member may exist but not be public across a package boundary. A runtime class-not-found or could-not-find-main-class message points toward the compiled output, qualified entry name, or runtime classpath. Imports do not configure the java launcher.
Follow a repeatable order: check spelling and the exact API version, inspect the package and access modifiers, compile the intended sources, inspect the output layout, then launch from the classpath root. When repairing a name conflict, decide which type you meant rather than deleting qualifiers until the source happens to compile.
Repair exercise: which Date did you mean?
The wildcard imports expose two different Date types, so the compiler cannot resolve the bare Date name. This starter intentionally fails compilation. Keep the epoch-based java.util.Date, make its choice explicit, and leave the output deterministic.
Main.java · Intentionally ambiguous Date
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Expected diagnostic: the reference to Date is ambiguous. No program output is produced because compilation fails.
Reveal the explained repair
The starter's problem is ambiguity, not a missing dependency. An explicit java.util.Date import identifies the intended type. If the program also needed java.sql.Date, use that fully qualified spelling for the second type instead of inventing an import alias or importing both with the same simple name.
Main.java · Make the intended Date explicit
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Epoch millis: 0
Independent lab: use the API without changing caller data
Build a single-file sorted-copy helper in the website runner, using explicit API contracts. Then move that same helper into the two-file local package project below. The browser lab and local project should produce identical output; the website runner itself remains single-file.
- Import java.util.Arrays explicitly. Use public Main with no package declaration for the website runner. Keep all examples on the Java 21 baseline.
- Implement static int[] sortedCopy(int[] values). Reject null with IllegalArgumentException and message Values must not be null. Create a same-length copy, sort only that copy, and return it.
- For original {40, 10, 20}, call the helper and print the original and sorted arrays. Print reference inequality to confirm a new array was returned, even when input is empty or already sorted.
- Search the sorted result for 20 and 30 with the int-array binarySearch overload. Print both results, then decode the negative missing result as -result - 1. Do not use a negative result as an array index.
- Keep the helper free of printing and input mutation. Test empty, already sorted, reverse-sorted, duplicate, negative, and extreme-int arrays, and null rejection.
- After the browser lab works, follow the separately labeled local project: public ScoreTools in the tools package, public static helper, and Main in the app package importing it. Compile both files to out and launch the qualified main class.
The single-file version and the packaged project should produce these same six lines:
Original: [40, 10, 20]
Sorted: [10, 20, 40]
Independent array: true
Found index: 1
Missing result: -3
Insertion point: 2
Main.java · Build a contract-aware array helper
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Hint: copy, sort, return, then search
Check null before calling the array API. Create a new int array with copyOf, sort that result rather than the original, and return it. Main prints and searches; the helper does neither. Test duplicates by checking the returned index's value, not by requiring a first-occurrence promise the API never made.
Reveal the complete single-file solution
Main.java · Complete sorted-copy practice
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Arrays.copyOf gives the helper new primitive-array storage, and Arrays.sort changes only that copy. binarySearch then receives the sorted input required by its contract. Twenty is at index one, while thirty belongs at insertion point two, encoded as negative three. Moving the helper to ScoreTools changes its qualified owner and access boundary, not these results.
Test changes and boundaries
- Run the original sample and verify both arrays, independent storage, and both search outcomes. Repeated calls should leave the original order unchanged.
- Try empty, already sorted, reversed, duplicate, negative, Integer.MIN_VALUE, and Integer.MAX_VALUE arrays. The returned array must be sorted, preserve the same values, and have a different identity.
- Search for a present duplicate and accept any returned index containing the target. For an absent value, decode the insertion point and verify it lies between zero and the array length.
- Reject null before calling Arrays methods. Modify a returned result afterward and check the input remains unchanged. Check the Java 21 API rather than assuming sort returns a new array.
- Compile and run the local two-file project from its root. Test a missing public method, a conflicting Date name, and an incorrect classpath root as different categories of error, then restore the working version.
Local JDK project: split the helper into two packages
Run locally, not in the website editor. Use a fresh package-practice folder. The source below is organized into two files; terminal commands belong in a terminal opened at that project's root.
package-practice/
src/
org/sovrancode/learning/
app/Main.java
tools/ScoreTools.java
out/ (created by javac)- Install a JDK supporting Java 21 and verify java -version and javac -version. Create a new package-practice folder and run all commands from that project root, not from the app folder.
- Create the two source folders shown in the tree with your editor or file manager. Save ScoreTools.java and Main.java with their exact package declarations and matching public class names.
- Run the javac command below. -d out creates the package-aligned class output. If compilation reports an error, fix it and compile again before launching; do not interpret stale output as a successful rebuild.
- Run the java command from the same project root. Match all six output lines with the browser lab. The classpath root is out, while the main class is its fully qualified dotted name.
- Change only the input array and repeat both commands. Then deliberately remove public from sortedCopy and observe the cross-package compile error; restore it and recompile. Do not paste these packaged files or shell commands into the website's single-file runner.
src/org/sovrancode/learning/tools/ScoreTools.java
The class and helper method are public so the app package can use them. The private constructor prevents accidental utility-class instances; all useful work here is static.
package org.sovrancode.learning.tools;
import java.util.Arrays;
public final class ScoreTools {
private ScoreTools() {}
public static int[] sortedCopy(int[] values) {
if (values == null) {
throw new IllegalArgumentException("Values must not be null.");
}
int[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy);
return copy;
}
}src/org/sovrancode/learning/app/Main.java
This file has its own package and imports. Only the helper's owner changes from the single-file lab; its copying and sorting contract stays the same.
package org.sovrancode.learning.app;
import java.util.Arrays;
import org.sovrancode.learning.tools.ScoreTools;
public class Main {
public static void main(String[] args) {
int[] original = {40, 10, 20};
int[] sorted = ScoreTools.sortedCopy(original);
System.out.println("Original: " + Arrays.toString(original));
System.out.println("Sorted: " + Arrays.toString(sorted));
System.out.println("Independent array: " + (original != sorted));
int found = Arrays.binarySearch(sorted, 20);
int missing = Arrays.binarySearch(sorted, 30);
System.out.println("Found index: " + found);
System.out.println("Missing result: " + missing);
if (missing < 0) {
System.out.println("Insertion point: " + (-missing - 1));
}
}
}Compile and launch from the project root
javac --release 21 -d out src/org/sovrancode/learning/tools/ScoreTools.java src/org/sovrancode/learning/app/Main.java
java -cp out org.sovrancode.learning.app.MainSuccessful verification means all six lines match the lab output, including the unchanged original array and independent array reference. If compilation fails, fix it and rebuild before launching. Do not rely on a previously compiled class file as proof that the changed source works.
Common mistakes and how to diagnose them
Treating an import as installation or execution
An import supplies a source-level name. It does not download a dependency, construct an object, or invoke a method. Verify that the required code is available to both compilation and runtime.
Assuming a wildcard includes subpackages
java.util.* does not import java.util.function types. Package nesting in names also does not grant shared package-private access. Import the exact type you intend to use.
Importing two types with the same simple name
Use an explicit choice and a fully qualified name for the other type. Java has no import-as alias. A used Date name from conflicting wildcard imports is ambiguous, not evidence that the JDK is missing Date.
Pasting package files into the single-file runner
The current website compiles Main.java and launches unqualified Main. Use its complete single-file examples for runnable practice; use the labeled local JDK project for real package declarations across files.
Launching a path instead of a qualified class name
Use java -cp out org.sovrancode.learning.app.Main from the project root. Do not append .class or set the classpath to the app directory below the package root.
Ignoring the exact API overload's contract
Arrays.sort(int[]) mutates and returns void; copyOf creates an array; binarySearch requires sorted input and can return a negative insertion-point encoding. Read the signature, preconditions, mutation behavior, and result rules before composing calls.
Frequently asked questions
Is a package the same as a folder?
A package is a Java namespace declared in source. Folder paths are the conventional file-based layout used to organize those sources and compiled classes. Our project aligns both so javac and the launcher can resolve the intended types predictably.
Why does String work without an import?
Public java.lang types are implicitly imported. That includes String, System, and Math; it does not automatically import every standard package or an external library.
Does import java.util.* slow down the program by loading everything?
The wildcard is a naming declaration, not an instruction to eagerly load all classes. Explicit imports are still useful because they communicate intent and reduce confusing name resolution.
Can I rename a class with import ... as ...?
No. Java does not provide that alias syntax. Import one simple name and fully qualify the conflicting type, or fully qualify both.
Why is the local project not another Run code block?
The website runner currently supports one Main.java and an unqualified Main entry point. Real package organization needs the supplied two files and qualified launch command, so it is labeled as local JDK work rather than pretending the runner can execute it.
Names, availability, access, and behavior are separate questions
Packages organize types. Imports shorten names in a source file. Access modifiers control permitted use. The classpath makes compiled code available. API documentation defines how the selected operation behaves. A correct program needs these pieces to agree.
Before moving on, explain why importing does not install a library, why sorting a copy protects the original, and why the launch class uses dots while the source paths use folders. Next: the inventory-model class challenge, bringing constructors, encapsulation, and organized responsibilities together.
Can you resolve a name and verify its contract?
Answer all six questions and read the explanations. Answers are temporary on this page and do not save course progress.
References and related learning
The scenarios, examples, explanations, and exercises are original SovranCode material. Use these Java 21 references to check declarations, exact method overloads, and build commands.
- Java 21 specification: package and import declarations
- Java 21 Arrays API: exact overloads and contracts
- Java 21 javac command: output directories and source layout
Review access boundaries · Review array storage · Review static calls · Java course roadmap.
Last updated: