从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • RSS
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金等
  • 职场规划
  • 关于离职
  • 杂谈
  • 📖 读书

    • 读书工具
    • 读书笔记
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

    • 我的 Java 学习路线
    • 安装 Java
    • Java数据类型

    • Java 多版本配置
    • 面向对象

      • 枚举类
      • static 关键字
      • classpath:JVM 查找类的机制
      • 包:Java 组织类的方式
      • jar 包
      • class 版本
      • 抽象类
      • 接口
      • 访问性修饰符
      • 非访问性修饰符
      • 内部类
        • 静态内部类(Static Nested Class)
        • 匿名内部类(Anonymous Class)
        • 小结
        • 参考
    • Java核心类

    • IO

    • Java与时间

    • 异常处理

    • 哈希和加密算法

    • Java8新特性

    • 网络编程

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSE
  • 面向对象
2023-02-13
目录

内部类

# 内部类

内部类(Inner Class),也叫嵌套类,是一个定义在另外一个类范围中的类。

class OuterClass {
    class InnerClass {
        // 定义了一个Inner Class
    }
}
1
2
3
4
5

一个内部类可以如常规类一样使用。通常,在一个类只被它的外部类所使用的时候,才将它定义为内部类。一个内部类具有以下特征:

  • — 个内部类被编译成一个名为 OuterClass$InnerClass 的类

  • 一个内部类可以引用定义在它所在的外部类中的数据和方法,即使是 private 的也可以。这很好理解,因为内部类就在 OuterClass 内部。所以,没必要将外部类对象的引用传递给内部类的构造方法。基于这个原因,内部类可以使得程序更加精简。

  • 一个内部类可以使用可见性修饰符所定义,和应用于一个类中成员的可见性规则一样。

  • 内部类对象通常在外部类中所创建并使用。但是也可以从另外一个类中来创建一个内部类的对象。如果内部类是非静态的,你必须先创建一个外部类的实例。换句话说,Inner Class 的实例不能单独存在,必须依附于一个 Outer Class 的实例。

    可以使用以下语法来创建一个内部类的对象:

        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
    
    1
    2

使用内部类的好处:

  • 一个简单的内部类的用途,是将相互依赖的类结合到一个主类中。这样做减少了源文件的数量。这样也使得类文件容易组织,因为它们都将主类名作为前缀。
  • 另外一个内部类的实际用途是避免类名的冲突。
  • 如果一个类不会被其他应用使用,仅仅会被某个类使用,将它定义在主类里面作为一个内部类使用是恰如其分的。例如为一个按钮设置处理器对象,这个处理器对象不会被其他应用所共享,仅仅用来处理这个按钮。内部类不被其他应用所共享,所以将它定义在主类里面作为一个内部类使用是恰如其分的。

演示:我们定义一个内部类

class Outer{

  private String name;

  Outer(String name ){
    this.name = name;
  }

  class Inner{
    void helloInner(){
      System.out.println("Hello " + Outer.this.name);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

然后在 main 方法里创建内部类对象:

public class LearnInnerClass {
  public static void main(String[] args) {
    Outer outer = new Outer("PeterJXL");
    Outer.Inner inner = outer.new Inner();
    inner.helloInner();
  }
}
1
2
3
4
5
6
7

运行结果:

Hello PeterJXL
1

# 静态内部类(Static Nested Class)

一个内部类可以被定义为 static。一个 static 的内部类可以使用外部类的名字所访问。一个 static 的内部类不能访问外部类中非静态的成员。

使用以下语法来创建一个内部类对象:

OuterClass.InnerClass innerObject = new OuterClass.InnerClass();
1

# 匿名内部类(Anonymous Class)

一个匿名内部类是一个没有名字的内部类。它将一步实现定义一个内部类以及创建一个内部类的实例,简化代码

匿名内部类的语法如下所示:

new SuperClassName/InterfaceName() {
    // Implement or override methods in superclass or interface
    // Other methods if necessary
}
1
2
3
4

由于匿名内部类是一种特殊类型的内部类,它被当作一个内部类对待,但同时具有以下特征:

  • — 个匿名内部类必须总是从一个父类继承或者实现一个接口,但是它不能有显式的 extends 或者 implements 子句
  • 一个匿名内部类必须实现父类或者接口中的所有抽象方法。
  • — 个匿名内部类总是使用它父类的无参构造方法来创建一个实例。如果一个匿名内部类实现一个接口,构造方法是 Object()。
  • 一个匿名内部类被编译成一个名为 OuterClassName$n.class 的类,n 是数字,从 1 开始命名并递增。如果有多个匿名类,Java 编译器会将每个匿名类依次命名为 Outer$1、Outer$2、Outer$3……

使用匿名内部类,可以更加简化代码。

例如,下面定义了一个内部类:

public class LearnInnerClass2 {
  public static void main(String[] args) {
    new Outer("PeterJXL").sayHello();
  }
}


class Outer{

  private String name;

  public Outer(String name){
    this.name = name;
  }

  public void sayHello(){
    new inner().run();
  }

  class inner implements Runnable{
    @Override
    public void run(){
      System.out.println("Hello, " + Outer.this.name);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

可以被一个匿名内部类所替代,如下所示:

public class LearnInnerClass3 {
  public static void main(String[] args) {
    Outer outer = new Outer("peterjxl");
    outer.sayHello();
  }
}


class Outer{
  private String name;

  Outer(String name){
    this.name = name;
  }

  void sayHello(){
    Runnable r = new Runnable() {
      @Override
      public void run(){
        System.out.println("Hello, " + Outer.this.name);
      }
    };
    new Thread(r).start();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

观察 sayHello() 方法,我们在方法内部实例化了一个 Runnable。Runnable 本身是接口,接口是不能实例化的,所以这里实际上是定义了一个实现了 Runnable 接口的匿名类,并且通过 new 实例化该匿名类,然后转型为 Runnable。

匿名类和 Inner Class 一样,可以访问 Outer Class 的 private 字段和方法。之所以我们要定义匿名类,是因为在这里我们通常不关心类名,比直接定义 Inner Class 可以少写很多代码。

# 小结

Java 的内部类可分为 Inner Class、Anonymous Class 和 Static Nested Class 三种:

  • Inner Class 和 Anonymous Class 本质上是相同的,都必须依附于 Outer Class 的实例,即隐含地持有 Outer.this 实例,并拥有 Outer Class 的 private 访问权限;
  • Static Nested Class 是独立类,但拥有 Outer Class 的 private 访问权限。

# 参考

《Java 语言程序设计 基础篇 原书第 10 版 ,梁勇著》 15.4 和 15.5 小节

内部类 - 廖雪峰的官方网站 (opens new window)

上次更新: 2024/9/30 20:09:39
非访问性修饰符
基本包装类型

← 非访问性修饰符 基本包装类型→

最近更新
01
吐槽一下《僵尸校园》
05-15
02
2025 年 4 月记
04-30
03
山西大同 “订婚强奸案” 将会给整个社会带来的影响有多严重? - 知乎 转载
04-26
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式