简单聊聊java中的final关键字
简单聊聊java中的final关键字
日常代码中,final关键字也算常用的。其主要应用在三个方面:
1)修饰类(暂时见过,但是还没用过);
2)修饰方法(见过,没写过);
3)修饰数据。
那么,我们主要也是从一下几个方面探讨一下,主要是第三点。
一、final修饰类和方法
final修饰的类不可被继承(例如: String, Integer, Double, ....);
final修饰的方法不可被重写(例如: AtomicInteger中的大部分方法)
二、final修饰数据
1. final修饰变量
分为局部变量和全局变量而言.如果是全局变量,不管你用不用,都必须而且只能赋值一次;
例如:
public class FinalTest {
private final int i;
}
如果不赋值,就会报编译错误: Variable "xxx" might not have been initialized。
如果是局部变量,如果不使用,可以不赋值。(当然,你得保证你的项目经理不会打死你)。
1.1 final修饰的基本数据类型和不变对象(例如: String, 包装类以及jdk8新的日期时间类库)那就是真的什么都不能该变了(引用与对象之间的引用关系,对象的内容(基本类型就是值)的值都不能改变). 例如:
public class FinalTest {
public static void main(String[] args) {
final int a = 10;
final LocalDate localDate = LocalDate.now();
}
}
如果再对a或者localDate进行赋值:就会报编译错误: cannot assign a value to final variable 'xxx'.
可以说,final对不可变对象的引用的修饰和对基础类型的引用的修饰含义几乎是一样的。
1.2 对于可变对象而言(常用的StringBuilder, 各种常见(List, Set, Map)的集合实现类),final仅仅只能保证引用和对象之前的引用关系不变,无法确保对象的内容(例如字段的值,容器内元素的个数)不变.
public class FinalTest {
public static void main(String[] args) {
final StringBuilder sb = new StringBuilder("sb ");
System.out.println("sb: " + sb);
sb.append("changed");
System.out.println("sb: " + sb);
}
}
-------------------------------------------------------------------------------
输出:
sb: sb
sb: sb changed
3. final修饰的值类型(8种基本数据类型 + String)将会优化为编译期常量
此处我们利用String的特性来测验一下:
public class FinalTest {
public static void main(String[] args) {
String a = "a";
String ab = a + "b";
System.out.println(ab == "ab");
final String finalA = "a";
String finalAB = finalA + "b";
System.out.println(finalAB == "ab");
}
}
-------------------------------------------------------------------------------
输出:
false
true
此处,我们可以对反编译FinalTest.class文件:
1 public class FinalTest {
2 public FinalTest() {
3 }
4
5 public static void main(String[] args) {
6 String a = "a";
7 String ab = a + "b";
8 System.out.println(ab == "ab");
9 String finalA = "a";
10 String finalAB = "ab";
11 System.out.println(finalAB == "ab");
12 }
13 }
对比第7行和第10行发现,第7行变量ab的值在编译期还是未知的(实际上在运行期,第7行的代码是这样执行的:
String ab = new StringBuilder("").append(a).append("b").toString;
而在StringBuilder#toString()方法内,new了一个新的String实例,因此ab 和 "ab"不是一个实例,所以第8行输出false.),而第10行变量finalAB的值在编译期就已知了,由于String常量池的缓存特性,使得finalAB和"ab"是同一个实例,所以第11行输出true.
这一点,有时候会带来一些问题。例如下面的例子:
1 class A{
2 public static final int A = 10;
3 }
4
5
6 class B{
7 public B(){
8 System.out.println(A.A);
9 }
10 }
从源代码中,可以看到class B和class A有些关系。但是实际上,编译之后的class字节码,类A 和类B没有任何关系。编译之后,第8行A.A已经被替换为10了。如果这个时候,修改了这个A中常量的值,然后仅仅对A重新编译,就会导致类B的class文件中依然是10.这可能给程序运行代码一些问题。
final修饰方法参数
`1这个在jdk中少见,但是在框架代码中常常见到.基本作用也就是防止方法调用者对参数在做赋值(其实这也是一种约定吧). 例如这样的场景: 现在有一组任务需要执行(任务可以并行),在这组任务全部执行完成之后,需要做一次清理缓存的操作; 可能的代码是这样的
List<Task> tasks = ...;
CountDownLatch countDoenLatch = new CountDownLatch(tasks.size());
for(Task task : tasks){
//线程池异步执行
WORKER.submit(task);
}
cleanCache(countDownLatch);
-----------------------------------------------------------------------------------------------------
public void cleanCache(final CountDownLatch countDownLatch){
countDownLatch.await();
...
}
此处cleanCache()方法中的参数CountDownLatch就需要使用final修饰。(如果对countDownLatch重新赋值,后续调用countDownLatch.await()会导致无限期等待)
小结:
final在修饰引用的时候,仅仅只能确保引用能且只能和某个对象建立引用关系(基本类型的值), 至于引用所指向的对象的内容是否可以改变,和这里的final没有任何关系,而是和这个对象是否是不变对象有关。 (通俗的将,使用final修饰某个引用的时候,这个final能够管得着的仅仅只是这个引用, 至于这个引起所指向的对象可不可变,它管不着。)
简单聊聊java中的final关键字的更多相关文章
- 浅析Java中的final关键字(转载)
自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...
- 关于Java中的final关键字
Java中的final关键字是用来限制用户行为的,说白了,就是用来限制我们这些程序员的.final可以用来修饰:变量.方法.类. 1)Java final variable final用来修饰变量时, ...
- 深入理解Java中的final关键字
Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...
- 浅析Java中的final关键字
浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- (转)深入理解Java中的final关键字
转自:http://www.importnew.com/7553.html Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方 ...
- [转载]浅析Java中的final关键字
浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- 转载:浅析Java中的final关键字
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...
- java中的final关键字
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...
- 浅析Java中的final关键字(转)
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...
随机推荐
- SpringBoot工作机制
1:前言 回顾探索Spring框架 1.spring ioc IoC其实有两种方式,一种就是DI,而另一种是DL,即Dependency Lookup(依赖查找),前者是当前软件实体被动接受其依赖的其 ...
- JDK1.8源码(四)——java.util.Arrays 类
java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用. 1.asList public static ...
- AsyncTask源码笔记
AsyncTask源码笔记 AsyncTask在注释中建议只用来做短时间的异步操作,也就是只有几秒的操作:如果是长时间的操作,建议还是使用java.util.concurrent包中的工具类,例如Ex ...
- VB求最大公约数的两个例子
VB求最大公约数的两个算法 Private Sub Command1_Click() Dim a As Long, b As Long a = InputBox("请输入要求最大公约数的整数 ...
- c++ --> cin和cout输入输出格式
cin和cout输入输出格式 Cout 输出 1>. bool型输出 cout << true <<" or " << false < ...
- centos-6.7 内核升级(转)
本文转自http://www.linuser.com/thread-1622-1-1.html 默认centos-6.7 自带的内核版本: [root@testserver ~ ::]#uname - ...
- dom4j 最常用最简单的用法(转)
要使用dom4j读写XML文档,需要先下载dom4j包,dom4j官方网站在 http://www.dom4j.org/目前最新dom4j包下载地址:http://nchc.dl.sourceforg ...
- hihocoder [Offer收割]编程练习赛52 D 部门聚会
看了题目的讨论才会做的 首先一点,算每条边(u, v)对于n*(n+1)/2种[l, r]组合的贡献 正着算不如反着算 哪些[l, r]的组合没有包含这条边(u, v)呢 这个很好算 只需要统计u这半 ...
- oracle中事务处理--事务隔离级别
概念:隔离级别定义了事务与事务之间的隔离程度. ANSI/ISO SQL92标准定义了一些数据库操作的隔离级别(这是国际标准化组织定义的一个标准而以,不同的数据库在实现时有所不同). 隔离级别 脏读 ...
- 十分钟释疑Oracle中“小表超慢”之谜(SQL调优/SQL优化)
前几天,一个用户找到我,说查一个小表的时候非常慢,我问有多慢,他说最快也得半个小时才能出结果,有时干脆不出结果,我说小表多大,他说就几十兆,有点疑惑,让他帮忙获取了相关信息,一看就明白了,原来所谓的小 ...