1-匿名内部类入门

匿名内部类

综合性强:1继承 2 多态 3 动态绑定 4内部类

what?

  1. 本质还是类
  2. 属于内部类
  3. 该类没有名字
  4. ==同时还是一个对象== —-> 在创建过程中使用了 new xxx()。类似创建对象的方法

位置:外部类的==局部位置==,比如方法中。

why?

一个需求:

//1.如果想使用 IA 接口。

2.传统方式 :创建一个 class 实现这个接口,然后再创建对象。

3.使用匿名内部类 直接 IA ia = new IA(){

} 就完成了一个 实现了接口的类的对象实例。

老韩的需求是 Tiger/Dog 类只是使用一次,后面不再使用。

–>.使用匿名内部类来简化 开发

How?

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
new 类或接口(参数列表){
类体。
}

package com.hspedu.innerclass;
/**
* 演示匿名内部类的使用
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类
//老韩解读
//1.需求: 想使用 IA 接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger 的编译类型 ? IA
//6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
/*
我们看底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
//7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
// 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用
演示基于接口的匿名内部类。
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
System.out.println("tiger 的运行类型=" + tiger.getClass());
tiger.cry();
tiger.cry();
tiger.cry();
// IA tiger = new Tiger();
// tiger.cry();

演示基于类的匿名内部类
//分析
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
//5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
};
System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
father.test();


基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//类
public Father(String name) {//构造器
System.out.println("接收到 name=" + name);
}
public void test() {//方法
}
}
abstract class Animal { //抽象类
abstract void eat();
}

一、接口的匿名内部类使用

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
27
28
29
30
public class AnnoymouslnnerClass {
public static void main(String[] args) {
tiger tiger = new tiger();
tiger.cry();
//使用匿名内部类实现
// 底层 会分配类名
/*class outerName+$1 implements IA{
* @Override
* public void cry() {
* System.out.println("tigger");
* }
*}
*
*
* 7 dk 底层在创建了 匿名内部类立即马上就创建了它的实例,并且把地址返回。
* 8.匿名内部类使用一次就没有了,不能再使用, ---但是匿名内部类的对象还可以使用
* 就没有了 不能使用 new outerclass$1这个方法再来调用
* */
IA tigger=new IA() {
@Override
public void cry() {
System.out.println("tigger");
}
};
tigger.cry();
//验证
// getclass 获取运行类型
System.out.println("tigger的运行类型"+tigger.getClass());
}
}

二、类的匿名内部类。

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
27
28
29
30
31
32
33
34
35
36
 基于类的匿名内部类
//1.father --编译类型
//2.编译类型 outerClass$2 --> extend father
//这个类只能使用一次,且是 继承了father的
//m
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
//5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("hello") {
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
};

基于抽闲类的匿名内部类
Animal animal = new Animal() {
//必须实现抽象方法
@Override
void eat() {

}
};

abstract class Animal{
abstract void eat();
}

二、匿名内部类的细节。

  1. 匿名内部类是一个对象。—> 创建的过程中也有 new xx的操作。
    1. 创建的内部类 为 ==extend 了该类的 一个子类==。
    2. 使用的过程中遵循多态的特点。

image-20221114214357388

  1. 可以访问外部类的所有成员。包括私有的

  2. 不能==添加访问修饰符==,它的堤围就是一个局部变量。

  3. 作用域:仅仅在定义它的方法或代码块中,且只能使用一次。—> 即 new 的那个操作。

  4. 如果外部内的成员和匿名内部类的成员重名时,匿名内部类遵循==就近原则==,如果想访问外部类的成员,则可以使用==(外部类名.this.成员)==

    外部类名.this 就是调用 ==匿名内部类所在方法==的 对象。

三、案例

1)接口参数

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
27
28
29
30
31
32
33
34
做实参直接传递,简洁高效。 InnerClassExercise01.java
package com.hspedu.innerclass;
import com.hspedu.abstract_.AA;
public class InnerClassExercise01 {
public static void main(String[] args) {
//当做实参直接传递,简洁高效
f1(new IL() {
@Override
public void show() {
System.out.println("这是一副名画~~...");
}
});
//传统方法需要先创建一个实现该接口的类,然后再使用 new创建对象。
f1(new Picture());
}
//静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
//接口
interface IL {
void show();
}


类->实现 IL => 编程领域 (硬编码)
class Picture implements IL {
@Override
public void show() {
System.out.println("这是一副名画 XX...");
}
}

2)类image-20221114222036530

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.hspedu.innerclass;
public class InnerClassExercise02 {
public static void main(String[] args) {
/*
1.有一个铃声接口 Bell,里面有个 ring 方法。(右图)
2.有一个手机类 Cellphone,具有闹钟功能 alarmClock,参数是 Bell 类型(右图)
3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4.再传入另一个匿名内部类(对象),打印:小伙伴上课了
*/
CellPhone cellPhone = new CellPhone();
//老韩解读
//1. 传递的是实现了 Bell 接口的匿名内部类 InnerClassExercise02$1
//2. 重写了 ring
//3. Bell bell = new Bell() {
// @Override
// public void ring() {
// System.out.println("懒猪起床了");
// }
// }
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{ //接口
void ring();//方法
}
class CellPhone{//类
public void alarmClock(Bell bell){//形参是 Bell 接口类型
System.out.println(bell.getClass());
bell.ring();//动态绑定
}
}