简体   繁体   中英

Java Classes: Anonymous vs Nested vs Private

Can someone explain the difference between anonymous classes, nested classes and private classes in Java? I'd like to know the runtime costs associated with each and the compiler approach to each, so I can get a grip on which is best to use for eg performance (potential for compiler optimisations), memory usage, and general acceptability with other Java coders.

By anonymous classes I mean those declared inline in a function in that weird Java way. This is often seen in examples of Swing code where you write a button handler inline with the declaration of it. I don't really like anonymous classes because you get those funny MyClass$1.class files and more often than not you'll have to refactor later when it turns out you want to make the anonymous class a singleton or need a handle to it or something. I also just don't like the way you're attaching a handler in the form of something you just made up whilst in the middle of another function call. It just makes me feel weird. :-)

Private classes are the ones you write at the bottom of your file completely outside the declaration of your public class. I prefer private classes just because they make sense in other languages where there isn't a strong 1:1 relationship between a source file and a class. I don't get that weird feeling and I know (or I think I know) how a Java compiler will handle the declaration of that class.

Nested classes are ones written inside the squigglies of your public class. I really don't know what a nested class means compared to the other two. :-)

Can someone explain the difference between anonymous classes, nested classes and private classes in Java?

  • Anonymous classes are for instance the Runnable in

     new Thread(new Runnable() { public void run() { ... } }.start(); 
  • Nested classes look like

     class SomeClass { ... class NestedClass { .... } } 
  • Private classes (which you refer to as "the ones you write at the bottom of your file completely outside the declaration of your public class") are actually package scoped classes. You can't have the private modifier in front of a class, unless it is nested!

I'd like to know the runtime costs associated with each and the compiler approach to each, so I can get a grip on which is best to use for eg performance (potential for compiler optimisations), memory usage, and general acceptability with other Java coders.

I doubt that there is any performance difference between these approaches. Why? Because each approach ends up as being compiled into a separate more or less "regular" class. ("More or less" due to the fact that an accesss-method is generated in some cases, but it's side effect free and most likely inlined by the JIT anyway.)

This code:

public class TestOuter {

    int fieldOuter;
    public void methodOuter() {
    }

    class TestInner {
        int fieldInner;
        public void methodInner() {
        }
    }
}


class TestPackage {

    int fieldPackage;
    public void methodPackage() {
    }

}

Gets compiled into:

$ javap -c TestOuter$TestInner
Compiled from "TestOuter.java"
public class TestOuter extends java.lang.Object{
int fieldOuter;

public TestOuter();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void methodOuter();
  Code:
   0:   return

}

$ javap -c TestOuter
Compiled from "TestOuter.java"
public class TestOuter extends java.lang.Object{
int fieldOuter;

public TestOuter();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void methodOuter();
  Code:
   0:   return

}

$ javap -c TestPackage
Compiled from "TestOuter.java"
class TestPackage extends java.lang.Object{
int fieldPackage;

TestPackage();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public void methodPackage();
  Code:
   0:   return

}

As for runtime cost, private and public classes are the same. In theory there is a difference, because the JVM could inline methods from a private class more easily, but that's theory.

Nested classes: there are two kind, static and non-static. This actually is a relatively big difference: the static class is like a private class, and the non-static class has a pointer (reference, whatever you want to call it) to the parent object. Which means it needs more memory, so if possible use static nested classes. Otherwise, nested classes are as fast as private or public classes. From a non-static nested class you can access the parent object (that's why it has a reference to the parent), but be careful when accessing private fields, because this is done using special hidden anonymous functions (Eclipse will give you a warning).

If you really want to understand all the differences, you should use javap to decompile the class.

First to correct some terminology.

  • A private class is a class that is declared with the access modifier private . This modifier can only be used on a nested class, so private classes are a subset of nested classes.

  • Classes that "you write at the bottom of your file completely outside the declaration of your public class" are actually package private . And this is because of their access / visibility ... not the fact that they are in the same file some other class.

(Not withstanding that you like doing this, it is generally accepted that it is a BAD IDEA to put more than one top-level class in one source file. It is liable to break tools and IDEs, for a start. Source: http://geosoft.no/development/javastyle.html .)

So what is the difference between them?

  • A package private class is the same as an ordinary public or protected class, except that it is ONLY visible to other classes in the same package.

  • A nested classes is a static class that is declared within another class. It behaves for all intents and purposes the same way as a non-nested class. In particular, instances can be created independent of any enclosing class instances.

  • A local inner class is a non- static class that is declared within another class. An instance must be created in the context of an instance of the enclosing class, and can access all members of that instance.

  • An anonymous inner class is functionally similar to a local inner class, except that:

    • it is declared within an method and can make use of variables declared in the methods (provided that they are final ), and
    • it and doesn't have a name and cannot be independently instantiated.

    The anonymous inner class syntax combines declaration and instantiation, and is designed to make it easy to write light-weight callbacks.

What about performance?

  • The performance of a nested class (private or otherwise) is identical to a regular class.
  • The two forms of inner class have a tiny performance cost in that they use a hidden attribute that holds a reference to the enclosing instance.

What about acceptability?

  • Nested classes (including private ones) and the two forms of inner classes are all acceptable, and have their uses. (Obviously some are more appropriate than others, depending on the use-case. But you could say that about every Java construct.)

  • The form that you mislabeled as "private" (where you put multiple top level classes into one source file) is generally thought to be a bad idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM