final关键字

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了final关键字相关的知识,希望对你有一定的参考价值。

final修饰的变量

被final修饰的变量一旦被赋初始值,final变量的值以后将不会被改变。

被final修饰的实例变量必须显示指定初始值,且只能在3个位置指定初始值:

1.定义final实例变量时指定初始值

2.在非静态初始化块中为final实例变量指定初始值

3.在构造器中为final实例变量指定初始值

public class FinalInstanceVaribaleTest {

    final int var1 = "var1".length();
    final int var2;
    final int var3;
    {
        var2 = "var22".length();
    }
    public FinalInstanceVaribaleTest(){
        this.var3 = "var333".length();
    }
}

但本质上还是在构造器中被赋初始值(经过编译器的处理)。

 

对于final类变量而言,同样必须显示指定初始值,只能在2个地方制定

1.定义final类变量时指定

2.在静态初始化块中指定

public class FinalClassVaribaleTest {

    final static int var1 = "var1".length();
    final static  int var2;
    static{
        var2 = "var22".length();
    }
}

本质上实在静态初始化块中赋初始值。

 

对于局部变量来说更为简单,Java本来就要求局部变量必须被显示地赋初始值。

对于一个final变量,不管是类变量、实例变量、局部变量,只要定义该变量时使用了final修饰符修饰,并且定义该final类变量时指定了初始值,而且该初始值可以在编译时就确定下来,那么这个final变量本质上就是一个直接量。

public class FinalLocalTest {

    public static void main(String[] args) {
        final int a = 2;
        System.out.println(a);
    }
}

实质上,a就成为了一个"宏变量"(在编译时就可确定的值),再用到a的时候直接以2来代替。

public class FinalTest {

    public static void main(String[] args) {
        final int a = 5 + 2;
        final String str = "s" + "tr";
        final String book1 = "book1:" + 99.0;
        //下面的book2因为调用了方法,所以无法在编译时被确定下来
        final String book2 = "book2:" + String.valueOf(99.0);
        System.out.println(book1 == "book1:99.0");
        System.out.println(book2 == "book2:99.0");
    }
}

此时book2就不是"宏变量",所以输出为true  false

 对于实例变量而言,有三种方法可以赋初始值,但对于final实例变量而言,只有在定义该变量时指定初始值才会有"宏变量"的效果。

public class FinalInitTest {
    final String str1;
    final String str2;
    final String str3 = "str";
    {
        str1 = "str";
    }
    public FinalInitTest(){
        str2 = "str";
    }
    public void display(){
        System.out.println(str1 + str1 == "strstr");
        System.out.println(str2 + str2 == "strstr");
        System.out.println(str3 + str3 == "strstr");
    }
    public static void main(String[] args) {
        FinalInitTest fit = new FinalInitTest();
        fit.display();
    }
}

结果为:flase,false,true

对于final类变量也是如此,只有在定义类变量时指定初始值,才会变为"宏变量"。

 

final方法不能被重写

如果父类中的某个方法被final修饰符进行修饰,那么这个方法不可能被子类访问到,因此这个方法也不会被子类重写。

class Parent{
    private final void a(){
        System.out.println("P-->a");
    }
}
public class Children extends Parent{
    public void a(){
        //这个a方法并不是覆盖父类方法,而是定义的一个普通方法
        System.out.println("C-->a");
    }
}

如果想要测试是否为覆盖(重写),可在方法前加@Override(一个工具注释)。

与此类似的还有父类子类不在同一个包下,访问修饰符为private或默认,也是无法重写的。

 

final修饰的类无法被继承

一些常用的类:String、Math、System等等。

 

在任何内部类中访问的局部变量都应该使用final修饰。

interface IntArrayProductor{
    int product();
}
public class CommanTest{
    //定义一个方法生成指定长度的数组,但每个数组元素由cmd负责产生
    public int[] process(IntArrayProductor cmd,int length){
        int[] result = new int[length];
        for(int i = 0;i < length;i++){
            result[i] = cmd.product();
        }
        return result;
    }
    public static void main(String[] args) {
        CommanTest ct = new CommanTest();
        final int seed = 5;
        int[] result = ct.process(new IntArrayProductor()
        {
            public int product(){
                return (int)Math.round(Math.random() * seed);
            }
        },6);
        System.out.println(Arrays.toString(result));
    }
}

此时seed变量必须被final修饰(否则会出现编译错误),不过我在jdk1.8运行没有final也可以,有可能是新加的特性吧。

此处所说的内部类为局部内部类(包括匿名内部类),因为只有其可以访问局部变量,普通静态内部类、非静态内部类都不可能访问方法体内的局部变量。

 

以上是关于final关键字的主要内容,如果未能解决你的问题,请参考以下文章

Java之final关键字

final关键字修饰类,方法以及变量的特点 学习

final关键字

Java中的final关键字(修饰类修饰方法修饰变量)

Java中的final关键字(修饰类修饰方法修饰变量)

final关键字