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.
I believe you simply call PrivateImpl
what it is: a non-public top-level class
. You can also declare non-public top-level interfaces
as well.
e.g., elsewhere on SO: Non-public top-level class vs static nested class
As for changes in behavior between versions, there was this discussion about something that "worked perfectly" in 1.2.2. but stopped working in 1.4 in sun's forum: Java Compiler - unable to declare a non public top level classes in a file.
My suggested name for this technique (including multiple top-level classes in a single source file) would be "mess". Seriously, I don't think it's a good idea - I'd use a nested type in this situation instead. Then it's still easy to predict which source file it's in. I don't believe there's an official term for this approach though.
As for whether this actually changes between implementations - I highly doubt it, but if you avoid doing it in the first place, you'll never need to care :)