本文本不想写,为了第4点而写
1.父类不可被继承
2.父类方法不可被重写
3.final提升基础数据类型到运行时常量池里
4.方法中,final指向的东西,匿名内部类也可以进行访问
第四点重点讲一下
void test(final Object o) { new Thread(new Runnable() { @Override public void run() { Log.i(TAG, o.toString()); } }).start(); }
这个o是外面传进来的,可能是在堆中分配的对象,也可能是如下
void test() { final Object o = new Object(); new Thread(new Runnable() { @Override public void run() { Log.i(TAG, o.toString()); } }).start(); }
这个o是临时创建的
通过这两个代码想说明,对象就这两种来源,都是创建在堆中的(而非异想天开地在栈帧的局部变量表中创建)。
我们的局部变量表只是有这样一个引用
引用名 内存地址
---------------------------
o e9879862dw
大概是这样的。但是为何匿名内部类只能访问加了final后的对象引用呢?
只有一个可能:
Java语法认为,这个匿名内部类的方法不一定何时会被调用,不一定一直像这样
void test() { final Object o = new Object(); Runnable runnable = new Runnable() { @Override public void run() { Log.i(TAG, o.toString()); } }; runnable.run(); }
直接就调用了。更多的是像这样
void test() { final Object o = new Object(); new Thread(new Runnable() { @Override public void run() { Log.i(TAG, o.toString()); } }).start(); }
在这个方法结束后才被调用。
在方法结束后自然要进行栈帧的出栈,局部变量表的reset,所以匿名内部类拿到的引用,其指向会被赋值为空!这就会造成空指针异常。
所以为了既规避空指针异常,又能及时回收栈帧、局部变量表,我们需要final关键字
有了final关键字,引用将会恒定地指向对象所在的内存区域。
这才是可信赖的,宝贝。