【JavaSE】匿名内部类
1. 匿名内部类的使用
(1)本质是类
(2)内部类
(3)该类没有名字(名字不是能直接看到的,实际上是系统取的)
(4)同时还是一个对象
- 说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
- 匿名内部类的基本语法
new 类或接口(参数列表) {
类体
}
- 传统方法实现 ,写一个类,实现该接口,并创建对象
public class AnonymouseInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 {//外部类
private int n1 = 10;
public void method() {
//基于接口的匿名内部类
//解读:
//1.需求:使用IA接口,并创建对象
//2.传统方式,写一个类,实现该接口,并创建对象
IA tiger = new Tiger();
tiger.cry();
}
}
interface IA {//接口
public void cry();
}
class Tiger implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
class Father {
public Father(String name) {
}
public void test() {
}
}
-
如果
Tiger
这个对象只用一次,后面不再使用了,如果再定义一个Dog
类,而且也只用一次,这种情况下就会定义很多类,这种情况有可能很多只用一次的情况,创建对象浪费资源 -
解决方案:这个时候就可以使用 匿名内部类 来简化开发
-
需求:既不去创建
Tiger
对象,又能去调用Tiger
类中的方法 -
接口是不能直接
new
的,但是后面重写的方法相当于在Tiger
类中重写的方法
-
匿名内部类实现
public class AnonymouseInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 {//外部类
private int n1 = 10;
public void method() {
//1.可以使用匿名内部类来开发
//2.tiger的编译类型是 IA
//3.tiger的运行类型是 匿名内部类
/*
* 看底层 类名
* class XXX implements IA {
* @Override
public void cry() {
System.out.println("老虎叫唤...");
}
* }
* XXX = Outer04$1
*
* 系统会分配 类名 Outer04$1
*
*/
// 4. jdk底层在创建匿名内部类 Outer04$1 ,马上就创建了 Outer04$1 实例,并且把地址返回给 tiger
// 5. 匿名内部类使用一次,就不能再使用了
IA tiger = new IA(){
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
tiger.cry();
System.out.println("tiger运行类型=" + tiger.getClass());
}
}
interface IA {//接口
public void cry();
}
- 可以看到使用匿名内部类也能达到同样的效果,并且不会创建该类,而是以匿名的方式创建的
- 可以看底层系统给匿名内部类分配的类名,jdk底层在创建匿名内部类
Outer04$1
,马上就创建了Outer04$1
实例,并且把地址返回给tiger
,匿名内部类使用一次,就不能再使用了。但是 tiger 对象可以使用。
class XXX implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
XXX 类名 = Outer04$1
就是等于在外部类的基础上 加上 $1
- 查看匿名内部类分配的名字
class XXX implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
System.out.println("tiger运行类型=" + tiger.getClass());
- 由上述可知,
XXX
类名为Outer04$1
,是系统分配的类名。jdk底层在创建匿名内部类 Outer04$1 ,马上就创建了Outer04$1
实例,并且把地址返回给tiger
- 上面是基于接口的匿名内部类实现。
案例演示:基于类的匿名内部类的实现
//分析
//1.father编译类型 Father
//2.father运行类型 Outer04$2
//3.底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了test()");
}
}
*/
//4,同时也直接返回了 匿名内部类 Outer04$2 的对象
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test()");
}
};
System.out.println("father运行类型=" + father.getClass());
father.test();
class Father {
public Father(String name) {
}
public void test() {
}
}
-
也可以直接查看的到匿名内部类的类名
-
基于抽象类的匿名内部类,编译类型是
Animal
,运行类型是匿名内部类
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
//查看系统分配给匿名内部类的 类名
abstract class Animal {
abstract void eat();
}
2. 匿名内部类发注意事项
- 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
}
}
class Outer05 {
private int n1 = 99;
public void f1() {
//创建一个基于类的匿名内部类
Person person = new Person(){
@Override
public void hi() {
System.out.println("匿名内部类重写了 hi 方法");
}
};
person.hi(); //动态绑定,运行类型是 Outer05$1
//也可以直接调用, 匿名内部类本身也是返回对象
// class 匿名内部类 extends Person{}
new Person(){
@Override
public void hi() {
System.out.println("匿名内部类重写了 hi 方法,1111");
}
@Override
public void ok(String str) {
super.ok(str);
}
}.ok("xdr");
}
}
class Person {
public void hi() {
System.out.println("Person hi()");
}
public void ok(String str) {
System.out.println("Person ok()" + str);
}
}
- 可以直接访问外部类的所有成员,包含私有的
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
}
}
class Outer05 {
private int n1 = 99;
public void f1() {
//创建一个基于类的匿名内部类
Person person = new Person(){
@Override
public void hi() {
//可以直接访问外部类的所有成员,包含私有的
System.out.println("匿名内部类重写了 hi 方法 n1=" + n1);
}
};
person.hi(); //动态绑定,运行类型是 Outer05$1
class Person {
public void hi() {
System.out.println("Person hi()");
}
}
-
不能添加访问修饰符,因为它的地位就是一个局部变量。
-
作用域:仅仅在定义它的方法或代码块中。
-
匿名内部类——>访问——>外部类成员【访问方式:直接访问】
-
外部其他类——不能访问——>匿名内部类【因为匿名内部类地位是一个局部变量】
-
如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则如果想访问外部类的成员,则可以使用【
外部类名.this.成员
】去访问
-
如果想访问同名外部类的话,可以使用 【
外部类名.this.成员
】去访问
-
上面的
Outer05.this
就是调用f1
的对象,谁调用f1
对象,这个Outer05.this
就是谁 -
可以看到都是同一个对象,所以对象外部类去访问 n1 ,指的就是外部类的属性
3. 匿名内部类的最佳实践
- 当做实参直接传递,简洁高效。
- 传统方法实现
public class InnerClassExercise01 {
public static void main(String[] args) {
//传统方法
f1(new Picture());
}
//静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
//类->实现IL => 编程领域 (硬编码)
class Picture implements IL {
@Override
public void show() {
System.out.println("这是一副名画...");
}
}
- 匿名内部类实现
public class InnerClassExercise01 {
public static void main(String[] args) {
//当做实参直接传递,简洁高效
f1(new IL() {
@Override
public void show() {
System.out.println("这是一副名画~~...");
}
});
}
//静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
//接口
interface IL {
void show();
}
- 案例2
1.有一个铃声接口Bell,里面有个ring方法。(右图)
2. 有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型(如下图)
3. 测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4. 再传入另一个匿名内部类(对象),打印:小伙伴上课了
- 思路:匿名内部 (1) 继承 (2) 多态 (3) 动态绑定 (4) 内部类
public class InnerClassExercise02 {
public static void main(String[] args) {
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();//动态绑定
}
}
- 点赞
- 收藏
- 关注作者
评论(0)