Java: Multiple class declarations in one file

Javac doesn’t actively prohibit this, but it does have a limitation that pretty much means that you’d never want to refer to a top-level class from another file unless it has the same name as the file it’s in.

Suppose you have two files, Foo.java and Bar.java.

Foo.java contains:

  • public class Foo

Bar.java contains:

  • public class Bar
  • class Baz

Let’s also say that all of the classes are in the same package (and the files are in the same directory).

What happens if Foo refers to Baz but not Bar and we try to compile Foo.java? The compilation fails with an error like this:

Foo.java:2: cannot find symbol
symbol  : class Baz
location: class Foo
  private Baz baz;
          ^
1 error

This makes sense if you think about it. If Foo refers to Baz, but there is no Baz.java (or Baz.class), how can javac know what source file to look in?

If you instead tell javac to compile Foo.java and Bar.java at the same time, or if you had previously compiled Bar.java (leaving the Baz.class where javac can find it), or even if Foo happens to refer to Bar in addition to Baz, then this error goes away. This makes your build process feel very unreliable and flaky, however.

Because the actual limitation, which is more like “don’t refer to a top-level class from another file unless it either has the same name as the file it’s in or you’re also referring to another class that’s named the same thing as that file that’s also in that file” is kind of hard to follow, people usually go with the much more straightforward (though stricter) convention of just putting one top-level class in each file. This is also better if you ever change your mind about whether a class should be public or not.

Newer versions of javac can also produce a warning in this situation with -Xlint:all:

auxiliary class Baz in ./Bar.java should not be accessed from outside its own source file

Sometimes there really is a good reason why everybody does something in a particular way.

Leave a Comment