写这篇博客,是为分析Handler引起内存泄漏做准备。
 
目录
- 匿名内部类的含义是什么?
 - 匿名内部类的三种情况
 - 非静态内部类为什么会持有外部类的引用?
 
匿名内部类的含义是什么?
首先是内部类,(内部类不难理解,有时间再分析,这里不展开)为什么称之为匿名?因为没有明确定义类的名称。看下面的例子就知道了。
匿名内部类的三种情况
- 实现接口的匿名内部类
例如android中常用的setOnClickListener(),runOnUiThread()。 
public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
	...
    public interface OnClickListener {
        void onClick(View v);
    }
	...
} 
		//使用:
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
 
View.OnClickListener只是接口名称,真正的类名,并没有给出。完整的写法,应该是:
    class TVListener implements View.OnClickListener{
        @Override
        public void onClick(View v) {
            System.out.println("onClick");
        }
    }
	
    tv.setOnClickListener(new TVListener());
 
TVListener就是具体的类名。
- 继承抽象类的匿名内部类。实现抽象方法,不举例了。
 - 继承普通类的匿名内部类。重写普通的某个方法,Android中的典型例子就是Handler,一般都会重写handleMessage()方法。
 
public class StandardActivity extends AppCompatActivity {
    private static final String TAG = "ActivityA";
    private Handler myHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 100) {
                Log.i(TAG, "xxx");
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate: ");
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = new Message();
                msg.what = 100;
                myHandler.sendMessage(msg);
            }
        }).start();
    }
}
 
非静态内部类为什么会持有外部类的引用?
静态内部类是不会持有外部类的引用的。详细查看:为啥非静态内部类能持有外部类?
 我们写三个类,看看编译出来的.class文件。
//模拟Android SDK中Activity.java
public class Activity {
}
//模拟Android SDK中的Handler.java
public class Handler {
    public void handleMessage(){
    }
}
//模拟实际开发中的MainActivity
public class MainActivity extends Activity {
    Handler mH;
    public void onCreate() {
        mH = new Handler() {
            @Override
            public void handleMessage() {
                System.out.println("重写handleMessage()方法");
            }
        };
        System.out.println(mH.getClass().getName());
    }
    public static void main(String[] args) {
        new MainActivity().onCreate();
    }
}
 
编译完,确实生成了4个.class文件:
 
看看MainActivity$1.class,构造器里面确实传入了MainActivity的对象var1。
class MainActivity$1 extends Handler {
    MainActivity$1(MainActivity var1) {
        this.this$0 = var1;
    }
    public void handleMessage() {
        System.out.println("閲嶅啓handleMessage()鏂规硶");
    }
}
 
有点不确定,如果不是匿名内部类,仅仅是非静态内部类,会不会也持有引用了?
 试下:
public class OutClass {
    class InClass{
    }
}
 
编译后:
 
 看看OutClass$InnerClass.class文件:
class OutClass$InClass {
    OutClass$InClass(OutClass var1) {
        this.this$0 = var1;
    }
}
 
还是在构造器中传入了外部类OutClass的引用。注意:这说明,即使不采用匿名内部类,采用非静态成员内部类的形式,定义Handler,也还是会持有Activity的引用。所以只能使用静态内部类的方式自定义Handler。
所以非静态内部类的.class文件中,构造器会自动传入外部类的引用。不管是不是匿名,只要是非静态内部类,默认持有外部类的引用。



















