# NOTES — two commands, and the six errors they produce

## Run it first

From the directory holding the two sources:

```
.toolchain\jdk-21\bin\javac.exe -d out *.java
.toolchain\jdk-21\bin\java.exe -cp out Main
```

Real output:

```
2 free spots
short name and full name agree: true
T0: 2026-08-18T10:00:00Z
one runtime type: true
```

And `out/` afterwards:

```
out/Main.class
out/SpotBoard.class
```

Flat, because both classes are in the default package. Add `package dojo;` to both files and the
same command produces `out/dojo/Main.class` and `out/dojo/SpotBoard.class` instead. The output
tree mirrors the package names, because that is what a package physically is.

---

## Decoding `javac -d out *.java`

- **`javac`** reads `.java`, writes `.class`. There is no separate link step in Java, at any point.
- **`-d out`** is the output directory. `javac` creates it if missing and writes one `.class` per
  class into it, building package subdirectories as required. Without `-d`, class files land beside
  their sources: `ls` then shows `Main.class Main.java SpotBoard.class SpotBoard.java` in one heap.
- **`*.java`** is your shell expanding a glob before `javac` sees it. `javac` receives a filename
  list.

**Naming every file is optional, and that is the part worth knowing.** Run
`javac -d out Main.java` with `SpotBoard.java` sitting beside it, unnamed, and both compile:

```
out/Main.class
out/SpotBoard.class
```

`javac` needed the type `SpotBoard` and searched its **sourcepath**, which defaults to the
classpath, which defaults to the current directory. It found `SpotBoard.java` and compiled it too.
The invariant: you give `javac` a name and it goes looking. You never give it a location.

Compare C++, where you name the file for the compiler and the objects for the linker, and nothing
searches on your behalf. `*.java` is still the habit to keep, because it makes the build
independent of which file happens to reference which.

## Decoding `java -cp out Main`

- **`-cp out`** (spelled `-classpath` if you prefer) is the search path for compiled classes.
  Several entries are joined with `;` on Windows and `:` on macOS and Linux. That separator is the
  one platform-specific detail in the Java build.
- **`Main` is a class name, not a filename.** The launcher resolves it against the classpath.
  `java -cp out Main.class` and `java -cp out out/Main.class` both fail: the argument takes no
  extension and no path.
- The launcher then reflectively looks up `public static void main(String[])` on that class and
  calls it. Nothing about `main` is special to `javac`. See error 3.

Classes load lazily, by name, on first use. A program can compile and then die partway through
with `NoClassDefFoundError` because something absent from the runtime classpath was finally
touched. C++ gives you that experience only with dynamic libraries.

---

## `SpotBoard.java`, line by line

```java
import java.util.ArrayList;
import java.util.List;
```

**These lines read no files and generate no bytes.** Each says: for the rest of this file, that
short name means that long name. They are order-insensitive, harmless to duplicate, and optional.
Everything below could be written with full names, and the compiled output would be
indistinguishable.

Two imports rather than one, because `import java.util.X` imports exactly `X`. The wildcard
`import java.util.*;` imports every type in that package and no subpackage;
`java.util.concurrent.ConcurrentHashMap` still needs its own line. Wildcards also make the
ambiguity in error 4 possible, which is why most codebases list types explicitly.

```java
    private final List<String> freeSpotIds = new ArrayList<>();
```

**Field type is the interface, constructed type is the implementation.** That pairing is Java's
default habit, and it is the reason `List` and `ArrayList` are two separate imports.

`new ArrayList<>()` uses the diamond operator, inferring `<String>` from the declared type on the
left. It is the direct analogue of C++ CTAD, and omitting the type argument on the right is the
normal form. `new ArrayList<String>()` is not wrong, only dated.

**`final` on a collection field is not `const`.** It stops the reference being reassigned. Any
code holding the reference can still call `freeSpotIds.add(...)`. The invariant it maintains is
narrow but real: `freeSpotIds` is never null after construction and never points at a different
list. The bug it prevents is the field being swapped out underneath you. The bug it does not
prevent is what A7 is about.

```java
    List<String> viaImport() {
        return List.copyOf(freeSpotIds);
    }

    java.util.List<String> viaFullName() {
        return java.util.List.copyOf(freeSpotIds);
    }
```

**These two methods exist to be the proof.** Same declared type, written two ways. Same runtime
class, which `Main` checks with `==` on the `Class` objects and prints as `one runtime type: true`.
Delete `import java.util.List;` and only `viaImport()` breaks.

`List.copyOf(...)` returns an unmodifiable copy, so neither method leaks the field. That is a
design point rather than a J2 point, and it is here because demonstrating imports with a method
that hands out internals would teach the wrong reflex.

```java
    String describe() {
        return freeSpotIds.size() + " free spots";
    }
```

**`String` is never imported, and not because it is a keyword.** Every file gets an implicit
`import java.lang.*;`. `String`, `Integer`, `Object`, `Exception`, `Thread` and `Math` are all
ordinary classes in `java.lang`. Nothing there is built into the language the way `int` is; the
shortness of `String` is a package accident.

---

## `Main.java`, line by line

```java
        SpotBoard board = new SpotBoard();
```

**No import, and no import is possible.** `SpotBoard` is in the default package, same as `Main`.
Types in one package see each other with no ceremony. Error 5 shows what happens when they are in
different packages.

```java
        System.out.println("T0: " + java.time.Instant.parse("2026-08-18T10:00:00Z"));
```

**A type used with zero imports, spelled in full at the point of use.** Nobody writes production
code this way. It is here so the belief that an import is required has something concrete to break
against. The instant is the one `corpus/parking-lot/tests_base` pins its clock to.

```java
    static boolean sameTypeBothWays(SpotBoard board) {
        List<String> viaImport = board.viaImport();
        java.util.List<String> viaFullName = board.viaFullName();
        return viaImport.equals(viaFullName);
    }
```

`.equals`, not `==`, on purpose: two distinct copies with equal contents. If that distinction is
not yet automatic, J6 is the lesson, and it is the most consequential one in the bridge.

---

# The six errors, produced for real

Every message below came from running the code above with one thing changed.

## 1 · The import removed

Delete `import java.util.List;` from `SpotBoard.java`:

```
SpotBoard.java:11: error: cannot find symbol
    private final List<String> freeSpotIds = new ArrayList<>();
                  ^
  symbol:   class List
  location: class SpotBoard
```

**`cannot find symbol` with `symbol: class X` is the missing-import shape.** Contrast
`symbol: variable X`, which `javac` prints when the name sat where a variable would also fit. Both
appear here: line 19, `return List.copyOf(freeSpotIds);`, reports `symbol: variable List`, because
`List.copyOf(...)` is equally consistent with a variable named `List`.

Three errors follow from one deleted line, one per use site. There is no single declaration to
fail at. And `viaFullName()` is untouched in the output. One method broke, the other did not, from
the same missing import.

## 2 · No `-cp`, so the class is nowhere

Run `java Main` from the directory holding the sources and `out/`:

```
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main
```

The default classpath is the current directory, which holds `Main.java` but not `Main.class`. That
went to `out/`. **The launcher does not compile, and never looks at `.java` files.**

Read the two lines as one thought. `Could not find or load main class` is the launcher's framing;
`ClassNotFoundException` underneath is the cause. When you see this, check whether `-cp` points at
the directory holding the `.class` file.

## 3 · A class with no `main`

```
java -cp out SpotBoard
```

```
Error: Main method not found in class SpotBoard, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
```

**`SpotBoard.class` was found and loaded.** This failure is strictly later than error 2 and means
something different. The classpath was right, the class name was right, and the class has no entry
point. `main` is invisible to `javac` and interesting only to the launcher. So every near-miss
signature compiles cleanly and fails right here: `void main()`, `static int main(String[])`,
`public void main(String[])`. Ignore the JavaFX line; it prints unconditionally.

## 4 · An ambiguous import

Add `import java.awt.List;` beside the existing `import java.util.List;`:

```
SpotBoard.java:13: error: reference to List is ambiguous
    private final List<String> freeSpotIds = new ArrayList<>();
                  ^
  both interface java.util.List in java.util and class java.awt.List in java.awt match
```

**This error is possible only because imports are aliases.** With `#include` you would get two
types with distinct qualified names and no conflict until you wrote an unqualified `List`. Here
two imports both claim the short name, so `javac` refuses to pick.

The fix is not to remove an import. It is to write the full name at the ambiguous use site, which
restates the model: short names are a convenience layered over full names that always work. The
everyday version of this error is `java.util.Date` against `java.sql.Date`.

## 5 · A packaged class reaching for the default package

Put `package dojo;` at the top of `Main.java` only, leaving `SpotBoard` in the default package:

```
Main.java:12: error: cannot find symbol
        SpotBoard board = new SpotBoard();
        ^
  symbol:   class SpotBoard
  location: class Main
```

**No import fixes this.** A class in the default package has no package name, so there is nothing
to write after `import`. `dojo.Main` cannot see it under any spelling.

That is why the project uses the default package for everything rather than for some things: the
two do not mix. Flat sources, one `javac -d out *.java`, one `java -cp out Main`, no imports
between your own classes. The hidden test suite lands in the same package and sees your types with
no ceremony.

## 6 · `package` without `-d`

Add `package dojo;` to both files and compile with no `-d`:

```
Main.class  Main.java  SpotBoard.class  SpotBoard.java
```

```
java -cp . dojo.Main
Error: Could not find or load main class dojo.Main
Caused by: java.lang.ClassNotFoundException: dojo.Main
```

The class files are flat, but the launcher looks for `dojo.Main` at `./dojo/Main.class`, because a
package is a directory path. With `-d out` the same sources give `out/dojo/Main.class` and
`java -cp out dojo.Main` runs. Building that tree by hand is the classic first hour with packages,
and `-d` is how you skip it.
