天天看點

面試官:final關鍵字有哪些作用?

面試官:final關鍵字有哪些作用?

介紹

final關鍵字的作用有如下幾種

  1. final修飾類時,表明這個類不能被繼承
  2. final修飾方法,表明方法不能被重寫
  3. final修飾變量,如果是基本資料類型的變量,則其數值一旦在初始化之後便不能改變;如果是對象類型的變量,隻能保證它的引用不變,但對象的内容是可以改變的

修飾類

final修飾類時,表明這個類不能被繼承

// 編譯錯誤,提示
// Cannot inherit from final 'java.lang.String'
public class ClassDemo extends String{
}      

盡量不要用final修飾類,除非這個類真的不可能被繼承,或者出于安全方面的考慮

修飾方法

final修飾方法,表明方法不能被重寫

在早期的版本,final修飾方法可以提高性能。不過在最新的版本中JVM做了優化,即使使用了final修飾也不會提高性能。

是以目前final的作用隻是不想讓子類重寫

修飾變量

final修飾變量,如果是基本資料類型的變量,則其數值一旦在初始化之後便不能改變;如果是對象類型的變量,隻能保證它的引用不變,但對象的内容是可以改變的

先來回顧一下8種基本資料類型

整數類型:byte(1位元組) short(2位元組) int(4位元組) long(8位元組)

浮點類型:float(4位元組) double(8位元組)

字元類型:char(2位元組)可以存儲一個漢字

布爾類型:boolean

JVM規範指出boolean當做int處理,也就是4位元組,boolean數組當做byte數組處理,這樣我們可以得出boolean類型占了單獨使用是4個位元組,在數組中是确定的1個位元組

public class VarDemo {

    public final int var = 0;

    public static void main(String[] args) {
        VarDemo varDemo = new VarDemo();
        // 編譯錯誤,提示
        // Cannot assign a value to final variable 'var'
        varDemo.var = 10;
    }
}      

從例子中可以看到,當想給final變量再次指派的時候,報編譯錯誤。

public class VarDemo {

    public final Map<String, String> map = new HashMap<>();

    public static void main(String[] args) {
        VarDemo varDemo = new VarDemo();
        varDemo.map.put("10", "10");
        varDemo.map.put("20", "20");
        // {20=20, 10=10}
        System.out.println(varDemo.map);
    }
}      

map雖然被final修飾了,裡面的值還是可以改變的,因為對象類型的變量隻能保證對象的引用不變,對象的内容是可以改變的

public class VarDemo {

    public final Map<String, String> map = new HashMap<>();

    public static void main(String[] args) {
        VarDemo varDemo = new VarDemo();
        // 編譯錯誤,提示
        // Cannot assign a value to final variable 'map'
        varDemo.map = new HashMap<>();
    }
}      

如果想讓map中的資料也不能變該怎麼辦呢?有很多三方的類庫,如Google Guava

// 不可變集合的建立
ImmutableList<String> list = ImmutableList.of("a", "b", "c");
ImmutableSet<String> set = ImmutableSet.of("a", "b");      

不可變集合是線程安全的,并且中途不可改變,因為add等方法是被聲明為過期,并且會抛出異常

public final void add(int index, E element) {
  throw new UnsupportedOperationException();
}      

還有需要注意的一點是在Java中數組也是對象,對象數組即使被final修飾,内容還是可以改變的

public class ArrayDemo {

    public static void main(String[] args) {
        final int array[] = {1, 2, 3};
        for (int i = 0; i < array.length; i++) {
            array[i] += 10;
            // 11
            // 12
            // 13
            System.out.println(array[i]);
        }
    }
}      
public class VarDemo {

    public static void invoke(final int a) {
        // 可以讀,但不可以修改
        System.out.println(a);
        // 編譯錯誤,提示
        // Cannot assign a value to final variable 'a'
        a = 100;
    }
}