技术探究:

被final修饰的 变量可以被修改吗 ?

在java的学习中,从刚接触final这个关键词时,就被告知:
------“被final修饰的变量只能一次赋值,以后不能被修改,即常量“。

对于这种比较基础的知识,我对老师的说法还是深信不疑的,总觉得这么基础的东西,作为老师不应该教错吧。而且日常工作里也确实是这么用的,使用final修饰变量作为常量,然后直接在其他类中使用的例子也比比皆是。

但最近在偶然的机会下,跟朋友深入探究了一下关于“被final修饰后的变量是否可以被修改”,才发现里面确实是有猫腻的 ,感觉被各种坑了!!!

首先,先说一下结论。被final修饰的变量中,有一部分变量是可以被修改的!!!


技术分析:

不谈理论,咱们先直接上代码瞅一眼:

首先:我们准备一个空的实体类ObjectOV:

public class ObjectVO {}

然后,我们再准备一个实体类,用来放用final修饰的各种变量。

public class FinalVO {private final int intValue = 1;private final Integer integerValue = new Integer(1);private final int intNoValue;private final String stringValue =  "1";private final String newStringValue = new String("1");private final String stringNoNValue;private final ObjectVO objectVO = new ObjectVO();public int getIntValue() {return intValue;}public Integer getIntegerValue() {return integerValue;}public int getIntNoValue() {return intNoValue;}public String getStringValue() {return stringValue;}public String getNewStringValue() {return newStringValue;}public String getStringNoNValue() {return stringNoNValue;}@Overridepublic String toString() {return "FinalVO{" +"intValue=" + intValue +", integerValue=" + integerValue +", intNoValue=" + intNoValue +", stringValue='" + stringValue + '\'' +", newStringValue='" + newStringValue + '\'' +", stringNoNValue='" + stringNoNValue + '\'' +", objectVO=" + objectVO +'}';}public FinalVO(int intNoValue, String stringNoNValue) {this.intNoValue = intNoValue;this.stringNoNValue = stringNoNValue;}
}

上面这个实体类中,所有变量都被final修饰。变量类型包括-----已赋值的基础变量、已赋值的包装类变量、未赋值的基础变量、直接赋值的String类型、new String方式赋值的String类型、未赋值的String类型,还有一个对象。

最后,我们再创建一个测试类,把所有被final修饰的内容都修改一下,然后再来看看结果:

public class FinalTest {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {FinalVO finalVO = new FinalVO(1,"1");Class clz = FinalVO.class;Field field = null;System.out.println(finalVO.toString());modifyValue(field,clz,finalVO,"intValue",2);modifyValue(field,clz,finalVO,"integerValue",2);modifyValue(field,clz,finalVO,"intNoValue",2);modifyValue(field,clz,finalVO,"stringValue","2");modifyValue(field,clz,finalVO,"newStringValue","2");modifyValue(field,clz,finalVO,"stringNoNValue","2");modifyValue(field,clz,finalVO,"objectVO",new ObjectVO());System.out.println(finalVO.toString());}private static void modifyValue(Field field,Class clz, FinalVO finalVO, String fieldName, Object obj) throws NoSuchFieldException, IllegalAccessException {field = clz.getDeclaredField(fieldName);field.setAccessible(true);field.set(finalVO,obj);}
}

接下来就是见证结果的时刻了:

FinalVO{intValue=1, integerValue=1, intNoValue=1, stringValue='1', newStringValue='1', stringNoNValue='1', objectVO=com.company.finalTest.ObjectVO@4b67cf4d}
FinalVO{intValue=1, integerValue=2, intNoValue=2, stringValue='1', newStringValue='2', stringNoNValue='2', objectVO=com.company.finalTest.ObjectVO@12a3a380}

让我们来分析一下这个结果:
从结果可以看到,只有被初始赋值的基础类型和被初始直接赋值的String类型的值没有改变,其余被final修改的内容都已出现变化。


技术总结:

让我们来分析一下上面这个结果:
对于这个结果,我一开始也不是太明白,然后开始大量的搜原因,最后得出来个名词—“内联函数“。
内联函数,编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。
我们可以理解成:JVM再编译代码的时候,会对代码进行一些优化。比如这段代码中的获取变量值,其实在编译阶段就已经被直接赋值好了。

用上面代码举例:

public int getIntValue() {return intValue;
}

这段代码经过JVM的内联优化之后会变成(可以通过反编译查看):

public int getIntValue() {return 1;
}

由此可见,我们可以修改对应变量的值,但无论我们怎么修改,在获取这个int值的时候都不会获取到修改后的值。

让我们来总结一下结果:

被final修饰的部分变量是可以被修改的,其中被初始赋值的基础类型和被初始直接赋值的String类型,这两种会被JVM进行内联优化 ,无法通过对象获取修改后的值。


期间,还发现了一个变量--StringBugger:
String是字符串变量,它的对象是可以扩充和修改的,即使是被final修饰,依然可以修改。

public class Test02 {public static void main(String[] args) {final StringBuffer sb = new StringBuffer("sb");System.out.println(sb);sb.append("a");System.out.println(sb);}
}

结果是:

sb
sba

被final修饰的部分变量后依然可以被修改相关推荐

  1. final 修饰的成员变量必须手动初始化

    理解1: final关键字我们并不陌生,但是final修饰的属性变量为什么必须在定义的时候或者构造函数中被初始化呢? static final修饰的变量又为什么必须在定义的时候进行初始化呢? 首先要明 ...

  2. git linux 配置环境变量后依然不生效 原因

    因为 系统中已经安装了一个低版本的 git 删除 掉它就好 : yum remove git source /etc/profile 这样我要的 版本就可以了

  3. final修饰变量、方法、类的作用

    1.final修饰类 final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的.在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展, ...

  4. final修饰的变量就是常量?

    概念 什么是常量? 对于这个问题,可能很多人都可以脱口而出 : 用final修饰的变量是常量 ,或者是在编译时期定义好的字符串.(字符串常量) 但是这种说法是不严谨的,因为准确来说 : 常量是用fin ...

  5. final修饰的变量就是常量?final修饰局部变量在栈还是堆还是常量池中?

    概念 常量池 常量池的好处 Class类文件中的常量池 常量池 运行时常量池 包装类常量池对象池 Java中装箱和拆箱 赋值时 方法调用时 方法运算时 参考 概念 什么是常量? 对于这个问题,可能很多 ...

  6. Java中被final修饰的变量的几种赋值方式

    关于final final 表示"最后的.最终的"含义,变量一旦赋值后,不能被重新赋值.被 final 修饰的实例变量必须显式指定初始值. final 修饰符通常和 static ...

  7. final修饰符,修饰的变量、方法、类、还有一些相关注意事项

    final final修饰变量:对于final修饰的变量来说,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,是指引用变量不能变,引用变量所指向的对象中的内容还是可 ...

  8. final修饰类,修饰方法,修饰变量有什么特点?

    1.final修饰的类不可以被继承,但可以继承其他的类. 2.final修饰的方法,子类可以继承但是不能重写. 3.子类重写父类的非final方法可以加上final. 4.被final修饰的基本数据类 ...

  9. java 中final修饰的变量_java中final修饰符的使用方法

    本文为大家分享了java中final修饰符的使用,供大家参考,具体内容如下 1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可 ...

最新文章

  1. mysql数据库常见错误码大全
  2. 关于Spring 声明式事务处理时,throws exception不回滚的问题
  3. SQL Server 2008 R2 Developer Edition图文安装教程
  4. SQLServer常用系统视图
  5. 图示不写程序如何根据dbSNP rs号批量获取基因组坐标、相关基因和表型影响
  6. 云图说|云上应用监控神器——应用性能监控APM2.0
  7. 繁体中文转换为简体中文的PHP类
  8. scala case class与class区别
  9. matlab设计滤波器
  10. java定义苹果类Apple_Java开发笔记(七十)Java8新增的几种泛型接口
  11. PDF文件密码怎么解除
  12. rand和randc有什么区别
  13. 修改UE4的缓存路径
  14. 投基取巧:如何通过基金投资获得 20%+ 的收益?基金理财干货分享,附思维导图!
  15. 宝塔面板网站一打开cpu百分百_解决宝塔面板CPU占满100%,负载100%网站缓慢等问题...
  16. esxi6.0虚拟机克隆及跨版本克隆
  17. 送给入门maven的愤怒青年:archetype-cattalog内容详解
  18. 洛谷P1477 假面舞会
  19. 使用oracle数据库建表语句,怎么使用sql查询oracle建表语句
  20. 常用ftp大全.txt

热门文章

  1. 从电阻丝印读取电阻阻值
  2. 用C语言编写函数multiple求倍数、用C语言编写函数isEven判断奇数和偶数
  3. 文件设置默认打开方式
  4. Kubernetes1.13集群安装dashboard 1.10.1
  5. CEPH(详解+配置)
  6. DOM节点类型及其属性和方法
  7. 2022软件测试面试题(不含答案)
  8. Deepin UOS 20安装(附带镜像文件)
  9. Scala一种编程语言
  10. Android修行手册之Kotlin-【Null检查】、【类型检查】、【区间】、【条件语句】、【循环控制】