匿名内部类之白话文版
匿名内部类对于很多刚入门的新手来说,都是一个很难跨越的坎,不是说这东西有多难,主要是这东西太饶,那么我们如何才能征服这小妖精呢?其实最重要的是搞懂三个明确:1.匿名内部类是存在在外部内的成员方法内的,换句话说匿名内部类它首先得是一个局部内部类;2.匿名内部类必须实现一个接口或继承一个类 3.第三个明确是在第二个明确基础上的,就是匿名内部类它实质也就是它继承的类或者实现接口的匿名子类对象,注意注意,它本质是一个子类对象!!
其实看代码会觉得匿名内部类的格式很复杂,各种花括号小括号分号缠绕在一块,如果用文字表达,看上去就清晰很多了:
new 父类(或接口){ 子类内容 }。
根据上面的解释,好像对于匿名内部类有一点点了解了,那么我们就去试一下。
要有匿名内部类,我们首先得创建一个接口或类:
1 abstract class AbsClass{ 2 public abstract void show(); 3 public void method(){ 4 System.out.println("我是抽象类的method"); 5 } 6 }
然后我们创建一个外部类,在外部类的成员方法内定义匿名内部类(就是之前提到的三个明确之一,匿名内部类首先得是一个局部内部类):
1 class Outer{ 2 public void method(){ 3 System.out.println("我是外部类的method"); 4 new AbsClass() {//new出来的这整个代码块,其实就代表匿名内部类,实际上也就是父类或接口的子类对象。所以,我们可以当然可以在new代码块之后用.方法名来调用本类方法 5 public void show() { 6 System.out.println("我是内部类的show"); 7 } 8 }.show(); 9 //当然我们也可以创建一个父类或接口引用指向这个匿名内部类(也就是匿名子类对象),然后用变量名来调用方法,这是比较常用的 10 AbsClass abs1=new AbsClass() { 11 public void show() { 12 System.out.println("我是通过变量名调用的内部类的show"); 13 } 14 }; 15 abs1.show(); 16 } 17 }
创建测试类对其进行测试:
1 public class 匿名内部类Test01 { 2 public static void main(String[] args) { 3 new Outer().method(); 4 } 5 }
其实现在要理解起来就会轻松很多,我要使用匿名内部类,其实就是创建某个类或者接口的子类对象而已,只不过这个子类对象稍微特殊一点,它匿名罢了。那么匿名内部类到底会在哪些地方被应用到呢?
当方法参数是接口或抽象类类型时,可以使用匿名内部类作为实际参数作为传递,这也是动态代理的主要操作。
下面用代码来进行分析:
首先定义一个类或接口
1 interface Inter{ 2 void show1(); 3 void show2(); 4 }
然后创建外部类,在外部类的成员方法内创建匿名内部类:
1 public class 匿名内部类Test02 { 2 public static void show(Inter in){ 3 //当一个方法定义时的形参是一个引用类型,那么它实际上是需要这个类或//者其子类或实现的对象,这个我们应该很清楚 4 in.show1(); 5 in.show2(); 6 } 7 public static void main(String[] args) { 8 /* 当我们以前看到这个show()方法参数是一个引用类型数据时,都是会去创建他的对象作为实际参数传递 9 * 如果是接口或者抽象类,我们就创建其子类对象作为实参进行传递, 10 * 但现在我们知道了匿名内部类的实质,也就是父类或接口的匿名子类对象,我们就可以将匿名内部类作为参数传递了,因为他实际上也是对象啊 11 * 我们只是需要在传递过程中完成对其父类抽象方法的重写即可 12 */ 13 show(new Inter() { 14 @Override 15 public void show2() { 16 System.out.println("我是匿名内部类的show1"); 17 } 18 @Override 19 public void show1() { 20 System.out.println("我是匿名内部类的show2"); 21 } 22 }); 23 } 24 }
我们现在都知道匿名内部类有两种调用自己内部方法的形式了,一种是用匿名对象调用,也就是在new代码块后面直接.方法名;另一种则是通过父类引用来调用方法,那么他们到底有什么区别呢?
1 public class 匿名对象类Demo03 { 2 public static void main(String[] args) { 3 new Outer03().method(); 4 } 5 } 6 interface Inter03{ 7 void show1(); 8 void show2(); 9 } 10 class Outer03{ 11 public void method(){ 12 new Inter03() { 13 @Override 14 public void show2() { 15 System.out.println("show1"); 16 } 17 @Override 18 public void show1() { 19 System.out.println("show2"); 20 } 21 public void show3(){ 22 System.out.println("我不是重写父类方法,我是自己的方法show3"); 23 } 24 }.show3();//这样子我是能调用我自己的方法show()3的,此时我又想调用里面的多个方法,所以我就想到了通过父类引用来给这个子类对象赋变量名,于是... 25 Inter03 inter03=new Inter03() { 26 @Override 27 public void show2() { 28 System.out.println("show1"); 29 } 30 @Override 31 public void show1() { 32 System.out.println("show2"); 33 } 34 public void show3(){ 35 System.out.println("我不是重写父类方法,我是自己的方法show3"); 36 } 37 }; 38 //inter03.show3();于是,我们很明显看到这里报错了,为什么呢? 39 //因为我们这里用父类引用指向子类对象,也就形成了多态,而多态中成员方法是完全按照父类中的执行的,不能执行子类特有方法,所以就报错了 40 //那么为什么上面通过匿名内部类直接调用自己特有方法就可以呢?因为他本质是一个对象,当没有父类引用指向它时,它当然可以调用自己本身的方法 41 } 42 }
其实看过上面的代码,就能明白他们的区别了。用父类引用进行调用的时候,只能调用父类中本来定义过的方法,因为父类引用指向子类对象就是多态!多态!!这里是很多人会跳入陷阱的地方了,对于成员方法而言,不管是编译还是运行,都是从父类中找的,那么如果你通过这个引用调用匿名内部类中特有的方法,自然是不可能实现的啦!!然后我们通过匿名对象.方法名的方法为什么就可以呢?因为它就是子类对象啊,它就死它自己啊,它并没有向上转型啊,自己当然可以调用自己的方法啊!!
说的最简单的,匿名对象类一个前提,两个明确:
前提:必须定义接口或父类
明确:1.定义在成员方法内,是局部内部类
2.匿名内部类的本质是继承的父类或实现的接口的匿名子类对象。
如果能想通这三个东西,对于理解使用匿名内部类也就没什么难度了。