问题1:内部类为什么会持有外部类的引用
这是因为内部类虽然和外部类写在同一个文件中,但是编译后还是会生成不同的class
文件,其中内部类的构造函数中会传入外部类的实例,然后就可以通过this$0
访问外部类的成员。
其实也挺好理解的吧,因为在内部类中可以调用外部类的方法,变量等等,所以肯定会持有外部类的引用的。
贴一段内部类在编译后用JD-GUI
查看的class
代码,也许你能更好的理解:
//原代码
class InnerClassOutClass{
class InnerUser {
private int age = 20;
}
}
//class代码
class InnerClassOutClass$InnerUser {
private int age;
InnerClassOutClass$InnerUser(InnerClassOutClass var1) {
this.this$0 = var1;
this.age = 20;
}
}
问题2:kotlin中的内部类与Java有什么不一样吗
这是因为在kotlin
中的匿名内部类
分为两种情况:
在Kotlin中
,匿名内部类如果没有使用到外部类的对象引用时候,是不会持有外部类的对象引用的,此时的匿名内部类其实就是个静态匿名内部类
,也就不会发生内存泄漏。在Kotlin中
,匿名内部类如果使用了对外部类的引用,像我刚才使用了btn2
,这时候就会持有外部类的引用了,就会需要考虑内存泄漏
的问题。
//java,匿名内部类的写法
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
上面这个是java匿名内部类的写法,kotlin没有new关键字,那么kotlin的匿名内部类该怎么写呢?
btn.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View?) {
print("1111")
}
})
同样kotlin
中对于内部类也是和Java
有区别的:
- Kotlin中所有的内部类都是默认静态的,也就都是
静态内部类
。 - 如果需要调用外部的对象方法,就需要用
inner
修饰,改成和Java一样的内部类,并且会持有外部类的引用,需要考虑内存泄漏问题。
kotlin的内部类与java的内部类有点不同java的内部类可以直接访问外部类的成员,kotlin的内部类不能直接访问外部类的成员,必须用inner标记之后才能访问外部类的成员
- 没有使用inner标记的内部类
class A{
var a = 0
class B{
//B类的内部是不能直接用a变量的
var b = 1
}
}
- 用inner标记的内部类
class A{
var a = 0
inner class B{
//B类的内部可以直接用a变量
var b = a
}
}
反编译后的java代码
public final class A {
private int a;
public final int getA() {
return this.a;
}
public final void setA(int var1) {
this.a = var1;
}
public final class B {
private int b = A.this.getA();
public final int getB() {
return this.b;
}
public final void setB(int var1) {
this.b = var1;
}
}
}
从上面可以看出,没有使用inner标记的内部类最后生成的是静态内部类,而使用inner标记的生成的是非静态内部类。