views:

183

answers:

4

It seems to me that non-public top-level classes and static nested classes essentially perform the same tasks when creating a helper class.


A.java


public class A 
{
    public static main (String[] args)
    {
        AHelper helper = new AHelper();     
    }
}
class AHelper {}


A.java


public class A
{
    public static main (String[] args)
    {
        A.AHelper helper = new A.AHelper();     
    }

   static class AHelper {}
}


Aside from how they are referenced, there seems to me very little difference between the two ways of creating a helper class. It probably comes down mostly to preference; does anyone see anything I'm missing? I suppose some people would argue that it's better to have one class per source file, but from my perspective it seems cleaner and more organized to have a non-public top-level class in the same source file.

+3  A: 

In neither example do you have one class per source file. But generally, you use a static nested class to signify that it is only intended to be used within its enclosing class (forcing it to be referenced as A.AHelper). That is not so clear if you move that class to the top level.

From the Sun tutorial:

Logical grouping of classes—If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.

danben
+1  A: 

One thing that comes to mind is the scope of the helper class. A nested class has access to private members of the parent class. If the helper is in its own file, you don't enjoy such access, although it is easy to handle with the default package visible scope.

Another consideration is code reuse - you might want your helper to help several classes in your package.

Yoni
No, this is not true of a static nested class, which is what he is asking about.
danben
@danben : what exactly is not true?
Carlos Heuberger
@Carlos Heuberger: it isn't true that a static nested class has access to private members of its enclosing class.
danben
Danben. I think I got it right. Just tried it in Eclipse with a minimal sample and it works.public class Outer { private static int foo = 5; static class Inner { private static void print() { System.out.println(foo); } }}
Yoni
@danben: static nested class have access to private static members of the class they are inside at compile time. They do not have DIRECT access at runtime, but the compiler will create a synthetic access method for that.
Carlos Heuberger
@Carlos Heuberger: ah, I didn't realize that. Is that part of the specification or is it implementation-specific?
danben
@danben: by specification. JLS 6.6.1: "...if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. "
Carlos Heuberger
@Carlos Heuberger - while my compiler verifies this behavior, that part of the spec you quoted sounds like a contradiction. We're talking about an access that doesn't occur within the body of the top-level class, unless the body of the nested class counts.
danben
@danben: I think the last is true, at least it's the way the compiler (Eclipse and SUN) works. I would say the body of the nested class counts as do the body of a method or the body of an initializer block. I would NOT say the JLS is very clear about it.
Carlos Heuberger
From the beginning of chapter 8 of JLS: "The body of a class declares members (fields and methods and nested classes and interfaces), instance and static initializers, and constructors". Seriously, why is it such an issue? If all the compilers act this way (IBM's compiler too), do you really think it contradicts the JLS?
Yoni
Another quote: "Member class declarations (§8.5) describe nested classes that are members of the surrounding class. Member classes may be static, in which case they have no access to the instance variables of the surrounding class; or they may be inner classes (§8.1.3)." It seems to be implied ...
Yoni
+1  A: 

Nesting a class (statically in Java) sends a clear message of intent: the nested class AHelper is only relevant and usable to support A class. It has no meaning on its own, and this is immediately obvious.

Pontus Gagge
A: 

One difference is that a static nested class can be declared public. You cannot do this for any other class in the same file as the primary class as a public main level class must be the same name as the file name.

So you could declare many public classes in one file, but only one of them being the main level. The other static nested classes ought to be related though to the main class or it really does not make sense to do that.

Kevin Brock