final 关键字的字面意思是最终的,不可修改的 。这似乎是一个看见名字就大概知道怎么用的语法,但你是否有深究过final在各个场景中的具体用法,注意事项,以及背后涉及的JAVA设计思想呢?一. final 修饰变量1. 基础: final 修饰基本数据类型变量和引用数据类型变量相信大家都具备基本的常识: 被 final 修饰的变量是不能够被改变的 。但是这里的”不能够被改变”对于不同的数据类型是有不同的含义的 。
当 final 修饰的是一个基本数据类型数据时,这个数据的值在初始化后将不能被改变;
当 final 修饰的是一个引用类型数据时,也就是修饰一个对象时,引用在初始化后将永远指向一个内存地址,不可修改 。但是该内存地址中保存的对象信息,是可以进行修改的 。
上一段话可能比较抽象,希望下面的图能有助于你理解,你会发现虽说有不同的含义,但本质还是一样的 。
首先是 final 修饰基本数据类型时的内存示意图:
文章插图
如上图, 变量 a 在初始化后将永远指向 003 这块内存,而这块内存在初始化后将永远保存数值 100 。
下面是 final 修饰引用数据类型的示意图:
文章插图
在上图中,变量 p 指向了 0003 这块内存,0003 内存中保存的是对象 p 的句柄(存放对象p数据的内存地址),这个句柄值是不能被修改的,也就是变量 p 永远指向 p 对象. 但是 p 对象的数据是可以修改的 。
// 代码示例public static void main(String[] args) {final Person p = new Person(20, "炭烧生蚝");p.setAge(18);//可以修改p对象的数据System.out.println(p.getAge()); //输出18Person pp = new Person(30, "蚝生烧炭");p = pp; //这行代码会报错, 不能通过编译, 因为p经final修饰永远指向上面定义的p对象, 不能指向pp对象. }
不难看出 final 修饰变量的本质: final 修饰的变量会指向一块固定的内存,这块内存中的值不能改变 。引用类型变量所指向的对象之所以可以修改,是因为引用变量不是直接指向对象的数据,而是指向对象的引用 。
所以被 final 修饰的引用类型变量将永远指向一个固定的对象,不能被修改;对象的数据值可以被修改 。
2. 进阶:被 final 修饰的常量在编译阶段会被放入常量池中final 是用于定义常量的,定义常量的好处是:不需要重复地创建相同的变量 。
而常量池是 Java 的一项重要技术,由 final 修饰的变量会在编译阶段放入到调用类的常量池中 。
请看下面这段演示代码,这个示例是专门为了演示而设计的,希望能方便大家理解这个知识点 。
public static void main(String[] args) {int n1 = 2019;//普通变量final int n2 = 2019;//final修饰的变量String s = "20190522";String s1 = n1 + "0522";//拼接字符串"20190512"String s2 = n2 + "0522";System.out.println(s == s1);//falseSystem.out.println(s == s2);//true}
温馨提示:整数 -127 - 128 是默认加载到常量池里的,也就是说如果涉及到 -127 - 128 的整数操作,默认在编译期就能确定整数的 。所以这里我故意选用数字2019 (大于128),避免数字默认就存在常量池中 。上面的代码运作过程是这样的:
首先根据 final 修饰的常量会在编译期放到常量池的原则,n2会在编译期间放到常量池中 。
然后 s 变量所对应的”20190522”字符串会放入到字符串常量池中,并对外提供一个引用返回给 s 变量 。(下一篇文章会介绍字符串常量池)
这时候拼接字符串 s1,由于 n1 对应的数据没有放入常量池中,所以 s1 暂时无法拼接,需要等程序加载运行时才能确定 s1 对应的值 。
但在拼接 s2 的时候,由于 n2 已经存在于常量池,所以可以直接与”0522”拼接,拼接出的结果是”20190522”
这时系统会查看字符串常量池,发现已经存在字符串20190522,所以直接返回20190522的引用 。
所以 s2 和 s 指向的是同一个引用,这个引用指向的是字符串常量池中的20190522 。
而 n1 会在程序执行时,才有具体的指向 。
当拼接 s1 的时候,会创建一个新的 String 类型对象,也就是说字符串常量池中的 20190522 会对外提供一个新的引用 。
所以当 s1 与 s 用 “==” 判断时, 由于对应的引用不同, 会返回 false 。而 s2 和 s 指向同一个引用,返回true 。
推荐阅读
- JavaScript 用法详解
- 从男人抱你的方式 探究男人的性爱心理
- 极品铁观音,观音王,铁观音茶叶中的极品
- 河里的鱼是怎么形成的 河里的水藻是怎么形成的
- 程序员在5G时代中的机遇!
- Java实现KMP 算法
- java实现一个Mqtt broker02处理MqttConn请求
- 淘宝规则中的雷区有哪些 除了从淘宝网首页可以进入规则频道以外
- 形容茶叶词语,找出问句中的关键词语
- 太阳系磁场 星球的磁场是如何形成的?