4

I've read elsewhere that a static anonymous class doesn't make sense - that all anonymous classes should be tied to an instance of the enclosing type. But the compiler let's you do it. Here's an example:

class Test {

    /*
     * What's the difference at between
     * Test.likeThis and Test.likeThat?        
     */

    // This is obviously okay:
    private static final class LikeThat {
        @Override
        public String toString() { return "hello!"; }       
    }
    public static Object likeThat = new LikeThat();

    // What about this - is it really any different? 
    public static Object likeThis = new Object() {
        @Override
        public String toString() { return "hello!"; }
    };
}

What's going on here?

9 Answers9

8

From the Java Language Specification, section 8.1.3:

An instance of an inner class I whose declaration occurs in a static context has no lexically enclosing instances. However, if I is immediately declared within a static method or static initializer then I does have an enclosing block, which is the innermost block statement lexically enclosing the declaration of I.

Your anonymous class (the one likeThis is an instance of) occurs in a static context, so it is not tied to an enclosing instance. However, it seems that it can refer to final variables of its enclosing block (see the rest of section 8.1.3, they give an example).

Btw, your wording is a bit deceptive, you're actually referring to a static instance of an anonymous class (it's the instance that's static, not the class).

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Olivier
  • 1,232
  • 6
  • 10
7

I see nothing wrong with static anonymous classes

Maurice Perry
  • 32,610
  • 9
  • 70
  • 97
5

Like anything in any language you should just consider why you're doing it. If you've got alot of these instances then I'd question the design decisions, but it doesn't necessarily means it's a pattern that should never be followed.

And of course, always consider the testability of the class and whether you can provide a test double if the need arises

tddmonkey
  • 20,798
  • 10
  • 58
  • 67
  • 1
    +1 - agreed, if you're seeing a lot of statics your codebase is going to be brittle and you're not really leveraging the power of OO that comes with the concept of an instance. – Nick Holt Aug 07 '09 at 09:13
1

I don't think they have no sense. If you don't need reference to enclosing object then it's better to leave it static. Later it can evolve in separate class with ease.

Wide-spread enum idiom (pre Java 5) used similar approach with anonymous static inheritors of enum class. Probably, now it is better stick to Java 5 enum for this case.

If you are able to find adequate real-world application for anonymous static classes - why not to use them?

Rorick
  • 8,857
  • 3
  • 32
  • 37
1

I do this all the time. It's especially handy for special-case implementations of utility interfaces, e.g.:

/** A holder for {@link Thing}s. */
public interface ThingsHolder {

    /** A {@link ThingsHolder} with nothing in it. */
    public static final ThingsHolder EMPTY_HOLDER = new ThingsHolder() {
        @Override
        public Iterable<Thing> getThings() {
            return Collections.emptySet();
        }
    };

    /** Provides some things. */
    Iterable<Thing> getThings();
}

You could create a private static inner class called EmptyHolder, and maybe in some cases that would make the code more readable, but there's no reason you have to do it.

David Moles
  • 48,006
  • 27
  • 136
  • 235
1

According to this answer which references the JLS, anonymous classes are never static, but when created in a "static context" they have no "enclosing instance".

That said,

  • They give the same error at compile time if you try to reference Test.this (non-static variable this cannot be referenced from a static context)
  • At runtime, the only obvious difference between the Class objects (apart from name) is that Test$1 is an "anonymous class" and Test$LikeThat is a "member class". Both of them have an enclosing class; neither of them have an enclosing constructor or method. (I only checked the likely-looking methods; there may be other differences.)
    • EDIT: According to getModifiers(), Test$1 is static and Test$LikeThat is static final! According to the language spec, Test$1 should actually be final. Hmm...
  • According to javap -c -verbose -s -private -l,

    • Test$1 specifies an "EnclosingMethod" (probably Test's static initializer?)
    • Test$LikeThat has an extra entry under "InnerClass" (#12; //class Test$1) and a curious constructor Test$LikeThat(Test$1). This appears to happen because LikeThat is private which makes the constructor private, so the compiler generates a "trampoline" to allow it to be called from Test.

If you remove the private, they appear to compile to roughly the same thing apart from the EnclosingMethod entry.

Test$1 does not have the field final Test this$0; that it would if it was defined in a non-static context.

Community
  • 1
  • 1
tc.
  • 33,468
  • 5
  • 78
  • 96
0

Seems perfectly legitimate to me. Since the anonymous class is static it won't have a reference to any enclosing class, but there should be no evil consequences from that.

Well, other than being a hidden singleton object, that's pretty evil.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
0

Of course they are not. I always use static nested classes, unless I need the implicit association to the enclosing object.

In java terminology nested class := a class which is declared within another class (or interface). Inner classes are those nested classes which have an associated instance from the enclosing class. (Nonstatic member classes, local classes, anonymous classes).

The implicit association can prevent garbage collection sometimes.

Karl
  • 3,170
  • 1
  • 21
  • 28
-1

These can be very convenient because of possibility to make circular references:

class A
{ 
    public static final A _1 = new A() {
        public A foo()
        {
            return _2;
        }
    };

    public static final A _2 = new A() {
        public A foo()
        {
            return _1;
        }
    };
}

Creation of several objects which are holding references to each other can be very awkward without usage of anonymous classes.

okutane
  • 13,754
  • 10
  • 59
  • 67