final关键字

2020-03-17  本文已影响0人  wbpailxt

final修饰基本类型和引用类型的区别

final修饰基本数据类型,基本数据类型属性的值(数值or布尔值or字符值)不能改变。
final修饰引用类型,引用类型属性不能更改对象的指向,即不能更改引用值。

不可变性的定义和拥有不可变性的办法

基本类型属性的值不能变,引用类型属性所指向的对象的状态不能变。

基本数据类型和String类型的属性:

引用类型(String除外)的属性:

final修饰不同位置变量的赋值时机

类中的final属性

package mythread;

/**
 * 会讲赋值操作和代码块都移到构造函数
 * 假如有构造函数则会把赋值操作和代码块的语句都添加到构造函数的前面
 *
 */
public class ThreadTest implements Runnable{

    private int age = 0;
    {
        System.out.println(age);
    }
    @Override
    public void run() {
        age++;
    }
    public ThreadTest(){
        age = 1;
    }
    public ThreadTest(int age){
        this.age = age;
    }
}

经过javac编译,再jad反编译之后得到

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   ThreadTest.java

package mythread;

import java.io.PrintStream;

public class ThreadTest
    implements Runnable
{

    public void run()
    {
        age++;
    }

    public ThreadTest()
    {
        age = 0;
        System.out.println(age);
        age = 1;
    }

    public ThreadTest(int i)
    {
        age = 0;
        System.out.println(age);
        age = i;
    }

    private int age;
}

类中的staic final属性

方法中的final变量

使用前赋值即可。

总结

局部变量无论修饰不修饰final,使用前都需要被初始化。
成员变量/静态成员变量修饰final强制初始化,不修饰final则有初始化值

final修饰方法

被final修饰的方法,子类不能重写,可以调用。
另外:子类中允许有和父类static方法同名的static方法,但是本质不一样,这两个static方法分别与父类和子类绑定,分属不同的类。

final修饰类

被final修饰的类不能被继承。

面试题

第一个题目

package immutable;

/**
 * 描述:     TODO
 */
public class FinalStringDemo1 {

    public static void main(String[] args) {
        String a = "wukong2";
        final String b = "wukong";
        String d = "wukong";
        String c = b + 2;
        String e = d + 2;
        System.out.println((a == c));
        System.out.println((a == e));
        System.out.println(b==d);

    }
}

结果:


运行结果

分析:


编译前后对比

b是编译时期常量,编译时用到b的就直接替换成b的值。
e是运行时确定的字符串会在堆上生成字符串对象。
e是指向堆上,ac是指向常量池的。

第二个题目

public class FinalStringDemo2 {

    public static void main(String[] args) {
        String a = "wukong2";
        final String b = getDashixiong();
        String c = b + 2;
        System.out.println(a == c);
    }

    private static String getDashixiong() {
        return "wukong";
    }
}

结果:


运行结果

分析


编译前后对比

编译器此时无法确定final属性的值,所以编译器也不会进行优化,所以c也是运行的时候才生成的,所以c的字符串对象也是建立在堆上的。而a还是指向常量池的。

后续

后续写一篇Class文件常量池,String常量池和运行时常量池的文章,敬请期待。

上一篇下一篇

猜你喜欢

热点阅读