final关键字的一些作用

本文本不想写,为了第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关键字,引用将会恒定地指向对象所在的内存区域。

这才是可信赖的,宝贝。

猜你喜欢

转载自blog.csdn.net/qq_36523667/article/details/81238385