📓
Be a Javaer
  • Introduction
  • 第 1 章 Java编程开发入门
    • 第 1 节 Java开发准备
    • 第 2 节 Java基本概念
    • 第 3 节 Java数据类型划分
    • 第 4 节 Java运算符
    • 第 5 节 Java程序逻辑控制
    • 第 6 节 Java方法的定义及使用
  • 第 2 章 Java面向对象编程
    • 第 1 节 类与对象
    • 第 2 节 深入分析类与对象
    • 第 3 节 数组的定义与使用
    • 第 4 节 String类的基本概念
    • 第 5 节 String类的常用方法
    • 第 6 节 this关键字
    • 第 7 节 引用传递
    • 第 8 节 数据表与简单Java类映射
    • 第 9 节 对象比较
    • 第 10 节 static关键字
    • 第 11 节 代码块
    • 第 12 节 内部类
    • 第 13 节 链表的定义与使用
    • 第 14 节 继承性
    • 第 15 节 覆写
    • 第 16 节 数组操作
    • 第 17 节 辅助概念
      • final关键字
      • 多态性
    • 第 18 节 抽象类的定义及使用
    • 第 19 节 接口的定义及使用
    • 第 20 节 Object类
    • 第 21 节 拓展概念
      • 匿名内部类
      • 包装类
    • 第 22 节 包的定义及使用
    • 第 23 节 访问控制权限
      • 单例设计模式
      • 多例设计模式
    • 第 24 节 异常的捕获及处理
    • 第 25 节 Java5新特性
      • 可变参数
      • foreach循环
      • 静态导入
    • 第 26 节 泛型
    • 第 27 节 枚举
    • 第 28 节 Annotation
    • 第 29 节 Java7新特性
      • AutoCloseable
      • Try-with-resources
    • 第 30 节 Java8新特性
      • 接口定义增强
      • Lambda表达式
      • 方法引用
      • 函数式接口
  • 第 3 章 Java高级编程
    • 第 1 节 Java多线程基础实现
    • 第 2 节 线程常用操作方法
    • 第 3 节 线程的同步与死锁
    • 第 4 节 生产者与消费者
    • 第 5 节 Java基础类库
      • StringBuffer
      • Runtime
      • System
      • finalize
      • Cleaner
      • 对象克隆
    • 第 6 节 数字操作类
      • Math类
      • Random类
      • 大数字操作类
    • 第 7 节 日期处理类
      • Date类
      • 日期格式化
      • Calendar类
    • 第 8 节 比较器
    • 第 9 节 正则表达式
      • 常用的正则标记
      • String类对正则的支持
      • java.util.regex包支持
    • 第 10 节 反射机制
    • 第 11 节 动态代理
    • 第 12 节 反射与Annotation
    • 第 13 节 国际化程序实现
    • 第 14 节 开发支持类库
      • Arrays类
      • UUID类
      • Optional类
      • ThreadLocal类
      • 定时器
      • Base64加密工具
    • 第 15 节 文件操作
    • 第 16 节 字节流与字符流
    • 第 17 节 IO辅助概念
      • 字符编码
      • 内存流
      • 管道流
      • RandomAccessFile
    • 第 18 节 打印流
    • 第 19 节 System类对IO的支持
    • 第 20 节 对象序列化
    • 第 21 节 IO高级应用
      • 缓冲输入流
      • Scanner
    • 第 22 节 网络编程
    • 第 23 节 类集框架
    • 第 24 节 List集合
    • 第 25 节 集合输出
    • 第 26 节 Map集合
    • 第 27 节 Set集合
    • 第 28 节 集合工具类
      • Stack
      • Queue
      • Properties
      • Collections工具类
    • 第 29 节 数据流Stream
    • 第 30 节 JDBC简介
    • 第 31 节 Statement接口
    • 第 32 节 PreparedStatment接口
    • 第 33 节 批处理与事务处理
  • 第 4 章 Oracle数据库基础
    • 第 1 节 Oracle简介
    • 第 2 节 Oracle安装与配置
    • 第 3 节 SQLPlus命令
    • 第 4 节 SQL简介与数据表分析
    • 第 5 节 SQL简单查询
    • 第 6 节 SQL限定查询
    • 第 7 节 查询排序
    • 第 8 节 综合练习:基础查询
    • 第 9 节 单行函数
    • 第 10 节 多表查询
    • 第 11 节 分组统计查询
    • 第 12 节 子查询
    • 第 13 节 综合案例:复杂查询
    • 第 14 节 数据更新操作
    • 第 15 节 事务处理
    • 第 16 节 数据伪列
    • 第 17 节 数据表的创建与管理
    • 第 18 节 约束的创建与管理
    • 第 19 节 综合案例:数据表操作
    • 第 20 节 序列的定义与使用
  • 第 5 章 JavaWeb基础
  • 第 6 章 走向单体地狱
  • 第 7 章 GitFlow工作流指南
    • 版本控制
    • Git
    • 集中式工作流
    • 功能分支工作流
    • GitFlow 工作流
    • Forking 工作流
    • Pull Requests
  • 第 8 章 微服务入门
    • 第 1 节 微服务简介
    • 第 2 节 Linux
    • 第 3 节 Docker
    • Docker 仓库
    • Ubuntu 安装 Docker
    • Docker 镜像加速器
    • 第 4 节 Docker Compose
    • 第 5 节 GitLab
    • 第 6 节 Nexus
    • 第 7 节 Harbor
  • 第 9 章 再谈微服务
  • 第 10 章 Spring Boot
  • 第 11 章 Spring Cloud Netflix
  • 第 12 章 Apache Dubbo Zookeeper
  • 第 13 章 Spring Cloud Alibaba
  • 第 14 章 Vue
  • 第 15 章 Kubernetes
  • 第 16 章 Spring Security oAuth2
  • 第 17 章 Flutter
  • Redis
    • Redis 入门
    • Redis 的数据类型
    • Redis 事务
    • Jedis
    • Spring Boot 整合 Redis
    • Redis 配置文件
    • Redis 持久化
    • Redis 发布/订阅
    • Redis 主从复制
    • Redis Sentinel
    • Redis 缓存故障
  • Glossary
由 GitBook 提供支持
在本页
  • 基本概念
  • 使用static定义内部类
  • 在方法中定义内部类
  • 总结

这有帮助吗?

  1. 第 2 章 Java面向对象编程

第 12 节 内部类


内部类的基本定义结构

  • 使用static定义内部类

  • 在方法中定义内部类

从开发的角度,内部类能少用就少用。优先考虑的还是普通类。

基本概念

所谓的内部类指的就是在一个类的内部继续定义了其他内部结构类的情况。

范例: 观察内部类的基本形式

class Outer { // 外部类
	private String msg = "Hello World !";
	class Inner { // 定义了一个内部类
		public void print() {
			System.out.println(msg);
		}
	}
	public void fun() {
		// 实例化内部类对象,并且调用print()方法
		new Inner().print();
	}
}
public class MainClass {
	public static void main(String[] args) {
		Outer out = new Outer(); // 实例化外部类对象
		out.fun(); // 调用外部类方法
	}
}

以上类的代码并不麻烦,但是从结构上讲是存在问题的,因为从类的结构本身就意味着属性与方法的组成,可是一个类里面又定义了另外一个类。这个时候内部类牺牲了类的结构,可是它实现了一个很重要的目的。

为了观察内部类达到的目的,下面将之前的内部类拿到外面来,并且要求实现与之完全一样的功能。

范例: 将内部类取出

class Outer { // 外部类
	private String msg = "Hello World !";
	public void fun() {
		// 实例化内部类对象,并且调用print()方法
		new Inner().print();
	}
}
class Inner { // 定义了一个内部类
	public void print() {
		System.out.println(msg);
	}
}
public class MainClass {
	public static void main(String[] args) {
		Outer out = new Outer(); // 实例化外部类对象
		out.fun(); // 调用外部类方法
	}
}

1、内部类需要访问msg属性,但是此属性属于Outer类中的,而在Outer类里面此属性使用private进行封装,所以此时如果要得到这个属性的内容,需要定义一个getter方法。

public String getMsg() {
	return this.msg;
}

2、此时Outer类的getMsg()是一个普通方法,那么所有类中的普通方法必须要通过类的实例化对象进行调用。

此时可以创建一个新的Outer对象,但是这并不满足之前所规定的条件,那么现在最好的做法是将主方法之中的Outer类对象传递给Inner类。

class Outer { // 外部类
	private String msg = "Hello World !";
	public String getMsg() {
		return this.msg;
	}
	public void fun() {
		// 实例化内部类对象,并且调用print()方法
		new Inner(this).print();
	}
}
class Inner { // 定义了一个内部类
	private Outer out;
	public Inner(Outer out) {
		this.out = out;
	}
	public void print() {
		System.out.println(this.out.getMsg());
	}
}
public class MainClass { 
	public static void main(String[] args) {
		Outer out = new Outer(); // 实例化外部类对象
		out.fun(); // 调用外部类方法
	}
}

实际上以上代码的最终目的只有一个:让内部类可以访问外部类中定义的一个私有的msg属性内容。

内部类有一个最大的优点:可以方便的访问外部类的私有属性。

但是需要注意的是内部类可以方便的访问外部类的私有属性,同样,外部类也可以通过内部类对象访问内部类的私有属性。

范例: 访问内部类的私有属性

class Outer { // 外部类
	private String msg = "Hello World !";
	class Inner { // 定义了一个内部类
		private String info = "你好,世界!";
		public void print() {
			System.out.println(msg);
		}
	}
	public void fun() {
		Inner in  = new Inner(); // 内部类对象
		// 直接利用内部类对象访问内部类定义的私有属性
		System.out.println(in.info);
	}
}
public class MainClass {
	public static void main(String[] args) {
		Outer out = new Outer(); // 实例化外部类对象
		out.fun(); // 调用外部类方法
	}
}

一旦使用了内部类之后,私有属性的访问就变得非常简单了。

在之前的案例里一直要求访问类属性的时候一定要在前面加上this,但是如果直接在pring()方法里面加上this表示的是查找本类的属性,但是此时要访问的实际上是我外部类的属性,那么应该使用“外部类.this”。

class Outer { // 外部类
	private String msg = "Hello World !";
	class Inner { // 定义了一个内部类
		public void print() {
			// 外部类.this = 外部类的当前对象
			System.out.println(Outer.this.msg);
		}
	}
	public void fun() {
		new Inner().print();
	}
}
public class MainClass {
	public static void main(String[] args) {
		Outer out = new Outer(); // 实例化外部类对象
		out.fun(); // 调用外部类方法
	}
}

以上的所有代码都有一个特点:通过外部类的一个fun()方法访问内部类的操作。内部类能不能像普通对象那样直接在外部产生实例化对象调用?

要想解决这个问题,那么就要通过内部类编译后生成的文件形式来观察。发现内部类的class文件的形式是:Outer$Inner.class。所有的“$”是在文件中的命名,如果换回到了程序里面就变为了“.”,也就是说内部类的名称就是“外部类.内部类”。此时可以给出内部类对象的实例化语法:

外部类.内部类 内部类对象 = new 外部类().new 内部类();

范例: 实例化内部类对象

class Outer { // 外部类
	private String msg = "Hello World !";
	class Inner { // 定义了一个内部类
		public void print() {
			// 外部类.this = 外部类的当前对象
			System.out.println(Outer.this.msg);
		}
	}
}
public class MainClass {
	public static void main(String[] args) {
		Outer.Inner in = new Outer().new Inner();
		in.print();
	}
}

内部类不可能离开外部类的实例化对象,所以一定要先实例化外部类对象之后才可以使用内部类对象。如果真的使用到了内部类,也基本上不会像以上的操作那样进行的。一定是通过外部类进行访问内部类。

如果现在一个内部类只希望被一个外部类访问,不能够被外部调用,那么可以使用private进行定义。

class Outer { // 外部类
	private String msg = "Hello World !";
	private class Inner { // 定义了一个内部类
		public void print() {
			// 外部类.this = 外部类的当前对象
			System.out.println(Outer.this.msg);
		}
	}
}

此时的内部类是不可能在外部进行对象实例化的。

使用static定义内部类

使用static定义的属性或者是方法是不受到类实例化对象控制的,所以如果使用了static定义内部类,它就不会再受到外部类的实例化对象控制。

如果一个内部类使用了static定义的话,那么这个内部类就变为了一个外部类,并且只能够访问外部类中定义的static操作。相当于定义了一个外部类。

class Outer { // 外部类
	private static String msg = "Hello World !";
	static class Inner {
		public void print() {
			System.out.println(msg);
		} 
	} 
}

此时如果想要取得内部类的实例化对象,使用的语法如下:

外部类.内部类 内部类对象 = new 外部类.内部类();

此时不再需要先产生外部类对象,再产生内部类对象,仿佛就变为了一个独立的类。

class Outer { // 外部类
	private static String msg = "Hello World !";
	static class Inner {
		public void print() {
			System.out.println(msg);
		} 
	} 
}
public class MainClass {
	public static void main(String[] args) {
		Outer.Inner in = new Outer.Inner();
		in.print();
	}
}

如果以后看到了可以直接实例化“类.类.类”的时候一定要知道,这是一个使用了static的内部类。

在方法中定义内部类

内部类可以在任意的位置上定义,包括:类中、代码块里、方法里面,其中方法中定义内部类是比较常见的形式,如果后期要使用也会使用此类形式。

范例: 在方法里面定义内部类

class Outer { // 外部类
	private String msg = "Hello World !";
	public void fun() {
		class Inner { // 方法中定义的内部类
			public void print() {
				System.out.println(Outer.this.msg);
			}
		}
		new Inner().print();
	}
}
public class MainClass {
	public static void main(String[] args) {
		new Outer().fun();
	}
}

但是方法里面会接收参数,方法里面也会定义变量。

范例: 访问方法中定义的参数或者是变量

class Outer { // 外部类
	private String msg = "Hello World !";
	public void fun(int num) { // 方法参数
		double score = 99.9; // 方法变量
		class Inner { // 方法中定义的内部类
			public void print() {
				System.out.println("属性:" + Outer.this.msg);
				System.out.println("方法参数:" + num);
				System.out.println("方法变量:" + score);
			}
		}
		new Inner().print();
	}
}
public class MainClass {
	public static void main(String[] args) {
		new Outer().fun(100);
	}
} 

此时发现没有加入任何修饰,方法中的内部类可以访问方法的参数以及定义的变量。但是这种操作只适合于JDK1.8之后的版本。如果在JDK1.7以及之前的版本有一个严格的要求:方法中定义的内部类如果想要访问方法的参数或者是方法定义的变量,那么参数或变量前一定要加上“final”标记。

范例: 正规代码

class Outer { // 外部类
	private String msg = "Hello World !";
	public void fun(final int num) { // 方法参数
		final double score = 99.9; // 方法变量
		class Inner { // 方法中定义的内部类
			public void print() {
				System.out.println("属性:" + Outer.this.msg);
				System.out.println("方法参数:" + num);
				System.out.println("方法变量:" + score);
			}
		}
		new Inner().print();
	}
}

总结

1、内部类只是阐述了基本定义形式,但是没有讲解如何去使用;

2、内部类可以与外部类之间方便的进行私有属性的访问;

3、内部类可以使用private声明,声明之后无法在外部实例化内部类对象;

  • 语法:外部类.内部类 内部类对象 = new 外部类().new 内部类();

4、使用static定义的内部类就相当于是一个外部类;

  • 语法:外部类.内部类 内部类对象 = new 外部类.内部类();

5、内部类可以在方法中定义。

上一页第 11 节 代码块下一页第 13 节 链表的定义与使用

最后更新于5年前

这有帮助吗?