1

I've been trying to understand the difference between nested, local, anonymous classes and I'm confused about a few things, but mostly why you cannot do this:

class OuterClass {

    InnerClass innerClass = new InnerClass() {
        //DO SOMETHING
    };
}

w/o doing this...

class OuterClass {
    class InnerClass {
    }

    InnerClass innerClass = new InnerClass() {
        //DO SOMETHING
    };
}

or this...

 class OuterClass {
       
        InnerClass innerClass = new InnerClass() {
            //DO SOMETHING
        };
 }

 class InnerClass {
 }

How is this at all different from this really?

class OuterClass {
           
            InnerClass innerClass = new InnerClass();
            innerClass.innerClassMethod(); 

     }
    
     class InnerClass {
         public void innerClassMethod() {
         }
     }

And why is it called anonymous? I dont understand that. Reading this link here I understand the logistical differences (i.e. no name, only 1 instantiation, only accessible where defined, etc. But it's really not a class so why is it called a class? It's actually, from what I can see an instantiation of a class. I see you can have other methods as well from the class it is derived from, but how are you allowed to have completely different methods than the base class w/o having to use @Override?

  • 2
    The link you provided states that an anonymous class is a class *that has no name.* None of your examples use non-named classes. – Robert Harvey Jul 21 '21 at 13:59
  • It really _is_ a class - a subclass of the named class; and it's _also_ an instantiation of this anonymous subclass. It is an anonumous class because it really has no name. It is not an instance of InnerClass, but an instance of an anonymous class _derived from_ InnerClass. – k314159 Jul 21 '21 at 13:59
  • 2
    What is `InnerClass` supposed to refer to in the first example? Anonymous classes have to have a parent. You can do `Object foo = new Object() { ... }` if you want the parent to be `Object`, but every class has to have a parent, even anonymous ones. – Silvio Mayolo Jul 21 '21 at 14:00
  • In fact no difference at all. For all from the above javac compiler will crate additional class file. I.e. something like OuterClass#InnerClass.class Everything else, including anonym classes and lambdas - are syntax sugar. – Victor Gubin Jul 21 '21 at 14:01
  • Your third example is the only one that looks like the anonymous class Pizza example in the link you provided. Look very carefully at that code. – Robert Harvey Jul 21 '21 at 14:03
  • @SilvioMayolo - The first example is what I am confused about. If we are calling this an anonymous CLASS, why does it need a parent at all? –  Jul 21 '21 at 14:03
  • @RobertHarvey - is the second example not an example of an anon class? –  Jul 21 '21 at 14:04
  • It's a class. Every class has a parent. The "anonymous" part doesn't come into play at that point. "Anonymous" means you don't give the class a name, but every class has a parent, even anonymous ones. – Silvio Mayolo Jul 21 '21 at 14:05
  • Related: https://stackoverflow.com/a/21557857 – Pshemo Jul 21 '21 at 14:07
  • 1
    @SilvioMayolo, ah ok so anon classes are merely children of their parent class without name, that makes sense. I guess I dont really see the point of using this though. –  Jul 21 '21 at 14:07
  • @madmaxx01 The official [doc](https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html) provides more details and might make the concept more clear – Gautham M Jul 21 '21 at 14:09
  • 2
    "I guess I dont really see the point of using this though" it is useful for instance in swing applications where we often use something along `component.add*SomeListenerType*(new TypeOfListener(){ void listeningMethod(){ usually unique code for that specific listener } });`. Here we don't want to reuse `usually unique code for that specific listener` anywhere else so we don't really need to create class for it. – Pshemo Jul 21 '21 at 14:09
  • 3
    Yeah, you've got the right idea. It can be very useful for implemented interfaces like `Listener`-type things. Often, you want an event listener with a specific behavior, but you only need that behavior in one place. It just saves you the trouble of making a named class that you're going to only use once ever. – Silvio Mayolo Jul 21 '21 at 14:10
  • @Pshemo Hah, great minds, I suppose :P – Silvio Mayolo Jul 21 '21 at 14:10
  • @SilvioMayolo "Every class has a parent" -- nitpick: every class except Object ;-) – k314159 Jul 21 '21 at 14:12
  • @SilvioMayolo so its kind of the same as saying `class Parent{}` and then `class Child extends Parent{}` but you're only using this instantiation one time so why bother naming it? –  Jul 21 '21 at 14:12
  • Please consider to rework your question. People shouldnt be forced to read through 20 comments to understand what you are asking for. Start by making sure the title (anonymous classes) fits your actual question (inner classes). – GhostCat Jul 21 '21 at 14:14
  • The bigger question now is why am I allowed to write the same methods with different implementations from the parent class the anon class extends from w/o having to use @Override? –  Jul 21 '21 at 14:23
  • `@Override` annotation isn't mandatory to actually override a method. That annotation was added in Java 1.5 and overriding was available since Java 1.0. Purpose of `@Override` annotation is to let compiler inform us about failed attempt to override a method (like when we didn't provide correct name of method or parameter types). More info: [When do you use Java's @Override annotation and why?](https://stackoverflow.com/q/94361) – Pshemo Jul 21 '21 at 14:34

2 Answers2

2
  • Everywhere you have written 'DO SOMETHING' you are actually creating a new class that inherits from whatever type is behind the 'new' Keyword...

  • This temporary class has no name of its own, hence anonymous.

  • It ends with ; because it is actually just a parameter of the outer class.

  • As Silvio pointed out in the comments all classes extend some class, even if it just the Object class.

You can't do this:

class OuterClass {

    InnerClass innerClass = new InnerClass() {
        //DO SOMETHING
    };
}

Because InnerClass does not exist yet to inherit from.

H3AR7B3A7
  • 4,366
  • 2
  • 14
  • 37
1

Two points about that what you're doing there with InnerClass innerClass = new InnerClass() {};

First you're using the class InnerClass as a template that you extend by another anonymous class, instantiate that and save that reference to the variable innerClass. So InnerClass has to be defined. And because there is no available named class definition for the object named innerclass, this is why it's anonymous.

Second, your comment //DO SOMETHING in there is wrong. The only thing you can do in there is to override already existing methods. Yes, you can also add new methods, but you cannot call the from the outside directly. InnerClass could be a normal class, an abstract class, or an interface.

Defining class InnerClass {} inside another class would be a nested class. The way you do it it is dependent on the state of the OuterClass. This could also be static, i.e. decoupled from any instance that Outerclass and its generica parameters would have.

Your third example is a normal (additional) class definition inside a file. But because Java Language Specification defines that there can not be two top-level public classes in one file, this second class definition cannot be public. Because JLS also states that the one top-level public class inside a file has to have the same name as the file it's defined in.

And to answer your last question, in reference to what I said about 'not being able to acces other methods': In your last example you explicitly define the method innerClassMethod() in a names class, and so it can be accessed.

JayC667
  • 2,418
  • 2
  • 17
  • 31
  • It occurs to me that "anonymous class" is a really poor name for this mechanism. It describes an implementation detail that has little to do with its actual purpose. – Robert Harvey Jul 21 '21 at 14:12
  • We have anonymous classes in C#, but they don't look anything like this. Example in C#: – Robert Harvey Jul 21 '21 at 14:13
  • `myAnonyClassObject = new { Name = "Abhimanyu", Age = 21 };` – Robert Harvey Jul 21 '21 at 14:13
  • I suppose Java does it the way it does because it doesn't have properties like C#. You have to use getters and setters instead. – Robert Harvey Jul 21 '21 at 14:15
  • Are you sure? Because I see you can do this in my IDE...`class OuterClass {class InnerClass { public int print() { System.out.println("print"); return 0; } } InnerClass innerClass = new InnerClass() { //DO SOMETHING public int print(int number) { return 1; } }; }` –  Jul 21 '21 at 14:17
  • 1
    @madmaxx01 yes, you can do that. But you can never call that `new OuterClass().innerClass.print(3);` because it is not defined. What you're doing there is *overloading* the method, i.e. add a method with another signature, which cannot be called as it is not defined in InnerClass. *overloading* the `public int print()` and calling it would work, but then you'd need to lose the `int number` parameter. – JayC667 Jul 21 '21 at 21:47
  • 1
    @RobertHarvey Well, as in Java, any custom reference type has to be derived from `Object` either explicitly or implicitly, we could also state `Object myAnonyClassObject = new Object() { String name = "Abhimanyu"; int age = 21; };`, but again, we could not easily access the properties easily. We could with Reflection or by inheriting from other classes, but that's exactly what I said above. Java's strict typing always refers to the explicit type of the variable we're using, not the real one. If we have `Object o = "Peter";` then o is an Object to the compiler, until we check/cast it to String – JayC667 Jul 21 '21 at 21:54
  • 1
    @RobertHarvey That all has nothing to do with properties, but how Java's explicit type system works. – JayC667 Jul 21 '21 at 21:55