嵌套类

作者: acc8226 | 来源:发表于2017-11-17 13:57 被阅读17次

目前,书中见到的类、接口和枚举类型都定义为顶层类型。也就是说,都是包的直接成员,独立于其他类型。不过,类型还可以嵌套在其他类型中定义。这种类型是嵌套类型(nested type),一般称为“内部类”,是 Java 语言的一个强大功能。

嵌套类型有两个独立的目的,但都和封装有关。

  • 如果某个类型需要特别深入地访问另一个类型的内部实现,可以嵌套定义这个类型。作为成员类型的嵌套类型,其访问方式与访问成员变量和方法的方式一样,而且能打破封装的规则。
  • 某个类型可能只在特定的情况下需要使用,而且只在非常小的代码区域使用。这个类型应该密封在一个小范围内,因为它其实是实现细节的一部分,应该封装在一个系统的其他部分无法接触到的地方。

嵌套类型也可以理解为通过某种方式和其他类型绑定在一起的类型,不作为完全独立的实体真实存在。类型能通过四种不同的方式嵌套在其他类型中。

提示 内部类编译成功后生成的字节码文件是“外部类$内部类.class”。

  • 静态成员类型
    静态成员类型是定义为其他类型静态成员的类型。嵌套的接口、枚举和注解始终都是静态成员类型(就算不使用 static 关键字也是)。

  • 非静态成员类
    “非静态成员类型”就是没使用 static 声明的成员类型。只有类才能作为非静态成员类型。

  • 局部类
    局部类是在 Java 代码块中定义的类,只在这个块中可见。接口、枚举和注解不能定义为局部类型。

  • 匿名局部(内部)类
    匿名类也是一种局部类,但对 Java 语言来说没有有意义的名称。因此没有名字。接口、枚举和注解不能定义为匿名类型。

“嵌套类型”这个术语虽然正确且准确,但开发者并没有普遍使用,大多数 Java 程序员使用的是一个意义模糊的术语——“内部类”。根据语境的不同,这个术语可以指代非静态成员类、局部类或匿名类,但不能指代静态成员类型,因此使用“内部类”这个术语时无法区分指代的是哪种嵌套类型。

虽然表示各种嵌套类型的术语并不总是那么明确,但幸运的是,从语境中一般都能确定应该使用哪种句法。

下面详细介绍这四种嵌套类型。每种类型都用单独的一节介绍其特性,使用时的限制,以及专用的 Java 句法。

局部类在一个 Java 代码块中声明,不是类的成员。只有类才能局部定义,接口、枚举类型和注解类型都必须是顶层类型或静态成员类型。局部类往往在方法中定义,但也可以在类的静态初始化程序或实例初始化程序中定义。

因为所有 Java 代码块都在类中,所以局部类都嵌套在外层类中。因此,局部类和成员类有很多共同的特性。局部类往往更适合看成完全不同的嵌套类型。

  1. 局部类的特性
    局部类有如下两个有趣的特性:
    和成员类一样,局部类和外层实例关联,而且能访问外层类的任何成员,包括私有成员
    除了能访问外层类定义的字段之外,局部类还能访问局部方法的作用域中声明为 final 的任何局部变量、方法参数和异常参数。
  2. 局部类的限制
    局部类有如下限制。
  • 局部类的名称只存在于定义它的块中,在块的外部不能使用。(但是要注意,在类的作用域中创建的局部类实例,在这个作用域之外仍能使用。稍后本节会详细说明这种情况。)
  • 局部类不能声明为 public、protected、private 或 static。
  • 与成员类的原因一样,局部类不能包含静态字段、方法或类。唯一的例外是同时使用 static 和 final 声明的常量。
  • 接口、枚举类型和注解类型不能局部定义。
  • 局部类和成员类一样,不能与任何外层类同名。
  • 前面说过,局部类能使用同一个作用域中的局部变量、方法参数和异常参数,但这些变量或参数必须声明为 final。这是因为,局部类实例的生命周期可能比定义它的方法的执行时间长很多。

局部类用到的每个局部变量都有一个私有内部副本(这些副本由 javac 自动生成)。只有把局部变量声明为 final 才能保证局部变量和私有副本始终保持一致。

这一点从下述代码中可以看出:

public class Weird {
  // 静态成员接口,下面会用到
  public static interface IntHolder { public int getValue(); }

  public static void main(String[] args) {
    IntHolder[] holders = new IntHolder[10];
    for(int i = 0; i < 10; i++) {
      final int fi = i;

      // 局部类
      class MyIntHolder implements IntHolder {
        // 使用前面定义的final变量
        public int getValue() { return fi; }
      }
      holders[i] = new MyIntHolder();
    }

    // 局部类不在作用域中了,因此不能使用
    // 但是在数组中保存有这个类的10个有效实例
    // 局部变量fi现在已经不在作用域中了
    // 但仍然在那10个对象getValue()方法的作用域中
    // 因此,可以在每个对象上调用getValue()方法,打印fi的值
    // 下述代码打印数字 0 到 9
    for(int i = 0; i < 10; i++) {
      System.out.println(holders[i].getValue());
    }
  }
}

相关文章

  • 局部类和嵌套类

    一. 嵌套类 1.1嵌套类的定义 在一个类体中定义的类叫作嵌套类。拥有嵌套类的类叫外围类。 1.2嵌套类的作用 定...

  • 常见的类

    嵌套类 内部类 枚举类 密封类 数据类 单例模式 伴生对象 嵌套类 嵌套类是嵌套在其它类中的类 不能访问外部类的成...

  • kotlin精讲-第3章(4)嵌套类&数据类

    嵌套类 我们在Kotlin内部还可以定义类,这样的类,我们可以称为嵌套类(nestedclasses)。嵌套类分成...

  • Java 内部类(嵌套类)和局部类

    嵌套类 定义在另一个类中的类,就叫嵌套类。在嵌套类外层的累,称为:外部类最外层的外部类,称为:顶级类 嵌套类又分为...

  • Kotlin面向对象 (7)✔️嵌套类

    嵌套类内部类 (特殊的嵌套类) kotlin 语言中允许在一个类的内部声明另一个类,称为“嵌套类”,嵌套类还有一种...

  • Java-嵌套类

    嵌套类分为两类:静态和非静态。被声明static的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。内部类有两种特殊的...

  • 10. 内部类

    1. 普通嵌套类 在Kotlin中,一个类嵌套在其他类中,而且可以嵌套多层 测试代码: 访问嵌套类的方式是 直接使...

  • kotlin 嵌套和内部类

    Kotlin 嵌套类 与Java类似,Kotlin允许您在另一个称为嵌套类的类中定义一个类 由于嵌套类是其封闭类的...

  • Android开发必知的java嵌套类

    嵌套类 指定义在另一个类的内部的类,嵌套类的存在只是为了他的外围类。嵌套类有四种:静态成员类,非静态成员类,匿名类...

  • C# 嵌套类

    在一个类或类的方法中定义另一个类,分为静态嵌套类(使用少)和非静态嵌套类(又称内部类)。嵌套类是外部类的补充,通过...

网友评论

    本文标题:嵌套类

    本文链接:https://www.haomeiwen.com/subject/oghjvxtx.html