User Professor Hans Noodles
Professor Hans Noodles
Level 41

Anonymous classes

Published in the Java Developer group
Hi! Anonymous classes - 1 In today's lesson, we'll continue to examine the topic of nested classes. Now it's time for the last group: anonymous inner classes. Let's return to our diagram: Anonymous classes - 2Like the local classes that we talked about in the last lesson, anonymous classes are a kind of inner class... They also have several similarities and differences. But first, let's dive in: why exactly are they called "anonymous"? To answer this, consider a simple example. Imagine that we have a basic program that is constantly running and doing something. We want to create a monitoring system for this program, made up of several modules. One module will track general indicators of performance and maintain a log. The second will register and record errors in an error log. The third will track suspicious activity: for example, unauthorized access attempts and other security-related things. Because all three modules should, in essence, simply start at the beginning of the program and run in the background, it would be a good idea to create a common interface for them:

public interface MonitoringSystem {
  
   public void startMonitoring();
}
3 concrete classes will implement it:

public class GeneralIndicatorMonitoringModule implements MonitoringSystem {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor security!");
   }
}
It would seem that everything is in order. We have a pretty coherent system made up of several modules. Each of them has its own behavior. If we need new modules, we can add them, because we have an interface that is quite easy to implement. But let's think about how our monitoring system will work. Anonymous classes - 3Basically, we just need to create 3 objects — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule — and call the startMonitoring() method on each of them. That is, all that we need to do is to create 3 objects and call 1 method on them.

public class Main {

   public static void main(String[] args) {

       GeneralIndicatorMonitoringModule generalModule = new GeneralIndicatorMonitoringModule();
       ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
       SecurityModule securityModule = new SecurityModule();

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Console output:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
And with such little work, we've written the entire system: 3 classes and one interface! And all this to achieve 6 lines of code. On the other hand, what are our options? Well, it's not very cool that we wrote these "one-time" classes. But how can we fix this? Here anonymous inner classes come to our rescue! Here's what they look like in our case:

public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor general indicators!");
           }
       };

       

MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor security!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
Let's figure out what's going on! It looks like we're creating an interface object:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
But we have long known that we can't create interface objects! And so it is — it's impossible. In fact, that's not what we're doing. When we write:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
the following happens inside the Java machine:
  1. An unnamed Java class is created that implements the MonitoringSystem interface.
  2. When the compiler sees such a class, it requires you to implement all the methods of the MonitoringSystem interface (we did this 3 times).
  3. One object of this class is created. Pay attention to the code:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
There's a semicolon at the end! It's there for a reason. We simultaneously declare the class (using curly braces) and create an instance of it (using ();). Each of our three objects overrides the startMonitoring() method in its own way. Finally, we simply call this method on each of them:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
Console output:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
That's it! We achieved our objective: we created three MonitoringSystem objects, overrode a method in three different ways, and called it three times. All three modules have been successfully called and are running. At the same time, the structure of our program has become much simpler! After all, the GeneralIndicatorMonitoringModule, ErrorMonitoringModule, and SecurityModule classes can now be entirely removed from the program! We simply don't need them — we did a great job without them. Anonymous classes - 4If each of our anonymous classes needs some different behavior, e.g. its own specific methods that the others don't have, we can easily add them:

MonitoringSystem generalModule = new MonitoringSystem() {
  
   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
  
   public void someSpecificMethod() {

       System.out.println("Specific method only for the first module");
   }
};
The Oracle documentation provides a good recommendation: "Use [anonymous classes] if you need to use a local class only once." An anonymous class is a full-fledged inner class. Accordingly, it has access to the variables of the external class, including static and private variables:

public class Main {

   private static int currentErrorCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {
          
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }

           public int getCurrentErrorCount() {

               return currentErrorCount;
           }
       };
   }
}
They have something in common with local classes: they are visible only inside the method in which they are declared. In the example above, any attempts to access the errorModule object outside the main() method will fail. And there's one more important limitation that anonymous classes inherit from their "ancestors" (inner classes): an anonymous class cannot contain static variables and methods. In the example above, if we try to make the getCurrentErrorCount() method static, the compiler will generate an error:

// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {

   return currentErrorCount;
}
We get the same result if we try to declare a static variable:

MonitoringSystem errorModule = new MonitoringSystem() {

   // Error! Inner classes cannot have static declarations!
   static int staticInt = 10;

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }

};
And our lesson today has come to an end! But even though we have investigated the last group of nested classes, we have not yet finished this topic. What more will we learn about nested classes? You will certainly find out soon! :)
Comments (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Baurzhan Konurbayev Level 40, United States
2 April 2021
Perfect, easy to read!