使用内部和匿名类优化Java代码
Java 1.1通过修改Java语言规范,大大简化了一些实用结构的实现。在这些修改中,最引人注目的是内部类和匿名类。如果使用得当,它们可以使程序更容易理解和维护。让我们来看看这些功能是如何工作的,如何正确使用它们,以及如何避免一些常见的错误。
内部类
简单地说,“内部类”是在另一个类内部声明的类。从Java 1.1开始,可以在一个类中声明另一个类,这与声明字段和方法非常相似。包装了内部类声明的类称为外部类。
实际上,Java语言规范允许你做更多的事情,包括:
在另一个类或接口中声明一个类。
在另一个接口或类中声明接口。
在方法中声明类。
类和接口声明可以嵌套到任何深度。
清单A是一些空类和接口的白色声明,演示了这些可能性。
使用import语句,您可以像任何其他标准类一样省略包名。此外,在外部类中,所有内部类和接口都可以通过简单的名称引用(参见清单A中的new语句)。请注意,从Method1引用Inner2仍然需要指定Interface1,因为Inner2处于不同的级别。
表A总结了清单A中声明的每个内部类和接口的完全限定名,使用import语句后,可以采用较短的形式。当然,在外部类中,也可以省略外部类的名称。
name
class/interface
inner 1 my package . inner 1
interface 1 my package . interface 1
inner 2 my package . interface 1 . inner 2
2 interface my package . interface 1 . interface 2
inner 3 inner 3是Method1的局部变量,因此不能在方法外部访问它。
对内部类的引用
内部类最自然的应用之一是声明只在另一个类内部使用的类,或者与另一个类密切相关的类。如清单B所示,这是一个链表的简单实现。由于Node类通常只在LinkedList的范围内使用,所以它被声明为LinkedList的内部类。
适用于类成员的访问控制修饰符也适用于内部类;也就是说,内部类可以有package、protected、private和public访问权限,它们的语义和正常的语义没有区别。因为节点将在LinkedList之外使用,所以它被声明为public。
然而,修饰语static有不同的含义。当应用于内部类时,其声明的类具有与其他类相同的语义,也就是说,它可以像标准类一样被实例化和使用。唯一的区别是它可以完全访问外部类的所有静态成员。清单C显示了一个简单的程序,它创建一个链表并将其打印到标准输出设备上。
非静态内部类
如果内部类没有指定static修饰符,它可以完全访问外部类的所有成员,包括实例字段和方法。为了实现这种行为,非静态内部类存储了对外部类实例的隐式引用。
因此,实例化非静态内部类需要使用不同语法的新语句:
。new
这种形式的new语句需要一个外部类的实例,这样就可以在该实例的上下文中创建内部类。注意,清单A声明了几个非静态内部类,并用标准的new语句在Method1中实例化它们。
我们可以这样做,因为Method1是外部类的实例方法,所以新语句将在外部类实例的上下文中隐式执行。只有当非静态内部类在外部类之外或在其他对象的上下文中被实例化时,才需要修改的语法。
但是,非静态内部类有一些限制。特别是,它们不能声明静态初始化列表和静态成员,除非它们在常量字段中。此外,在方法内部声明的内部类不能访问该方法的局部变量和参数,除非它们被初始化为final。
匿名类
匿名类是不能有名字的类,所以没有办法引用它们。它们必须在创建时声明为新语句的一部分。
这需要另一种形式的new语句,如下:
new
这种形式的new语句声明了一个新的匿名类,它扩展了给定的类或者实现了给定的接口。它还创建该类的新实例,并将其作为语句的结果返回。要扩展的类和要实现的接口是新语句的操作数,后跟匿名类的主体。
如果一个匿名类扩展了另一个类,它的主体可以访问该类的成员、覆盖它的方法等等,这与任何其他标准类是一样的。如果匿名类实现了一个接口,那么它的主体必须实现该接口的方法。
注意,匿名类的声明是在编译时进行的,而实例化是在运行时进行的。这意味着for循环中的新语句将创建同一个匿名类的几个实例,而不是创建几个不同匿名类的一个实例。
从技术上来说,匿名类可以视为非静态内部类,因此它们与方法内部声明的非静态内部类具有相同的权限和限制。
如果要执行的任务需要一个对象,但不值得创建一个全新的对象(原因可能是所需的类太简单,或者因为只在方法内部使用),那么匿名类就非常有用。匿名类特别适合在Swing应用程序中快速创建事件处理程序。
清单D是一个非常简单的Swing应用程序,它展示了与匿名类相关的几个概念。这个例子创建了两个匿名类。第一个扩展java.awt.event.WindowAdapter,在应用程序窗口关闭时调用应用程序的onClose方法。
即使onClose声明为私有,匿名类也可以调用它,因为匿名类本质上是应用类的内部类。第二个匿名类实现java.awt.ActionListener接口,该接口在按下按钮后关闭应用程序窗口。注意,匿名类可以访问局部变量框架。这是因为匿名类是在与frame相同的方法中声明的。但是,应该将该帧声明为最终帧,否则会产生编译错误。
更优化的代码
内部类和匿名类是Java 1.1提供的两个优秀工具。它们提供了更好的封装。因此,代码更容易理解和维护,相关的类可以全部存在于同一个源代码文件中(由于内部类),并且可以在一个程序中避免大量非常小的类(由于匿名类)。
0条评论