关于匿名内部类首先要明白:
1,匿名内部类是定义在类的局部位置的(方法或者代码块中)
2,匿名内部类可以理解为一个类同时也是一个对象
3,匿名内部类没有类名(其实还是有类名的,一会看代码演示)
4,基本语法:new 接口或者类(参数列表){
类体
};
下面来看看基于一个接口的匿名内部类,先看一段代码:
public class Outer {
public void f(){
IA ia = new IA(){
@Override
public void say() {
System.out.println("hi~");
}
};
ia.say();
}
}
interface IA{
void say();
}
class test21{
public static void main(String[] args) {
new Outer().f();
}
}
关于这段代码肯定有很多疑问,我来一一解释一下。
先来看一个需求:我有一个接口,现在我想要实现接口里面的方法,并且在Outer类的f()方法里去使用这个方法。
常规的方法就是写一个新的类,让这个类去实现这个接口,然后再new一个对象,通过对象去调用这个方法。可是如果我这个方法只用一次的话,这样去做就显的代码有一些啰嗦,如果再来一个接口就又要写一个新的类......,这样想想都烦。所以我们就可以使用匿名内部类去解决这个问题。
所以上面这段代码就可以这样理解:
IA ia = new IA(){}
这里肯定有很多疑问,为什么可以实例化一个接口?其实这里不是实例化一个接口,这里在底层就相当于系统去创建了一个实现了IA接口的类(也就是匿名内部类),然后立马去创建了这个类的对象,接着返回给ia,让ia去指向这个对象,最后要注意,底层在创建了一个对象之后,这个类就没有了(不是说ia没有了,只是匿名内部类没有了,但是返回的对象还是存在的)。
这就是匿名内部类的一个大体过程,那我为什么说匿名内部类其实是有名字的呢,其实只要调一下ia的getclass方法就可以很清楚的看到底层创建的匿名内部类的名字了?下面看一段代码:
public class Outer {
public void f(){
IA ia = new IA(){
@Override
public void say() {
System.out.println("hi~");
}
};
System.out.println(ia.getClass());
}
}
interface IA{
void say();
}
class test21{
public static void main(String[] args) {
new Outer().f();
}
}
输出结果:class Outer$1
所以这个Outer$1就是匿名内部类的名字,这也就证实了我前面说的匿名内部类其实是有名字的。
再来看看基于一个类的匿名内部类:
public class Outer {
public void f(){
M m =new M(){
@Override
public void say() {
System.out.println("hello");
}
};
m.say();
}
}
class M{
public void say(){
System.out.println("hi");
}
}
class test21{
public static void main(String[] args) {
new Outer().f();
}
}
如果前面的东西已经理解了,相信这里大家都应该猜到了基于一个类的匿名内部类的大体过程了。没错,底层就是创建了一个继承了M类的类(也是就匿名内部类),然后再new一个匿名内部类的对象,最后再返回给m。
可以思考一下这段代码会输出上面结果
输出的结果其实是hello,这应该也不难,如果弄明白了过程就可以知道,这里面其实是有一个向上转型的过程的,因为m的编译类型是M而运行类型是......注意这里可不是什么M了,而是匿名内部类Outer$1(这个可以自己输出看一下)而Outer$1又是M的子类,用父类的引用去指向子类的对象。这可不就是典型的向上转型嘛,所以输出的自然就是hello了。
还有基于抽象类的匿名内部类,我就不再详细说明了,相信大家已经很清楚了。
这里主要就是为大家讲解了一下匿名内部类的底层运行过程,还有其他简单的细节可能还没有讲到,但是那些都是跟局部内部类是差不多的东西了,如果大家有什么不理解的地方,欢迎私信询问我,如果文章有什么错误,欢迎大家评论区指正。