Java的匿名内部类(重要)
说明:
匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
解读:
(1)匿名内部类的本质是类 (2)它是一个内部类 (3)该类没有名字 (4)它同时还是一个对象
1.匿名内部类的基本语法:
new 类或接口(参数列表){
类体
};
引出:
package com.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类只使用一次,以后再也不使用了//4.解决方案:使用匿名内部类简化开发Tiger tiger = new Tiger();tiger.cry();}
}
interface IA{ //接口public void cry();
}
class Father{public Father(String name) { //构造器}public void test(){ //方法}
}
class Tiger implements IA{@Overridepublic void cry() {System.out.println("老虎叫.....");}
}
基于接口的匿名内部类的使用:
package com.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类只使用一次,以后再也不使用了//4.解决方案:使用匿名内部类简化开发//5.tiger的编译类型是IA//6.tiger的运行类型就是匿名内部类//如果Father是抽象类,则必须实现抽象类中的方法/*此时的匿名内部类 看底层:class Outer04$1 implements IA{ //匿名内部类的名称 = 外部类名称 + $1,也就是Outer04$1@Overridepublic void cry() {System.out.println("老虎叫唤.....");}}*///7.jdk底层在创建匿名内部类Outer04$1,立即马上就创建了Outer04$1的实例,并且把地址返回给tiger//8.匿名内部类使用一次,就不能再使用IA tiger = new IA(){@Overridepublic void cry() {System.out.println("老虎叫唤.....");}};tiger.cry();System.out.println("tiger的运行类型是" + tiger.getClass());}
}
interface IA{ //接口public void cry();
}
class Father{public Father(String name) { //构造器}public void test(){ //方法}
}
基于类的匿名内部类的使用:
class Outer04{ //外部类private int n1 = 10;public void method(){ //方法//演示基于类的匿名内部类://father的编译类型是Father//father的运行类型 是匿名内部类 Outer04$2//底层会创建匿名内部类/*class Outer04$2 extends Father{@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}}*///同时也直接返回了匿名内部类Outer04$2的对象//注意("jack")会传递给Father的构造器Father father = new Father("jack") {@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}};System.out.println("father对象的运行类型是" + father.getClass());father.test();}
}
class Father{public Father(String name) { //构造器}public void test(){ //方法}
}
我的理解:
就是先创建一个子类对象,然后jvm创建一个匿名内部类,将这个匿名内部类的匿名对象赋给最先创建的子类对象,而这个匿名内部类的创建过程只有一次,子类对象可以无数次使用
匿名内部类的使用:
匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法有下面两种:
package com.innerclass;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 person = new Person(){@Overridepublic void hi() {System.out.println("匿名内部类重写了hi()");}};person.hi();//动态绑定,它的编译类型是Person,运行类型是Outer05$1//调用方式第二种:创建匿名对象直接调用//匿名内部类本身也是返回对象new Person(){@Overridepublic void hi() {System.out.println("匿名内部类重写了hi()...................");}@Overridepublic void ok(String str) {super.ok(str);}}.ok("jack");}
}
class Person{public void hi(){System.out.println("Person中的hi()");}public void ok(String str){System.out.println("Person中的ok()" + str);}
}
//抽象类/接口...都可以写
1.可以直接访问外部类的所有成员,包括私有的
2.不能添加访问修饰符,因为它的低位就是一个局部变量
3.作用域:仅仅在定义它的方法或代码中
4.匿名内部类---访问--->外部类成员[访问方式:直接访问]
5.外部其他类--不能访问-->匿名内部类(因为 匿名内部类地位是一个局部变量)
6.如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
匿名内部类的最佳实践:
当作实参直接传递,简洁高效
package com.innerclass;public class InnerClassExercise01 {public static void main(String[] args) {//匿名内部类可以当作实参直接传递,简洁高效f1(new IL(){@Overridepublic void show() {System.out.println("这是一副名画");}});}//静态方法,形参是接口类型public static void f1(IL il){il.show();}
}
//接口
interface IL{public void show();
}
练习
package com.innerclass;public class InnerClassExercise02 {public static void main(String[] args) {Cellphone cellphone = new Cellphone();cellphone.alarmClock(new Bell(){@Overridepublic void ring() {System.out.println("懒猪起床了");}});cellphone.alarmClock(new Bell() {@Overridepublic void ring() {System.out.println("小伙伴们上课了");}});}
}
//有一个铃声接口Bell,里面有个ring方法.
//有一个手机类Cellphone,具有闹钟功能 alarmClock 参数是Bell类型
//测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起来了
//再传入另一个匿名内部类(对象),打印:小伙伴上课了
interface Bell{void ring();
}
class Cellphone{public void alarmClock(Bell bell){ //形参是接口类型bell.ring();}
}