你好!在今天的课程中,我们将继续讨论嵌套类的主题。轮到最后一组了——Java 中的匿名内部类。让我们回到我们的图表: 就像我们在上一讲中讨论的本地类一样,匿名类是内部类的子集。它们之间也有一些相似之处和不同之处。但首先,让我们弄清楚:为什么他们实际上被称为“匿名”?为此,我们来看一个简单的示例。想象一下,我们有一个不断运行并执行某些操作的主程序。我们想为这个程序创建一个由多个模块组成的监控系统。第一个模块将监视一般性能指标并保留日志,第二个模块将记录错误并将错误记录在错误日志中,第三个模块将监视可疑活动:例如,未经授权的访问尝试和其他与安全相关的事情。由于所有三个模块本质上应该在程序开头启动并在后台运行,因此最好为它们创建一个通用接口:
那么我们今天的课程就到此结束了!尽管我们已经介绍了最后一组嵌套类,但我们还没有完成这个主题。接下来我们将学习关于嵌套类的哪些内容?你一定很快就会知道!:)
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 个对象 - GeneralIndicatorsMonitoringModule
、ErrorMonitoringModule
、 - 并在每个对象上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 机器内部会发生以下情况:
- 创建一个未命名的 Java 类来实现
MonitoringSystem
. - 编译器看到这样一个类,就会要求你实现所有接口方法
MonitoringSystem
(我们这样做了 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!");
}
};
最后,我可以向您推荐一个关于匿名类主题的精彩视频,其中对该主题的解释尽可能简单明了:)
GO TO FULL VERSION