博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 进阶 -- final 解析
阅读量:4286 次
发布时间:2019-05-27

本文共 2912 字,大约阅读时间需要 9 分钟。

谈到 final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到 final 关键字。另外,Java中的 String 类就是一个 final 类,那么今天我们就来了解 final 这个关键字的用法。

1. final 关键字的基本用法

在Java中,final 关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。下面就从这三个方面来了解一下 final 关键字的基本用法。

1.1 修饰类

当用 final 修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用 final 进行修饰。final 类中的成员变量可以根据需要设为 final,但是要注意 final 类中的所有成员方法都会被隐式地指定为 final 方法。

在这里插入图片描述

在使用 final 修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为 final类。

1.2 修饰方法

下面这段话摘自《Java编程思想》第四版第143页:

“使用 final 方法的原因有两个:

  1. 把方法锁定,以防任何继承类修改它的含义
  2. 第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用 final 方法进行这些优化了。

因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。

注:类的 private 方法会隐式地被指定为final方法。

1.3 修饰变量

修饰变量是 final 用得最多的地方,也是本文接下来要重点阐述的内容。首先了解一下 final 变量的基本语法:

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

举个例子:

在这里插入图片描述

2. 深入理解 final 关键字

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

当用 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));    }}

Result:

truefalse

这里面就是 final 变量和普通变量的区别了, 当 final 变量是 基本数据类型 以及 String 类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该 final 变量的地方,相当于直接访问的这个常量,不需要在运行时确定。

因此在上面的一段代码中,由于变量 bfinal 修饰,因此会被当做编译器常量,所以在使用到 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

2.2 被 final 修饰的引用变量指向的对象内容可变吗?

在上面提到被 final 修饰的引用变量一旦初始化赋值之后就不能再指向其他的对象,那么该引用变量指向的对象的内容可变吗?看下面这个例子:

public class Test {    public static void main(String[] args)  {        final MyClass myClass = new MyClass();        System.out.println(++myClass.i);     }} class MyClass {    public int i = 0;}

这段代码可以顺利编译通过并且有输出结果,输出结果为 1。这说明引用变量被 final 修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容是可变的

2.3 finalstatic

很多时候会容易把 staticfinal 关键字混淆,static 作用于成员变量用来表示只保存一份副本,而 final 的作用是用来保证变量不可变。看下面这个例子:

public class Test {    public static void main(String[] args)  {        MyClass myClass1 = new MyClass();        MyClass myClass2 = new MyClass();        System.out.println(myClass1.i);        System.out.println(myClass1.j);        System.out.println(myClass2.i);        System.out.println(myClass2.j);     }} class MyClass {    public final double i = Math.random();    public static double j = Math.random();}

运行这段代码就会发现,每次打印的两个j值都是一样的,而i的值却是不同的。从这里就可以知道final和static变量的区别了。

2.3 匿名内部类中使用的外部局部变量为什么只能是 final 变量?

参见海子博文中 中的解释.

转载自博客

– 海子

你可能感兴趣的文章
javaScript实现网页表格打印功能
查看>>
cvc-complex-type.2.4.a: Invalid content was found starting with element
查看>>
创建自定义的jsp标签
查看>>
根据两点经纬度计算距离-mysql方式和java方式
查看>>
Servlet技术浅析(一)之GenericServlet抽象类
查看>>
Servlet技术浅析(二)之HttpServlet抽象类
查看>>
设计模式之装饰者模式
查看>>
Servlet技术浅析(三)之-----ServletRequest接口和HttpServletRequest接口
查看>>
Servlet技术浅析(四)之-----ServletResponse接口和HttpServletResponse接口
查看>>
Servlet技术浅析(五)之-----ServletConfig接口和ServletContext接口
查看>>
Servlet技术浅析(六)之-----JavaWeb应用的生命周期和Servlet的生命周期
查看>>
Servlet技术浅析(七)之-----ServletContext与Web应用范围
查看>>
Servlet技术浅析(八)之-----浏览器缓存浅析
查看>>
Servlet技术浅析(九)之-----下载文件和上传文件
查看>>
一台linux操作系统上配置多台Tomcat服务
查看>>
maven入门浅析(二)-----maven集成eclipse、jboss
查看>>
正则表达式入门教程(三)
查看>>
SyntaxError: identifier starts immediately after numeric literal错误解决办法
查看>>
正则表达式入门教程(四)
查看>>
JAVA程序员成长之路的总结
查看>>