3

I came across this piece of code while I was working on a project, this was reported as a bug for something.

public class Test {

    public static Test ONE = new Test() {
        @Override
        public int value() {
            return 1;
        }
    };

    private Test() {
    }

    public int value() {
        return 0;
    }
}

What I think this code means:
I think that this is simply instantiating the class Test with a reference variable named ONE.
What the user mentioned:
The user mentioned that this is a nested class within the outer class, but I'm confused that how can a class be nested within itself.
What I have researched:
I used code parser named ANTLR to parse this code and it showed that this is not a class, insted used the token Type.
Thanks in Advance

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
  • Hmm, on second thought, it *might* be nested, if it's the anonymous class that is nested (probably named `Test$1` or somesuch). But that kind of construct isn't what I think of as "nested", it's an anonymous class imo. – markspace Mar 11 '21 at 15:01
  • `new Test() {...}` is a nested class inside `Test` that is also an anonymous subclass of `Test`, used to create one instance. – khelwood Mar 11 '21 at 15:01
  • I'd wait a bit and let others chime in before deleting, I could be wrong and the discussion might be interesting. – markspace Mar 11 '21 at 15:02
  • Related and worth a read: [Why is an anonymous class in a static context valid](https://stackoverflow.com/q/27738935/5515060), not sure if it would apply as a duplicate though – Lino Mar 11 '21 at 15:03

2 Answers2

5

It's an (Nested) Anonymous Inner Class, but not what people typically call a Nested Class which, as far as I've noticed, usually refers to the non-local non-anonymous member classes. Though any class which isn't a Top-Level Class is of course a Nested Class.

The class is not "nested within itself" since new Test() { ... } is actually an anonymous subclass of Test.

I've included a diagram I found here and a pretty exhaustive list of examples in code.

1


import static java.lang.System.out;
@SuppressWarnings("unused")
public class Test {
    static String staticField = "field in class static context";
    String instanceField = "field in instance context";
    
    static Object staticRef1 = /* Static Field Reference to ... */
    /* ... Anonymous Inner Class created in static context */
    new Object() { 
        public void print() {
            out.println(staticField);
        }
    };
    
    static Object staticRef2; /* Static Field Reference to ... */
    static { /* static block ... */
        String localVar_InStaticBlock = "local variable in static block context";
        
        /* ... Anonymous Inner Class created in static block context */
        staticRef2 = new Object() {
            public void print() {
                out.println(localVar_InStaticBlock);
                out.println(staticField);
            }
        };
        
        /* Local Reference to Anonymous Inner Class created in static block context */
        Object localVar = new Object() {
            public void print() {
                out.println(localVar_InStaticBlock);
                out.println(staticField);
            }
        };
    }
    public Object instanceRef1 = /* Instance Field reference to ... */
    /* ... Anonymous Inner Class created in instance context */
    new Object() {
        public void print() {
            out.println(instanceField);
            out.println(staticField);
        }
    }; 

    /* Instance Field reference to ... */
    public Object instanceRef2;
    { /* instance block... */
        String localVar_InInstanceBlock = "local variable in instance block context";
        
        /* ... Anonymous Inner Class created in instance block context*/
        instanceRef2 = new Object() {
            public void print() {
                out.println(localVar_InInstanceBlock);
                out.println(instanceField);
                out.println(staticField);
            }
        };
        
        /* Local Reference to Anonymous Inner Class created in instance block context */
        Object localVar = new Object() {
            public void print() {
                out.println(localVar_InInstanceBlock);
                out.println(instanceField);
                out.println(staticField);
            }
        };
    }
    /* Nested Inner Class */
    class NestedInnerClass {
        public void foo() {
            out.println(instanceField);
            out.println(staticField);
        }
    }

    /* Nested Static Class */
    static class NestedStaticClass {
        public void foo() {
            out.println(staticField);
        }
    }
    void method() {
        String localVar_InMethodContext = "local variable in method context";
        
        /* Method-Local Inner Class */
        class MethodLocalInnerClass {
            void print() {
                out.print(localVar_InMethodContext);
                out.println(instanceField);
                out.println(staticField);
            }
        }
        
        Object methodLocalTest = new MethodLocalInnerClass();
        // ...
    }
}
xtratic
  • 4,600
  • 2
  • 14
  • 32
  • I think it's a nested class, not an inner class. A nested class belongs to a containing class. An inner class belongs to a particular instance of its containing class. – khelwood Mar 11 '21 at 21:51
  • @khelwood Any non-top-level class is a nested class, but OPs class is a *(Nested) Anonymous Inner Class* defined in a static context and referenced by a static reference. – xtratic Mar 12 '21 at 02:14
2

While xtratic answer is correct, some additional explanation might be provided. Your code is interpreted as if you declare a new inner class which is a subclass of Test and then instantiate an object of this class:

public class Test {

    public static Test ONE = new $1();

    class $1 extends Test {
        @Override
        public int value() {
            return 1;
        }
    }

    private Test() {
    }

    public int value() {
        return 0;
    }
}

If you compile your Test.java you'll see that two class files are generated, Test.class and Test$1.class, the later contains the anonymous inner class which was auto-generated. The name of the anonymous class is $1, but because it's an inner class of Test the class file has name Test$1.class.

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
Alex Sveshnikov
  • 4,214
  • 1
  • 10
  • 26
  • So if this class was not an inner class but something like [Oracledoc](https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html#:~:text=Anonymous%20classes%20enable%20you%20to,a%20local%20class%20only%20once.) then its name would have been simple $1. I mean if it wouldn't have been an inner class but just an anonymous class then its name would have been simply $1? –  Mar 11 '21 at 15:47
  • Well, actually the name of the class is just `1`. The full binary name of the class is `$`, so it's placed into `Test$1.class` file. Obviously you can't create a class with name `1` manually. – Alex Sveshnikov Mar 11 '21 at 16:30
  • Btw, similar idea is used for lambda's: their are just automatically generated methods with special numerical names, which cannot be created manually. – Alex Sveshnikov Mar 11 '21 at 16:37