Packaging and Deploying Java Code
Packages and compilation
A package statement must be the first non-comment line; imports are not transitive; a public class must live in a file with the same name. javac -d out src/**/*.java writes class files into a directory tree mirroring the package, and java -cp out com.example.Main runs them. The classpath separator is ; on Windows and : on Unix - prefer -cp to the CLASSPATH variable. Classes in the unnamed (default) package cannot be imported by packaged classes.
JARs
jar --create --file app.jar --main-class com.example.Main -C out . embeds Main-Class in the manifest, so java -jar app.jar works - provided that class exists at runtime. --list --file inspects contents, --extract unpacks, --describe-module prints the descriptor.
Modules
module-info.java names the module and uses directives: requires (dependency; requires transitive re-exports it), exports (grants compile-time visibility of a package), opens (allows deep reflection), and uses/provides ... with for services loaded by ServiceLoader. The module path replaces the classpath: java --module-path mods -m com.example/com.example.Main. A named module does not read the unnamed module (the classpath) unless --add-reads is used; every module reads java.base implicitly.
Deployment tools
jdeps analyses dependencies, jlink builds a custom runtime image from a module set, and jpackage produces native installers. Java 21 also runs single-file sources directly with java Hello.java, compiling and executing in memory.
Worked rule: if java -jar reports "no main manifest attribute", the manifest lacks Main-Class - rebuild with --main-class, and remember a manifest class name uses dots, not slashes.