表面上是没有引用名的, 但其实是有用于定位的“名字”,
如上代码,
new Foo()在定义的时候,
重写了bar()这个方法,
如此一来new Foo(){...}
这里就是一个匿名内部类
了;
呐这个匿名内部类,实际上在字节码
中是会定义出来的,!!!
定义出来一个用于定位的“名字”,
这个“名字”可见上面代码的第二行,
“com.bennyhuo.iiv.ch1.
”即代码包名
,
“OuterClass$1
”即外部内名
$1
,
1
代表这个匿名内部类
,
是前缀的外部类中,定义的第一个匿名内部类,
再创建第二个匿名内部类 就是$2
了;
所以匿名内部类
跟普通类
一样,是可以加载
出来的!!!
只不过参数格式
不一样,
普通类
是“class 类名
”
匿名内部类
是“class 包名.外部类名$num
”
匿名内部类
被创建的时候,
就默认 匿名内部类
是作为一个子类
去继承
其对应的父类
了:(接口亦同)
既 继承某个父类 又 实现某个接口 的“匿名内部类” 的 这种类型,
在Java中是不被接受的,
因为这其实是一种“或类型”,
即Runnable或上Foo的结果,作为一种类,
这在Java中是不被接受的:**即使使用Java 10 的var关键字来定义,
如上代码,
new Foo()在定义的时候,
重写了bar()这个方法,
如此一来new Foo(){...}
这里就是一个匿名内部类
了;
呐这个匿名内部类,实际上在字节码
中是会定义出来的,!!!
定义出来一个用于定位的“名字”,
这个“名字”可见上面代码的第二行,
“com.bennyhuo.iiv.ch1.
”即代码包名
,
“OuterClass$1
”即外部内名
$1
,
1
代表这个匿名内部类
,
是前缀的外部类中,定义的第一个匿名内部类,
再创建第二个匿名内部类 就是$2
了;
所以匿名内部类
跟普通类
一样,是可以加载
出来的!!!
只不过参数格式
不一样,
普通类
是“class 类名
”
匿名内部类
是“class 包名.外部类名$num
”
####b.匿名内部类的继承结构
- 匿名内部类
被创建的时候,
就默认 匿名内部类
是作为一个子类
去继承
其对应的父类
了:(接口亦同)
- 但是下面这种类型,
既 继承某个父类 又 实现某个接口 的“匿名内部类” 的 这种类型,
在Java中是不被接受的,
因为这其实是一种“或类型”,
即Runnable或上Foo的结果,作为一种类,
这在Java中是不被接受的:
>>
即使使用Java 10 的var关键字来定义, 也是不行的, 这种类型还是不能被接受: (在处理 var时,编译器先是查看表达式右边部分, 也就是所谓的构造器,并将它作为变量的类型,然后将该类型写入字节码当中)
嗯,
可是如果实在是想实现一个
如既 继承某个父类 又 实现某个接口 的“匿名内部类”
这样的类型,
但要不想占用太多资源
,要求同匿名内部类
一样用完即销毁
,怎么办?
那别用匿名内部类
呗,
在方法体内部
实现即可,!!!
便可以在方法调用完毕后将其回收
,
也可以达到需求
:
另外,Kotlin是可以实现,
既 继承某个父类 又 实现某个接口 的“匿名内部类” 的 这种类型的
:
(object类似于class与定义一个引用,
object与后面冒号之间不接名字表示匿名,
冒号后面要继承什么,实现什么,直接写出来就是了)
匿名内部类
对外部类
的引用
)匿名内部类
的构造方法
是 编译器
帮忙定义
的!!!
开发者没有权 定义匿名内部类
的构造方法
;编译器 会 根据代码 为 匿名内部类
的构造方法
引入一些参数,
如下面图中例子,
(右上)有一个OuterClass
,里边有一个InnerClass
,
(左上)这时候在Client类中,
new出来一个匿名内部类
,
例子中这个new出来的匿名内部类
,
实际上它的父类就是InnerClass
,
而InnerClass本身是一个非静态的内部类
,
!!!!!非静态的内部类本身就会引用外部类的实例!!!!!!
,
所以OuterClass()的实例也会在这里(左上第四行)new出来;
而下方的Client$1
就是上述所说的匿名内部类的类型
了,
Client$1
的命名格式其实就是刚刚说的外部内名$匿名内部类序号
;
所以图中下方代码块的第二行,
即编译器
根据代码 为 匿名内部类
生成的构造方法
,
其第一个参数
,就是Client,即匿名内部类所在方法
对应的 外部作用域
(最外部类);
因为这里的匿名内部类所在的方法
是非静态方法
,
所以一定是被某个实例(最外部类实例)
引用
着的!!!!!
其第二个参数
,即匿名内部类的父类
,
这个父类
如果是某外部类
的非静态内部类
,
那把这个对应的外部类实例
传进来即可,
因为这个外部类实例
可以应用到其成员
(包括非静态内部类
);
interface
跟静态内部类
的效果是差不多的,
就是静态
的,
也就是不会去引用其外部类的实例!!!!!
所以这时候匿名内部类
的构造方法
的参数
就只有一个所在方法的最外部类实例
了;
而,当匿名内部类所在的方法是静态的,
则其构造方法的参数中,
不存在所在方法的最外部类实例
了;
即,
匿名内部类
的构造方法
的参数个数
, 由其父类
以及其所在方法
是否静态
决定, 父类非静态
,则需传入父类相关实例
; 所在方法非静态
,则需传入所在方法的最外部类实例
; 反则, 哪个静态了,就不用传哪个; 00 01 10 11
所在方法内
(外部作用域) 的 局部变量
快照的情况
匿名内部类
重写父类方法
时,引用到的外部方法体内
的局部final变量
通常,要求要被捕获的局部变量
需要是final
修饰的;
虽然说如果不final
的话,
对匿名内部类
的构造方法
也不是很有影响
,
因为传给匿名内部类构造方法
的这个局部变量实例
,
实际上只是捕获局部变量实例
的一个快照
,
快照
即复制一份引用
,给匿名内部类
的构造方法
去使用,
但是,
如果这个局部变量实例
不是final
的,
那局部变量实例
被重新赋值
了,
外部的局部变量实例
跟传给匿名内部类构造方法
的局部变量实例
,就不一样了!
这个肯定是不行的吧,
所以,
Java要求,
这个地方(图中左边,第三行,也即被传给 匿' 构造方法
的这个 局部实例
)一定
要是final
的,
原因就是为了让这个局部变量实例
,在外部和在 匿’ 构造方法
中,
给保持一致
!
匿名内部类的构造方法小结
反射
,
去修改匿名内部类
的构造方法
持有的外部引用
(参数列表
)的一个接口,只有一个抽象方法时,可以用Lambda表达式替换实现;