一、概述
内部类:将一个类 A 定义在另一个类 B 里面,里面的那个类 A 就称为 内部类,类 B 则称为 外部类。
二、成员内部类
1、概述
成员内部类:定义在 类中方法外 的类。
2、定义格式
定义格式:
class 外部类 {
class 内部类{
}
}
3、访问
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
创建内部类对象格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
Demo:
1 public class Person {
2 private boolean live = true;
3 // 成员内部类
4 class Heart {
5 public void jump() {
6 // 直接访问外部类成员
7 if (live) {
8 System.out.println("心脏在跳动");
9 } else {
10 System.out.println("心脏不跳了");
11 }
12 }
13 }
14 public boolean isLive() {
15 return live;
16 }
17 public void setLive(boolean live) {
18 this.live = live;
19 }
20 }
21
22 // 测试类
23 public static void main(String[] args) {
24 // 创建外部类对象
25 Person p = new Person();
26 // 创建内部类对象,调用内部类方法方式一
27 Heart heart = p.new Heart();
28 // 调用内部类方法
29 heart.jump();
30 // 调用外部类方法
31 p.setLive(false);
32 // 调用内部类方法
33 heart.jump();
34
35 // 调用内部类方法方式二
36 Person.Heart heart = new Person().new Hear();
37 heart.jump();
38 }
39 }
40
41 运行结果:
42 心脏在跳动
43 心脏不跳了
注意:内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的 .class 文件,但是前面冠以外部类的类名和 $ 符号。如:Person$Heart.class
三、局部内部类
1、概述
局部内部类:定义在 类中方法内 的类,就是局部内部类。即只有当前所属的方法才能使用它,出了这个方法外面就不能使用。
2、定义格式
定义格式:
修饰符 class 外部类名称 {
修饰符 返回值类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
// ...
}
}
}
定义一个类的时候,权限修饰符规则:
(1)外部类: public / (default)
(2)成员内部类:public / protected / (default) / private
(3)局部内部类:什么都不能写。
3、扩展
局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。
原因:
(1)new出来的对象在堆内存当中。
(2)局部变量是跟着方法走的,在栈内存当中。
(3)方法运行结束之后,立刻出栈,局部变量就会立刻消失。
(4)但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
四、匿名内部类【重要】
1、概述
匿名内部类:是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。
开发中,最常用到的内部类就是匿名内部类了,以接口为例,当你使用一个接口时,都得做如下几步操作:
(1)定义子类
(2)重写接口中的方法
(3)创建子类对象
(4)调用重写后的方法
而匿名类就可以把以上四步合成一步。
前提:匿名内部类必须继承一个父类或者实现一个父接口
2、格式
定义格式:
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
3、使用方式
以接口为例,匿名内部类的使用。
定义接口:
1 public abstract class FlyAble{
2 public abstract void fly();
3 }
创建匿名内部类,并调用:
1 public class InnerDemo {
2 public static void main(String[] args) {
3 /*
4 1.等号右边:是匿名内部类,定义并创建该接口的子类对象
5 2.等号左边:是多态赋值,接口类型引用指向子类对象
6 */
7 FlyAble f = new FlyAble(){
8 public void fly() {
9 System.out.println("我飞了~~~");
10 }
11 };
12 //调用 fly方法,执行重写后的方法
13 f.fly();
14 }
15 }
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。如下所示
1 public class InnerDemo2 {
2 public static void main(String[] args) {
3 /*
4 1.等号右边:定义并创建该接口的子类对象
5 2.等号左边:是多态,接口类型引用指向子类对象
6 */
7 FlyAble f = new FlyAble(){
8 public void fly() {
9 System.out.println("我飞了~~~");
10 }
11 };
12 // 将f传递给showFly方法中
13 showFly(f);
14 }
15 public static void showFly(FlyAble f) {
16 f.fly();
17 }
18 }
将以上两步,也可以简化为一步:
1 public class InnerDemo3 {
2 public static void main(String[] args) {
3 /*
4 创建匿名内部类,直接传递给showFly(FlyAble f)
5 */
6 showFly( new FlyAble(){
7 public void fly() {
8 System.out.println("我飞了~~~");
9 }
10 });
11 }
12 public static void showFly(FlyAble f) {
13 f.fly();
14 }
15 }