【从零开始学Java | 第十四篇】内部类
目录
前言
一、什么是内部类?
二、内部类的分类
三、成员内部类
1、成员内部类如何书写?
2、如何创建成员内部类的对象?
3、成员内部类如何获取外部类的成员变量
四、静态内部类
五、匿名内部类
总结
前言
在前面的学习中,我们写的类都是并列存在的,但有时候,我们会遇到一种特殊情况:一个类只为另一个类服务,完全没有必要暴露给外部世界。比如人(Person)和心脏(Heart),心脏离开人体单独存在是没有意义的。 为了解决这种问题,Java 允许我们在一个类的内部定义另一个类——这就是内部类(Inner Class)。
一、什么是内部类?
定义:将一个类 A 定义在另一个类 B 的里面,A 就叫内部类,B 就叫外部类。
- 内部类表示的事物是外部类的一部分
- 内部类单独出现没有任何意义
内部类的访问特点:
- 内部类可以直接访问外部类的成员,包括私有的。
- 外部类若要访问内部类的成员,必须创建一个内部类的对象。
示例1:内部类可以直接方位外部类的成员,包括私有。
示例2:外部类若要访问内部类的成员,必须创建一个内部类的对象。
二、内部类的分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
其中成员内部类、静态内部类、局部内部类仅仅了解即可,最重要的还是匿名内部类。
三、成员内部类
写在成员位置的,属于外部类的成员。
1、成员内部类如何书写?
- 成员内部类可以被一些修饰符所修饰,比如:private、缺省、protected、public、static等。
- 在成员内部类里,JDK16之前不能定义静态变量 ,JDK16之后才可以定义静态变量。
public class Car { private String carName; String carColor; int carAge; class Enginee{ String engineeName; int engineeAge; } }2、如何创建成员内部类的对象?
方式一:在外部类中编写方法,对外提供内部类的对象。
方式二:直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
方式一:
在外部类中定义一个getInstance()方法,返回一个内部类对象。
public class Outer { String name; private class Inner{ } public Inner getInstance(){ return new Inner(); } }利用多态来接收
public class Test { public static void main(String[] args) { // Outer.Inner oi = new Outer().new Inner(); Outer o = new Outer(); Object inner = o.getInstance(); } }方式二:
public class Outer { String name; class Inner{ } }public class Test { public static void main(String[] args) { Outer.Inner oi = new Outer().new Inner(); } }3、成员内部类如何获取外部类的成员变量
使用Outer.this.变量名来调用外部类的成员变量。
public class Outer { private int a = 10; class Inner{ private int a = 20; public void show(){ int a = 30; System.out.println(a); System.out.println(this.a); System.out.println(Outer.this.a); } } }四、静态内部类
在内部类前面加上static。它不再依赖外部类的对象,就像一个独立存在的类,只是恰好借住在外部类的壳子里。
限制:因为是静态的,所以它不能访问外部类的非静态变量。
实例化:Outer.Inner oi = new Outer.Inner();
五、匿名内部类
上一篇我们学了接口。如果我想用一个接口,标准流程是:写个类实现接口 -> 重写方法 -> new 这个实现类。但如果这个实现类我这辈子只用一次,专门为它建个.java文件是不是太浪费了?
匿名内部类它允许我们在实现接口(或继承父类)的同时,直接创建出一个没有名字的对象。
匿名内部类本质上就是隐藏了名字的内部类。
格式:
new 类名或接口名(){
重写方法;
};
包含了实现/继承关系、方法的重写、创建对象。
//Swim接口 public interface Swim { void Swimming(); } //Aminal类 public abstract class Animal { public abstract void eat(); }匿名内部类的实现:
public class Test { public static void main(String[] args) { new Swim(){ @Override public void Swimming() { System.out.println("重写了Swim接口中的Swimming方法"); } }; new Animal(){ @Override public void eat() { System.out.println("重写了Animal类中的eat方法"); } }; } }匿名内部类的使用:主要看method()方法的调用
public class Test { public static void main(String[] args) { new Swim(){ @Override public void Swimming() { System.out.println("重写了Swim接口中的Swimming方法"); } }; new Animal(){ @Override public void eat() { System.out.println("重写了Animal类中的eat方法"); } }; method( new Animal() { @Override public void eat() { System.out.println("狗在吃骨头"); } } ); } public static void method(Animal a){ a.eat(); } }总结
- 内部类的优势:可以无条件访问外部类的私有成员。
- 成员内部类依赖外部类对象(
outer.new Inner()),静态内部类不依赖(new Outer.Inner())。 - 匿名内部类可以简化代码,省略哪些只用一次的接口或类。
