使用技巧:内部类和匿名类优化Java代码

技巧|优化

Java 1.1通过对Java语言规范进行修改,显著简化了一些实用结构的实现。在那些修改中,最引人注目的就是内部类和匿名类。如运用得当,它们可使程序更易理解和维护。下面来看看这些特性具体是如何工作的,如何正确使用它们,以及如何避免一些常见的错误。

内部类

简单地说,“内部类”是在另一个类的内部声明的类。从Java 1.1开始,你可在一个类中声明另一个类,这与声明字段和方法非常相似。包装了内部类声明的类就称为“外部类”。

实际上,Java语言规范还允许你做更多的事情,包括:

在另一个类或者一个接口中声明一个类。

在另一个接口或者一个类中声明一个接口。

在一个方法中声明一个类。

类和接口声明可嵌套任意深度。

清单A是类和接口的一些空白声明,它演示了这些可能性。

使用一个import语句,你可像使用其他任何标准类那样省略package名称。此外,在外部类中,可利用简单名称来引用所有内部类和接口(参见清单A中的new语句)。注意从Method1中引用Inner2仍需指定Interface1,因为Inner2在一个不同的级别上。

表A总结了清单A中声明的每个内部类和接口的完全限定名称。用了import语句之后,就可采用较短的形式。当然,在外部类中,你还可省略外部类的名称。

名称

类/接口

Inner1 mypackage.Inner1

Interface1 mypackage.Interface1

Inner2 mypackage.Interface1.Inner2

Interface2 mypackage.Interface1.Interface2

Inner3 Inner3对于Method1来说是local的,所以它不可在方法外部访问

引用内部类

内部类最自然的一种应用就是声明只在另一个类的内部使用的类,或者声明与另一个类密切相关的类。如清单B所示,它是一个链表的简单实现。由于Node类通常只在LinkedList的范围内使用,所以最好将Node声明为LinkedList的一个内部类。

适用于类成员的访问控制修改符也适用于内部类;也就是说,内部类可以具有package、protected、private和public访问权限,它们的语义和正常的语义没有什么不同。由于Node要在LinkedList的外部使用,所以把它声明为public。

然而,修饰符static具有不同的含义。应用于内部类时,它声明的类具有与其他类相同的语义,也就是可进行实例化,并像一个标准类那样使用。惟一的区别就是它拥有对外部类的所有静态成员的完全访问权限。清单C展示了一个简单的程序,它创建一个链表,并将它打印到标准输出设备。

非静态内部类

如果内部类没有指定static修饰符,就拥有对外部类的所有成员的完全访问权限,包括实例字段和方法。为实现这一行为,非静态内部类存储着对外部类的实例的一个隐式引用。

所以,对一个非静态内部类进行实例化需要采用不同语法的new语句:

.new

这种形式的new语句要求外部类的一个实例,使内部类能在那个实例的上下文中创建。注意清单A声明了几个非静态内部类,并用标准的new语句在Method1中实例化它们。

之所以能那样做,是因为Method1是外部类的一个实例方法,所以new语句会在外部类的一个实例的上下文中隐式地执行。只有在外部类的外部或者在其他对象的上下文中实例化一个非静态内部类时,才需要使用修改过的语法。

但是,非静态内部类具有一些限制。尤其是,它们不能声明静态初始化列表和静态成员,除非是在常量字段中。此外,方法内部声明的内部类不能访问方法的局部变量和参数,除非它们被初始化成final。

匿名类

匿名类是不能有名称的类,所以没办法引用它们。必须在创建时,作为new语句的一部分来声明它们。

这就要采用另一种形式的new语句,如下所示:

new <类或接口> <类的主体>

这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。它还创建那个类的一个新实例,并把它作为语句的结果而返回。要扩展的类和要实现的接口是new语句的操作数,后跟匿名类的主体。

如果匿名类对另一个类进行扩展,它的主体可以访问类的成员、覆盖它的方法等等,这和其他任何标准的类都是一样的。如果匿名类实现了一个接口,它的主体必须实现接口的方法。

注意匿名类的声明是在编译时进行的,实例化在运行时进行。这意味着for循环中的一个new语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例。

从技术上说,匿名类可被视为非静态的内部类,所以它们具有和方法内部声明的非静态内部类一样的权限和限制。

如果要执行的任务需要一个对象,但却不值得创建全新的对象(原因可能是所需的类过于简单,或者是由于它只在一个方法内部使用),匿名类就显得非常有用。匿名类尤其适合在Swing应用程序中快速创建事件处理程序。

清单D就是一个非常简单的Swing应用程序,它展示了与匿名类有关的几个概念。这个例子创建了两个匿名类。第一个对java.awt.event.WindowAdapter进行扩展,并在应用程序窗口关闭时调用应用程序的onClose方法。

即使onClose声明为private,匿名类也能调用它,因为匿名类本质上是应用程序类的一个内部类。第二个匿名类实现了java.awt.ActionListener接口,它在一个按钮被按下后关闭应用程序窗口。注意匿名类可以访问本地变量frame。这是由于匿名类在与frame相同的方法内部声明。然而,frame要被声明为final,否则会生成编译错误。

更优化的代码

内部和匿名类是Java 1.1为我们提供的两个出色的工具。它们提供了更好的封装,结果就是使代码更容易理解和维护,使相关的类都能存在于同一个源代码文件中(这要归功于内部类),并能避免一个程序产生大量非常小的类(这要归功于匿名类)。

时间: 2024-09-19 09:27:42

使用技巧:内部类和匿名类优化Java代码的相关文章

使用内部和匿名类优化Java代码

优化 Java 1.1通过对Java语言规范进行修改,显著简化了一些实用结构的实现.在那些修改中,最引人注目的就是内部类和匿名类.如运用得当,它们可使程序更易理解和维护.下面来看看这些特性具体是如何工作的,如何正确使用它们,以及如何避免一些常见的错误.    内部类    简单地说,"内部类"是在另一个类的内部声明的类.从Java 1.1开始,你可在一个类中声明另一个类,这与声明字段和方法非常相似.包装了内部类声明的类就称为"外部类".    实际上,Java语言规

全面了解Java中的内部类和匿名类_java

Java内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦.学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构.下面从以下几个方面来介绍: 第一次见面 public interface Contents { int value(); } public interface

Java 中的内部类和匿名类

Java 内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口.由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能. 不过你可能要质疑,更改一下方法的不就行了吗? 的确,以此作为设计内部类的理由,实在没有说服力. 真正的原因是这样的,java 中的内部类和接口加在一起,可以的解决常被 C++ 程序员抱怨 ja

Java的内部类和匿名类

提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class), 关于这两者的区别与联系,在下文中会有对比.内部类从表面上看,就是在类中又定义了一个类(下文会看到,内部类可以在很多地方定义),而实际上并没有那么 简单,乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用 心良苦.学会使用内部类,是掌握Java高级编程的一部分,它可以让你更

Java通过接口实现匿名类的实例代码_java

复制代码 代码如下: package com.chase.test; /** * 通过接口实现匿名类的实例 *  * @author Chase *  * @date 2013-10-18 下午04:28:17  * * @version V1.0 */interface I1 {    void print();    void eat();} public class AnonymousClass {     public static String excute(I1 c){       

使用 IBM 静态工具优化 Java 代码,第 2 部分: 分析错误报告

概述 BEAM 报告的结果文件是通过 build.xml 中 --beam::complaint_file 所定义的,在这 里,本文假设其为 BEAM-messages.BEAM-messages 记录着报出的所有代码缺陷,这些缺陷 分为 ERROR,MISTAKE 和 WARNING 三大类,严重程度依次递减.每一个具体的 ERROR, MISTAKE 和 WARNING 都代表着一个错误模式,本文接下来就通过实例分析理解其中的某些 重要错误模式,告诉读者在写 Java 代码时如何避免这些错误

使用 IBM 静态工具优化 Java 代码,第 1 部分: 工具入门

什么是 BEAM? 关于缩写 BEAM 的声明 处于表达简洁的目的,本文采用了工具名称的缩写 - BEAM,这只是工具全称 "Checking Tool for Bugs Errors and Mistakes"的文字缩写,而不是工具的名称. IBM Checking Tool for Bugs Errors and Mistakes(本文后面将采用其文字缩写 BEAM )是 IBM 开发的一个静态分析工具,可以用于分析并查找出 C, C++ 和 Java 代码中的一 些不容易发现的潜

优化-java代码中有个循环,数据量一大直接网页报500错误

问题描述 java代码中有个循环,数据量一大直接网页报500错误 求大神帮忙优化一下,10000数据还可以,但是数据一多网页就崩溃了,就是代码中的row++,加上去就不行了 解决方案 结果是内存益处了 那就是你的程序太耗费资源了. 那个获取page的方法: 1--Page对象村的东西太多了,很多何你写入单元格的数据没关系, 既然这块逻辑是大数据量的,为什么不拆分针对这块逻辑的结构呢? 使用Page造成了很大的内存浪费 在循环外部定义这个结构 List list = null 2--将方法的参数精

用stack变量优化Java代码

java程序包含了大量的对象,我们需要了解它们是从哪里被访问的,变量存储于何处对程序的性能有显著的影响--尤其是某些需要被频繁访问的变量. 我们写一个Java类,在其内部方法中定义的局部变量或对象是存储在stack(堆栈)中的,且JVM是一种stack-based的,因此访问和操纵stack中的数据时性能最佳.而Java类的instance变量(这个类的field)和static变量是在constant pool(常量池)中存储和得到访问的.constant pool中保存了所有的符号引用(sy