Hey, Nice to meet You. 

必有过人之节.人情有所不能忍者,匹夫见辱,拔剑而起,挺身而斗,此不足为勇也,天下有大勇者,猝然临之而不惊,无故加之而不怒.此其所挟持者甚大,而其志甚远也.          ☆☆☆所谓豪杰之士,

夯实Java基础(九)----final关键字

1、final简介

Java语言中的final关键字,想必大家都不是很陌生,平时使用最多的情况应该是结合Static关键字来定义常量,还有在面试的时候有一个常见的面试题就是:final、finally、finalize区别,那么下面就来了解final这个关键字的用法,其实这个关键字还是非常简单的。

final从字面意思是不可更改的,最终的意思,它可以用来修类、成员方法、变量(包括成员变量和局部变量)、参数

  • final类:表示不能被继承,没有子类,final类中的方法默认是final的;
  • final方法:表示不能被重写,但可以被继承,可以被重载,这里很多人会弄混;
  • final成员变量:表示常量,只能被赋值一次,赋值后值不再改变,变量是只读的。final变量经常和static关键字一起使用,作为常量。
  • final参数(形参):表明该形参的值不能被修改,即不能被重新赋值了;

2、final修饰类

final修饰类,表示该类不能再被继承了。如果一个类中的功能是完整的,那么我们可以将该类用final来修饰,它不需要被继承来扩展别的功能了。我们最常用String、Integer、System等类就是用final修饰的,其不能再被其它类所继承。

image

用final修饰类如果被继承了那么在编译的时候就会报错。

3、修饰方法

final修饰方法,表示这个方法不能被子类方法重写。如果你认为一个方法的功能已经足够完整了,不需要再去子类中扩展的话,我们可以声明此方法为final。比如Object类中getClass()方法就是final修饰的。

image

注意:类中所有的private方法都自动成为final。由于不能访问一个private方法,所以它绝对不会被覆盖。

4、修饰变量

final修饰变量表示是常量,一般都和static一起使用,用来定义全局常量。final无论修饰的是成员变量还是局部变量,都必须进行显式初始化。

public class FinalTest {
    //显式初始化
    final int AA = 11;
    final int BB;
    final int CC;
    final int DD;
    //构造代码块初始化
    {
        BB = 22;
    }
    //构造方法初始化
    public FinalTest() {
        CC = 33;
        DD = 44;
    }
    public FinalTest(int CC, int DD) {
        this.CC = CC;
        this.DD = DD;
    }
}

我们可以通过显式初始化、构造代码块初始化、构造方法初始化等只要能够初始化成功的方式对final修饰的变量进行初始化即可。前面都是final修饰基本数据类型的变量,如果final修饰引用变量会是怎么样,我们来看一下举例:

public class FinalTest {

    public static void main(String[] args) {
        final AA aa = new AA();
        //这里在引用其他的对象就会报错Cannot assign a value to final variable 'aa'
        //aa=new AA();
        aa.i++;
        System.out.println(aa.i);
    }

}
class AA {
    int i;
}
//运行结果:1

可以看到,虽然我们将引用变量用final修饰了,但是该对象的变量 i 我们还是可以进行修改,而这个变量的引用不能再指向另一个对象了。表明final修饰的是引用变量,就不能再指向其他对象,但是如果该对象内的变量不是final修饰的,其变量的值是可以进行修改的。

final关键字修改变量小结:对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

5、修饰参数

final修饰参数准确的来说应该是修饰形参,表明该形参的值不能被修改。

public class FinalTest {
    public void show(final int param) {
        //编译报错:Cannot assign a value to final variable 'param'
        //param=10;
        System.out.println(param);
    }

    public static void main(String[] args) {
        FinalTest f = new FinalTest();
        f.show(5);
    }
}

我在使用final修饰形参时,表明此形参是一个常量。当我们调用方法的时候,给形参进行赋值,一旦赋值以后,就只能在该方法使用,而且不能进行重新赋值操作,否则编译报错。如果形参是引用类型,则引用变量不能再指向其他对象,但是该对象的内容是可以改变的。

6、类的final变量和普通变量有什么区别?

参考链接:https://www.cnblogs.com/xiaoxi/p/6392154.html

当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了。那么final变量和普通变量到底有何区别呢?下面请看一个例子:

public class Test {
    public static void main(String[] args) {
        String a = "hello2";
        final String b = "hello";
        String d = "hello";
        String c = b + 2;
        String e = d + 2;
        System.out.println((a == c));
        System.out.println((a == e));
    }
}

输出结果:true、false
大家可以先想一下这道题的输出结果。为什么第一个比较结果为true,而第二个比较结果为fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。这种和C语言中的宏替换有点像。因此在上面的一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的值。而对于变量d的访问却需要在运行时通过链接来进行。想必其中的区别大家应该明白了,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,比如下面的这段代码就不会进行优化:

public class Test {
    public static void main(String[] args) {
        String a = "hello2";
        final String b = getHello();
        String c = b + 2;
        System.out.println((a == c));

    }

    public static String getHello() {
        return "hello";
    }
}

这段代码的输出结果为false。这里要注意一点就是:不要以为某些数据是final就可以在编译期知道其值,通过变量b我们就知道了,在这里是使用getHello()方法对其进行初始化,他要在运行期才能知道其值。

7、final、finally和finalize的区别

1、final修饰符(关键字)。被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。将变量或方法声明为final,可以保证他们在使用的过程中不被修改。被声明为final的变量必须在声明时给出变量的初始值,而在以后的引用中只能读取。被final声明的方法也同样只能使用,即不能方法重写。

2、finally是在异常处理时提供finally块来执行任何清除操作。不管有没有异常被抛出、捕获,finally块都会被执行。try块中的内容是在无异常时执行到结束。catch块中的内容,是在try块内容发生catch所声明的异常时,跳转到catch块中执行。finally块则是无论异常是否发生,都会执行finally块的内容,所以在代码逻辑中有需要无论发生什么都必须执行的代码,就可以放在finally块中。

3、finalize是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者被执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

posted @ 2019-07-25 17:06  唐浩荣  阅读(407)  评论(0编辑  收藏  举报