简单聊聊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关键字的更多相关文章

  1. 浅析Java中的final关键字(转载)

    自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...

  2. 关于Java中的final关键字

    Java中的final关键字是用来限制用户行为的,说白了,就是用来限制我们这些程序员的.final可以用来修饰:变量.方法.类. 1)Java final variable final用来修饰变量时, ...

  3. 深入理解Java中的final关键字

    Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...

  4. 浅析Java中的final关键字

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

  5. (转)深入理解Java中的final关键字

    转自:http://www.importnew.com/7553.html Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方 ...

  6. [转载]浅析Java中的final关键字

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

  7. 转载:浅析Java中的final关键字

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

  8. java中的final关键字

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

  9. 浅析Java中的final关键字(转)

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

随机推荐

  1. 求第k小的元素

    用快排解决: 用快排,一趟排序后,根据基准值来缩小问题规模.基准值的下角标i 加1 表示了基准值在数组中第几小.如果k<i+1,那就在左半边找:如果k>i+1那就在右半边找.当基准值的下角 ...

  2. 剑指Offer-数组中重复的数字

    package Array; /** * 数组中重复的数字 *在一个长度为n的数组里的所有数字都在0到n-1的范围内. * 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次 ...

  3. AngularJs踩过的坑

    1. 使用checkbox和radio时, 不能使用ng-model直接绑定原始对象, 需要绑定一个对象的某个子属性, 才能把值绑定到scope <label><input type ...

  4. 实现Java线程安全

    一个类如果想要满足线程安全的条件: 每个线程都能正常的执行原子操作,保证得到正确的结果 这个类的对象可以同时被多个线程安全的访问 在每个线程的原子操作都完成后,对象处于合理的状态 一般情况下不可变类总 ...

  5. Dubbo源码-从HelloWorld开始

    Dubbo简介 Dubbo,相信做后端的同学应该都用过,或者有所耳闻.没错,我就是那个有所耳闻中的一员. 公司在好几年前实现了一套自己的RPC框架,所以也就没有机会使用市面上琳琅满目的RPC框架产品. ...

  6. Jmeter 前置处理器 BeanShell_PreProcessor 适用思考

    首先摘抄一段官方文档的话: Before invoking the script, some variables are set up in the BeanShell interpreter: lo ...

  7. 多目标跟踪(MOT)论文随笔-POI: Multiple Object Tracking with High Performance Detection and Appearance Feature

    网上已有很多关于MOT的文章,此系列仅为个人阅读随笔,便于初学者的共同成长.若希望详细了解,建议阅读原文. 本文是tracking by detection 方法进行多目标跟踪的文章,最大的特点是使用 ...

  8. 关于伪类after后续追加,实现js事件(如点击事件)

    实现情况为:点击"编辑"后,"编辑"文字变成"完成",再点击伪类元素后的"完成",此时的"完成"应该 ...

  9. 201621123062《java程序设计》第七周作业总结

    1. 本周学习总结 1.1 思维导图:Java图形界面总结 1.2 可选:使用常规方法总结其他上课内容. 1.布局管理器的具体使用方法 2.事件处理模型及其代码的编写 3.Swing中的常用组件 4. ...

  10. C简单实现双向链表

    <pre name="code" class="cpp">//链表结构 typedef struct DulNode { DataType data ...