在能够通过编译的前提下,无论局部变量声明时带不带final关键字修饰,对其访问的效率都一样。

  并且:重复访问一个局部变量比重复访问一个成员或静态变量快;即便将其final修饰符去掉,效果也一样。

例如说,以下代码:

static int foo() {
int a = someValueA();
int b = someValueB();
return a + b; // 这里访问局部变量
}

与带final的版本:

static int foo() {
final int a = someValueA();
final int b = someValueB();
return a + b; // 这里访问局部变量
}

效果一模一样,由javac编译得到的字节码会是这样:

invokestatic someValueA:()I
istore_0 // 设置a的值
invokestatic someValueB:()I
istore_1 // 设置b的值
iload_0 // 读取a的值
iload_1 // 读取b的值
iadd
ireturn

  字节码里没有任何东西能体现出局部变量的final与否,Class文件里除字节码(Code属性)外的辅助数据结构也没有记录任何体现final的信息。既然带不带final的局部变量在编译到Class文件后都一样了,其访问效率必然一样高,JVM不可能有办法知道什么局部变量原本是用final修饰来声明的。

  但有一个例外,那就是声明的“局部变量”并不是一个变量,而是编译时常量的情况:

static int foo2() {
final int a = 2; // 声明常量a
final int b = 3; // 声明常量b
return a + b; // 常量表达式
}
这样的话实际上a和b都不是变量,而是编译时常量,在Java语言规范里称为constant variable。
Chapter 4. Types, Values, and Variables
其访问会按照Java语言对常量表达式的规定而做常量折叠。
Chapter 15. Expressions
实际效果跟这样的代码一样:
static int foo3() {
return 5;
}

由javac编译得到对应的字节码会是:

iconst_5 // 常量折叠了,没有“访问局部变量”
ireturn
  (用Eclipse里的Java编译器ECJ来编译 foo3() 可能会在iconst_5之前看到一些冗余的对局部变量的代码。那个其实没有任何作用,真正有用的还是后面的iconst_5,所以仍然符合Java语言规范的要求。可以在Preferences->Java->Compiler->Code Generation->Preserve unused (never read) local variables把钩去掉来改变Eclipse这一行为,然后得到的代码就会跟javac更接近。)
  而这种情况如果去掉final修饰,那么a和b就会被看作普通的局部变量而不是常量表达式,在字节码层面上的效果会不一样
static int foo4() {
int a = 2;
int b = 3;
return a + b;
}

就会编译为:

iconst_2
istore_0 // 设置a的值
iconst_3
istore_1 // 设置b的值
iload_0 // 读取a的值
iload_1 // 读取b的值
iadd
ireturn

  但其实这种层面上的差异只对比较简易的JVM影响较大,因为这样的VM对解释器的依赖较大,原本Class文件里的字节码是怎样的它就怎么执行;对高性能的JVM(例如HotSpot、J9等)则没啥影响。这种程度的差异在经过好的JIT编译器处理后又会被消除掉,上例中无论是 foo3() 还是 foo4() 经过JIT编译都一样能被折叠为常量5。

  Android里的Dalvik VM虽然是个比较简单的VM,但Android开发套件里的dexopt也可以用来处理这种final的局部“常量”与“变量”的差异,所以实际性能也不会受多少影响。

  还有,先把成员或静态变量读到局部变量里保持一定程度的一致性,例如:在同一个方法里连续两次访问静态变量A.x可能会得到不一样的值,因为可能会有并发读写;但如果先有final int x = A.x然后连续两次访问局部变量x的话,那读到的值肯定会是一样的。这种做法的好处通常在有数据竞态但略微不同步没什么问题的场景下,例如说有损计数器之类的。

  最后,其实很多人用这种写法的时候根本就没想那么多吧。多半就是为了把代码写短一点,为了把一串很长的名字弄成一个短一点的而把成员或静态变量读到局部变量里,顺便为了避免自己手滑在后面改写了局部变量里最初读到的值而加上final来让编译器(javac之类)检查。

 
以上内容整理自R大回答。

final对于访问效率的影响的更多相关文章

  1. java提高数据库访问效率代码优化

    package com.jb.jubmis.comm; import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQL ...

  2. linux测试noatime对文件访问时间的影响

    linux测试noatime对文件访问时间的影响 文件(如abc)有3个时间: # stat abc Access: 2015-04-16 19:30:13.665970572 +0800 Modif ...

  3. ejb2.0用本地引用提高EJB访问效率

    用本地引用提高EJB访问效率 EJB 1.0和1.1规范只定义了一种在EJB组件中引用另一组件的方法,即通过Bean的远程接口.如果两个Bean都在同一个容器之内,则这种网络开销是不必要的.为解决这个 ...

  4. 【.NET6】gRPC服务端和客户端开发案例,以及minimal API服务、gRPC服务和传统webapi服务的访问效率大对决

    前言:随着.Net6的发布,Minimal API成了当下受人追捧的角儿.而这之前,程序之间通信效率的王者也许可以算得上是gRPC了.那么以下咱们先通过开发一个gRPC服务的教程,然后顺势而为,再接着 ...

  5. java - day008 -final ,static ,访问控制符.

    面向对象   封装         类: 模板         对象: 实例         引用,遥控器         构造方法                新建对象时执行           ...

  6. as3 中trace() 函数对效率的影响

    进行页游开发的过程中,很多开发者都有一个习惯,在数据输出中添加trace()函数来跟踪数值 - 不进行条件编译,发布的时候也不删除.实际上大量的trace函数会降低程序的效率,我们可以用一个简单的例子 ...

  7. 遍历hashMap对效率的影响

    测试环境:jdk1.7.0_79\Processor 1.7 GHz Intel Core i5 遍历Map的方式有很多,通常场景下我们需要的是遍历Map中的Key和Value. 写了两个方法: pu ...

  8. Hosts文件实际应用 配置内部服务器提高访问效率和速度

    一 hosts文件的作用和介绍 https://jingyan.baidu.com/article/335530da45485e19cb41c3d6.html https://www.cnblogs. ...

  9. MySQL查询where条件的顺序对查询效率的影响<转>

    看到有资料说,where条件的顺序会影响查询的效率,根据的逻辑是: where条件的运行是从右到左的,将选择性强的条件放到最右边,可以先过滤掉大部分的数据(而选择性不强的条件过滤后的结果集仍然很大), ...

随机推荐

  1. [iOS Animation]-CALayer 图层树

    图层的树状结构 巨妖有图层,洋葱也有图层,你有吗?我们都有图层 -- 史莱克 Core Animation其实是一个令人误解的命名.你可能认为它只是用来做动画的,但实际上它是从一个叫做Layer Ki ...

  2. 3、手把手教你Extjs5(三)MVVM特性的简单说明

    下面我们来看一下自动生成的代码中的MVVM架构的关系.Main是一个可视的控件,MainController是这个控件的控制类,MainModel是这个控件的模型类. 在上面的图片中,左边是Main. ...

  3. Apache 重启时会有报 AH00558

    AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0 ...

  4. vs2012中的小技巧

    解除起始页: 网站(或者叫项目)-属性-启动选项-使用当前页 发布项目: 有些文件在发布的时候,不能发布到指定文件夹中,所以要手动修改该文件的属性 修改两处: 复制到输出目录:始终复制 生成操作:内容

  5. 巧用HTML5给按钮背景设计不同的动画

      如何巧用HTML5设计按钮背景不同动画特效,在该特效中,当鼠标滑过按钮时,使用CSS3   animation 来动画   background-size  和  background-posit ...

  6. eclipse控制台中文乱码解决

    Eclipse控制台中的中文输出乱码问题 博客分类: MySql EclipseTomcatXMLWeb  今天做S2SH集成的例子,所有该设置的地方都设置成了UTF-8,包括tomcat的配置文件s ...

  7. Chapter5 – 碰撞检测

    主人公能够放子弹了,虽然子弹看起来很美,但是怎么样来打到妖怪? 在这一章我们介绍一下最简单的碰撞检测方法去实现它. 首先第一个,我们有必要保存每个妖怪和子弹的指针,来够追踪他们的位置. 在这个游戏中我 ...

  8. C# Expression表达式笔记

    整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的来吧  它表示具有常量值的表达式 我们选建一个控制台应用程序 ConstantExpression _ ...

  9. IOS开发-UI学习-NSBundle和NSURL的区别(读取文件以及写入文件)

    NSBundle和NSURL的区别: 在项目的工程中添加一个文件,本例程添加的是aa.txt,文件的内容为百度: www.baidu.com,现在要使用NSBundle和NSURL分别去获取内容,代码 ...

  10. php中字符串长度和截取的函数

    在做PHP开发的时候,由于我国的语言环境问题,所以我们常常需要对中文进行处理. 在PHP中,我们都知道有专门的mb_substr和mb_strlen函数,可以对中文进行截取和计算长度,但是,由于这些函 ...