JavaRush /Java 博客 /Random-ZH /Java 中的匿名类

Java 中的匿名类

已在 Random-ZH 群组中发布
你好!在今天的课程中,我们将继续讨论嵌套类的主题。轮到最后一组了——Java 中的匿名内部类。让我们回到我们的图表: 匿名类 - 2就像我们在上一讲中讨论的本地类一样,匿名类是内部类的子集。它们之间也有一些相似之处和不同之处。但首先,让我们弄清楚:为什么他们实际上被称为“匿名”?为此,我们来看一个简单的示例。想象一下,我们有一个不断运行并执行某些操作的主程序。我们想为这个程序创建一个由多个模块组成的监控系统。第一个模块将监视一般性能指标并保留日志,第二个模块将记录错误并将错误记录在错误日志中,第三个模块将监视可疑活动:例如,未经授权的访问尝试和其他与安全相关的事情。由于所有三个模块本质上应该在程序开头启动并在后台运行,因此最好为它们创建一个通用接口:
public interface MonitoringSystem {

   public void startMonitoring();
}
它将由 3 个特定类来实现:
public class GeneralIndicatorsMonitoringModule implements MonitoringSystem {

@Override
   public void startMonitoring() {
       System.out.println("Monitoring of general indicators has started!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Bug Tracking Monitoring Started!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Security monitoring started!");
   }
}
似乎一切都井然有序。我们有一个相当清晰的由几个模块组成的系统。他们每个人都有自己的行为。如果我们需要新的模块,我们可以添加它们,因为我们有一个很容易实现的接口。但让我们考虑一下我们的监控系统将如何工作。 匿名类 - 3本质上,我们应该只创建 3 个对象 - GeneralIndicatorsMonitoringModuleErrorMonitoringModule、 - 并在每个对象上SecurityModule调用一个方法。startMonitoring()也就是说,您所需要做的就是创建 3 个对象并对其调用 1 个方法。
public class Main {

   public static void main(String[] args) {

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

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
控制台输出:

Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
对于这么小的工作,我们编写了一整套系统:3 个类和一个接口!而这一切都是为了6行代码。另一方面,我们有什么选择?是的,我们编写这样的“一次性”类并不是很酷。但我们该如何解决这个问题呢?这就是匿名内部类为我们提供帮助的地方!在我们的例子中它们是这样的:
public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Monitoring of general indicators has started!");
           }
       };



           MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Bug Tracking Monitoring Started!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Security monitoring started!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
让我们弄清楚这是怎么回事!看起来我们正在创建一个接口对象:
MonitoringSystem generalModule = new MonitoringSystem() {

@Override
   public void startMonitoring() {
       System.out.println("Monitoring of general indicators has started!");
   }
};
但我们很早就知道,创建界面对象是不可能的!没错,这是不可能的。事实上,我们不这样做。我们写下的那一刻:
MonitoringSystem generalModule = new MonitoringSystem() {

};
在 Java 机器内部会发生以下情况:
  1. 创建一个未命名的 Java 类来实现MonitoringSystem.
  2. 编译器看到这样一个类,就会要求你实现所有接口方法MonitoringSystem(我们这样做了 3 次)。
  3. 创建了该类的一个对象。注意代码:
MonitoringSystem generalModule = new MonitoringSystem() {

};
末尾有一个分号!她站在那里是有原因的。我们同时声明一个类(通过大括号)并使用创建其对象我们的三个对象中的每一个都以自己的方式(); 重写了一个方法。startMonitoring()最后我们简单地对每个方法调用这个方法:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
控制台输出:

Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
就这样!我们已经完成了我们的任务:我们创建了三个对象MonitoringSystem,以三种不同的方式重新定义它,并调用它三次。所有三个模块均已成功启动并运行。同时,我们的程序结构也变得简单多了!GeneralIndicatorsMonitoringModule毕竟,ErrorMonitoringModule现在可以SecurityModule从程序中完全删除课程!我们根本不需要它们——没有它们我们也能过得很好。如果我们的每个匿名模块类需要一些不同的行为,其他人没有的自己的特定方法,我们可以轻松添加它们:
MonitoringSystem generalModule = new MonitoringSystem() {

   @Override
   public void startMonitoring() {
       System.out.println("Monitoring of general indicators has started!");
   }

   public void someSpecificMethod() {

       System.out.println("Specific method for first module only");
   }
};
Oracle 文档有一个很好的建议:“如果您需要一次性使用本地类,请使用匿名类。” 匿名类是一个成熟的内部类。因此,它可以访问外部类变量,包括静态变量和私有变量:
public class Main {

   private static int currentErrorsCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {

           @Override
           public void startMonitoring() {
               System.out.println("Bug Tracking Monitoring Started!");
           }

           public int getCurrentErrorsCount() {

               return currentErrorsCount;
           }
       };
   }
}
它们与本地类有一些共同点:它们仅在定义它们的方法内部可见。errorModule在上面的示例中,任何在方法之外访问对象的尝试都main()将失败。还有一个匿名类从其“祖先”——内部类继承下来的一个更重要的限制:匿名类不能包含静态变量和方法。如果我们尝试将上面示例中的方法设为getCurrentErrorsCount()静态,编译器将抛出错误:
//error! Inner classes cannot have static declarations
public static int getCurrentErrorsCount() {

   return currentErrorsCount;
}
如果我们尝试声明静态变量,我们会得到相同的结果:
MonitoringSystem errorModule = new MonitoringSystem() {

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

   @Override
   public void startMonitoring() {
       System.out.println("Bug Tracking Monitoring Started!");
   }

};
最后,我可以向您推荐一个关于匿名类主题的精彩视频,其中对该主题的解释尽可能简单明了:)
那么我们今天的课程就到此结束了!尽管我们已经介绍了最后一组嵌套类,但我们还没有完成这个主题。接下来我们将学习关于嵌套类的哪些内容?你一定很快就会知道!:)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION