有关内部类不得不说的

Posted 碎格子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有关内部类不得不说的相关的知识,希望对你有一定的参考价值。

在我的Android开发常见的Activity中内存泄漏及解决办法这篇博客里有谈到内部类导致的内存泄漏。代码如下:

private static Object inner;
void createInnerClass() 
    class InnerClass 
    
    inner = new InnerClass();


View icButton = findViewById(R.id.ic_button);
icButton.setOnClickListener(new View.OnClickListener() 
    @Override public void onClick(View v) 
        createInnerClass();
        nextActivity();
    
);

在文章里楼主提到,非静态内部类会持有外部类的引用,而导致内存泄漏,而将其改为静态内部类就可以解决。

现在我们由这个结论引出问题,为什么非静态内部类会持有外部类的引用?

查阅google, 有些博主一语带过:

“当我们在创建一个内部类的时候,它无形中就与外围类有了一种联系,依赖于这种联系,它可以无限制地访问外围类的元素。”

所以什么叫“无形之中就有了联系”?为什么“依赖于这种联系,它可以无限制地访问外围类的元素”?看上去博主似乎自己也没搞明白。

让我们先回正题,看看为什么非静态类会持有外部类的引用。借用stackoverflow上有位答主的例子来看看:

class Outer 
    private int foo = 0;
    class Inner implements Runnable 
        public void run() foo++; 
    
    public Runnable newFooIncrementer() 
        return new Inner(); 
    

这是一个内部类,但这个类在编译的时候是这个样子的:

class Outer 
    private int foo = 0;
    static class Inner implements Runnable 
        private final Outer this$0;
        public Inner(Outer outer)
            this$0 = outer;
        
        public void run() this$0.foo++; 
    
    public Runnable newFooIncrementer() 
        return new Inner(this); 
    

当我们在进行new Inner()操作时,我们可以看到编译出来的代码里,调用构造方法时传入了一个this,这个this就是外部类对象的引用。
非静态内部类在生成的时候是作为外部类的一个成员类生成的,也就是外部类必须先生成,再有内部类的生成,所以内部类会“无形中就与外围类有了一种联系”。而从上面的例子可以看到,作为一个外部类的成员,它会持有一个外部类的引用,外部类的引用对自己元素的访问当然是无限制的,所以“它可以无限制地访问外围类的元素”。

为什么非静态内部类不能有静态变量?

public class OuterClass
    class InnerClass
        private static int i;
    

这是一段错误的代码,原因是非静态内部类里声明了一个静态变量。
为什么非静态内部类不能有静态变量呢?这要说到类的加载顺序了,java类加载的顺序是,先加载类,再执行static变量的初始化,再执行对象的创建。我们写了上面的代码,是希望加载的顺序是:先加载OuterClass,再加载InnerClass,最后执行static的初始化。而上面我们说到了,非静态内部类是作为外部类的成员类加载的,他的初始化必须在外部类的实例化对象创建后才进行,但java虚拟机要求所有的静态变量必须在对象创建之前初始化。上面代码中,按理加载完OuterClass之后就初始化静态变量i,但i声明在InnerClass里,这时连InnerClass都没初始化,哪来的i呢?
其实同理,静态内部类可以有静态成员这个理论同样可以通过类的加载顺序来解释,所以你知道了吗?

以上是关于有关内部类不得不说的的主要内容,如果未能解决你的问题,请参考以下文章

在方法中定义的内部类称为局部内部类

局部内部类详解

Java中成员变量局部变量局部内部类局部内部类方法作用域问题。

Java中,局部内部类

java9-8 局部内部类

局部内部类