程序员你真的理解final关键字吗?

文章目录

    • 1、修饰类
    • 2、修饰方法
    • 3、修饰变量
    • 4、final变量修饰变量(成员变量、局部变量)
        • 4、1 final修饰成员变量:
        • 4、2 final修饰局部变量:
    • 5、final变量和普通变量的区别
    • 6、final与static的藕断丝连
    • 7、关于final修饰参数的争议

前言

提到final关键字,想必大家都不陌生,可是程序员你真的理解final吗?就比如网上流传的”方法中不需要改变作为参数的对象变量时,使用final进行声明,可以防止你无意的修改而影响到调用方法外的变量“ 针对这句话你怎么看?反正博主不认同,这句话显然太过于决定,至于原因后续文章将讲到…

在使用匿名内部类的时候会经常用到final关键字。而且在Java中String类就是一个final类,从本篇文章开始,咋们一起来揭开final的神秘面纱…

1、修饰类

final修饰一个类时,表明这个类不能被继承。

package FinalDemo;final class Father{}
class Son extends Father{   //编译报错,不能继承final修饰的类}

在这里插入图片描述

2、修饰方法

final修饰方法,方法不可以重写,但是可以被子类访问 【前提:方法不是 private 类型】。

package FinalDemo;class Fu{public final void speak(){System.out.println("粑粑:不,你不想拉粑粑");}
}
class  Zi extends Fu{//直接编译失败,被final修饰的方法不能被重写
//    public void speak(){
//        System.out.println("熊孩子:粑粑,我想拉粑粑");
//    }
}public class EmbellishMethod {public static void main(String[] args) {Zi z =new Zi();z.speak();  //访问final修饰的方法}
}运行结果: 粑粑:不,你不想拉粑粑

3、修饰变量

final用得最多的时候就是修饰变量

如果被final修饰的是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

package FinalDemo;public class EmbellishVariable {public final int a=1;public void method(){// final修饰基本数据类型的变量,其数值一旦在初始化之后便不能更改a=2;// final修饰引用类型的变量,其初始化之后便不能再让其指向另一个对象final String str=new String();str=new String();}
}

在这里插入图片描述
以上是final关键字的基本用法,很多同学都看的没有激情,好的,从下面开始我们慢慢来深入final关键字…

4、final变量修饰变量(成员变量、局部变量)

首先,变量分为成员变量和局部变量

4、1 final修饰成员变量:

1、成员变量必须在定义时或者构造器中进行初始化赋值

public class FinalAndVariable {public int t; //编译成功public final int b; //编译失败public final int c = 1; //编译成功
}

在这里插入图片描述
如果在定义成员变量的时候不初始化行不行呢,答案是可以,对博主没有写错是可以的,前提是在构造方法中将成员变量b进行初始化,代码如下:

public class FinalAndVariable {public int t;public final int b; //编译成功public final int c = 1; //编译成功public FinalAndVariable() {  //构造方法b=2;  //在构造方法中将成员变量b进行初始化}
}

在这里插入图片描述
2、final变量一旦被初始化赋值之后,就不能再被赋值了。【注意是成员变量】

package FinalDemo;
//如果被final修饰的是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
// 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。public class EmbellishVariable {public final int a=1;public void method(){// final修饰基本数据类型的变量,其数值一旦在初始化之后便不能更改a=2; //编译失败// final修饰引用类型的变量,其初始化之后便不能再让其指向另一个对象final String str=new String();str=new String();//编译失败}
}

4、2 final修饰局部变量:

1、只需要保证在使用之前被初始化赋值即可

5、final变量和普通变量的区别

为了加深各位对final变量和普通变量之间的区别,先来做一道程序:

public class FinalAndVariableDifference {public static void main(String[] args)  {String a = "helloWord1";final String b = "helloWord";String F = "helloWord";String c = b + 1;String e = F + 1;System.out.println((a == c));System.out.println((a == e));}
}

猜想一下上面程序运行的结果…估计很多小白童鞋要GG,运行结果如下:

true
false

大家可以先想一下这道题的输出结果,Why?显然这里就体现了final变量和普通变量的区别了!

当final变量修饰基本数据类型以及String类型时,编译期间能知道它的确切值时,编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。有C语言基础的童鞋应该都知道这种骚操作类似C语言的宏替换。

分析上面代码:由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的值(这种情况我们成为编译器的优化)。而对于变量F的访问却需要在运行时才能连接确定,所以返回false

注意:只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,那是不是只要是被final修饰的变量就会进行优化呢?当然不是!比如下面的这段代码就不会进行优化:

final可以在编译(类加载)时初始化,也可以在运行时初始化,初始化后不能被改变。下面这个程序便是在运行时初始化的典型事例…

public class FinalAndVariableDifference {public static void main(String[] args)  {String a = "helloWord2";final String b = getHello();  //尽管是final修饰,但不会进行优化,因为它要运行时初始化才被确定String c = b + 2;System.out.println((a == c));}public static String getHello() {return "helloWord";}
}运行结果:false

被final修饰的变量不一定会进行优化,优化的前提是编译时就已经能够确定!

除此之外,还必须要清楚的一点是:被final修饰的引用变量一旦初始化赋值之后指向的对象不可变但该对象的内容可变

怎么理解呢?来看一个程序:

class AA{int i=1;
}
public class EmbellishQuote {public static void main(String[] args) {final AA a = new AA();  //final修饰引用变量a=new AA(); //编译失败,说明被final修饰的引用变量一旦初始化赋值之后指向的对象不可变System.out.println( ++a.i ); //输出值为2,说明内容可变}
}//运行结果: 2

6、final与static的藕断丝连

到这里,是否对final重新认识了?当然final的使用始终离不开static字眼,二者可谓藕断丝连,常常繁见,那么一起来看看下面这个程序吧。

package Demo;class FinalDemo {public final double i = Math.random();public static double t = Math.random();
}public class DemoDemo {public static void main(String[] args) {FinalDemo demo1 = new FinalDemo();FinalDemo demo2 = new FinalDemo();System.out.println("final修饰的  i=" + demo1.i);System.out.println("static修饰的 t=" + demo1.t);System.out.println("final修饰的  i=" + demo2.i);System.out.println("static修饰的 t=" + demo2.t);System.out.println("t+1= "+ ++demo2.t );
//      System.out.println( ++demo2.i );//编译失败}
}
运行结果:final修饰的  i=0.7282093281367935static修饰的 t=0.30720545678577604final修饰的  i=0.8106990945706758static修饰的 t=0.30720545678577604t+1= 1.307205456785776

这是啥咩…不是说好的final修饰基本数据类型的变量时,则其数值一旦在初始化之后便不能更改咩?为啥子这里final修饰的基本类型值反而不一致,static修饰的基本类型却一致?

是的,我是在前面说过这些话,但是你注意到了这句话的核心前提咩:final修饰基本数据类型的变量时,则其数值一旦在初始化之后便不能更改。

是的,已经很明显了,上面代码中被final修饰的变量是在运行时才初始化的,并没有在编译期就被初始化!由于值为随机数,运行时被初始化是不确定的一个值,也就是个随机数,仅仅当运行之后被初始化之后他的值才会不变!

至于static修饰的变量没有发生变化是因为static作用于成员变量只是用来表示保存一份副本,其不会发生变化。怎么理解这个副本呢?其实static修饰的在类加载的时候就加载完成了(初始化),而且只会加载一次也就是说初始化一次,所以不会发生变化!

关于static关键字,详细的讲解可以看这篇深入理解static关键字

7、关于final修饰参数的争议

到这里,我相信各位都对final有一个大概的系统性了解了,那么我们一起来回到关于开篇的问题。

关于不认同网上流传的”方法中不需要改变作为参数的对象变量时,使用final进行声明,可以防止你无意的修改而影响到调用方法外的变量“这句话,首先要想理解这句话可以先看下面final修饰的程序1代码:

package FinalDemo;class Parameter{public void method(final int a){  //使用final修饰参数//      a++;  //编译失败//      a=1;  //编译失败System.out.println(a);}
}
public class ParameterAndFinal {public static void main(String[] args) {Parameter par=new Parameter();int a=2;par.method(a);int b=4;par.method(b);}
}
运行结果: 
2
4

1、至于上面代码中注释的代码编译失败,我相信各位都能知其原因!
2、运行结果,我们也知道,方法是运行时才初始化的,执行到 int b=4par.method(a)方法以及结束,再到par.method(b)的时候,又重新初始化了,所以打印结果如上。
3、要想理解还得看没有final修饰的程序2

package FinalDemo;class Parameter{public void method(int a){  //不使用final修饰参数a++;a=6;System.out.println(a);}
}
public class ParameterAndFinal {public static void main(String[] args) {Parameter par=new Parameter();int a=999;par.method(a);int b=777;par.method(b);}
}
运行结果: 6  6

看完之后发现,确实,使用final修饰的程序1中,因为使用了final,所以不会影响到你在外部传递的参数,而不使用final修饰的程序1中,因为没使用final,不管你传递啥,没无效,不得不说确实是验证了网上的那句话…

但是对于下面这个程序来说,就不怎么管用了喔

package FinalDemo;class BB {public void method(final StringBuffer buffer) {buffer.append("波波小菜鸡");}
}
public class ParameterAndFinal {public static void main(String[] args)  {BB b = new BB();StringBuffer buffer = new StringBuffer("乾坤未定你我皆是");b.method(buffer);System.out.println(buffer.toString());}}//运行结果:  乾坤未定你我皆是波波小菜鸡

为啥子我要说不管用了捏?因为你可是试着把final去掉再次运行,你会发现,结果同样都是: 乾坤未定你我皆是波波小菜鸡…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

axios vue 动态date_Web前端Vue系列之-Vue.js 实战

课程简介:课程目标:通过本课程的学习,让大家掌握Vue.js的进阶知识并在项目中应用。适用人群:具有一定vue开发基础的开发人员。课程概述:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式Jav…

vue 组件 - 非单文件组件

一、定义组件 const school Vue.extend({name: xuexiao, // ----------------------------> 指定组件在开发者工具中显示的名字template: // ----------------------------> 模板<div>... 此处是结构</div>,data() { // ---------------------------->…

matlab安装好 启动总是闪退_在Ubuntu16.04下安装MATLAB2017b

1. 前言最近在折腾Ubuntu系统的高端机子&#xff0c;matlab这家伙的交互和可视化太方便了&#xff01;于是想在Linux下安装matlab&#xff0c;在各个版本中&#xff0c;matlab2017的性价比是非常高的&#xff0c;因此选择安装介个。阅读了很多帖子&#xff0c;综合找到几个靠谱…

vue 脚手架

一、 脚手架 初始 全局安装脚手架 npm i -g vue/cli切换到项目根目录&#xff0c;使用 vue create 项目名称 创建项目使用 npm run serve | yarn serve 启动项目 如果中途卡顿 使用 npm 淘宝镜像 npm config set registry --> https://registry.npm.taobao.orgvue 隐藏了…

这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析

前言 package com.jvm.classloader;class Father2{public static String strFather"HelloJVM_Father";static{System.out.println("Father静态代码块");} }class Son2 extends Father2{public static String strSon"HelloJVM_Son";static{Syste…

bigdecimal js 判断等于0_为啥阿里禁用BigDecimal的equals方法做等值比较

BigDecimal&#xff0c;相信对于很多人来说都不陌生&#xff0c;很多人都知道它的用法&#xff0c;这是一种java.math包中提供的一种可以用来进行精确运算的类型。很多人都知道&#xff0c;在进行金额表示、金额计算等场景&#xff0c;不能使用double、float等类型&#xff0c;…

git提交到github总是要输入密码_GitHub不为人知的秘密

本来想叫《GitHub骚操作》的&#xff0c;发现相关的文章已经有很多&#xff0c;而且和我本章要讲的内容完全不同&#xff0c;所以就换了这个也算贴切的标题。起因之前写过一篇文章《VM Manager 插件分享》&#xff0c;事后我发现有个地方不对劲&#xff01;看之前文章标题大家应…

MyBatis中大于号以及小于号的表达方式

mybatis使用的是xml格式的文件。使用>和<号的时候&#xff0c;会存在与xml的标签的规范冲突。 1.场景还原 在实际项目中&#xff0c;有很多需求需要通过设定一个具体的时间段来搜索或过滤所需的数据&#xff0c;今天笔者就mybatis中时间比较涉及到的大于&#xff0c;小于…

ug冲模标准件库_昆山兴模lt;携手gt;武汉益模,打通冲模“智能设计+精益管理”的最后一道关卡...

武汉益模科技股份有限公司是国内领先的工业互联网及智能制造的解决方案提供商&#xff0c;为模具、装备、军工、汽车、家电及等有柔性化生产需求的工厂提供专业的智能设计/信息化管理/智能加工/数字化工厂等工业软件、工业机器人自动化以及智能装备&#xff0c;拥有麦格纳、安波…

简述网络调研的作用_利用龙伯球透镜天线提升高铁4G网络覆盖

透镜天线&#xff0c;一种能够通过电磁波&#xff0c;将点源或线源的球面波或柱面波转换为平面波从而获得笔形、扇形或其他形状波束的天线。通过合适设计透镜表面形状和折射率 n&#xff0c;调节电磁波的相速以获得辐射口径上的平面波前。透镜天线吸收了许多光信息工程技术&…

SQLIntegrityConstraintViolationException: 异常解决

SQLIntegrityConstraintViolationException: Duplicate entry ‘xxx’ for key yyyzzz’异常解决 一. 异常现象 在做Java Web项目操作数据库添加数据的时候&#xff0c;突然发现曝出如下图所示异常&#xff1a; Caused by: java.sql.SQLIntegrityConstraintViolationExceptio…

一步怎么测量图片_测量不容易?15套测量仪器实操手册+自动计算表格,自学也可以...

测量不容易&#xff1f;15套测量仪器实操手册自动计算表格&#xff0c;自学也可以很多施工羡慕测量工资高&#xff0c;但是测量工资高也就意味着责任大&#xff0c;施工在休息的时候测量就下工地了&#xff0c;施工聚会的时候&#xff0c;测量在埋头苦算。如果施工想要干测量该…

Java 中判断一个字符串是否包含另外一个字符串的方法

方法一&#xff1a;indexOf(String s) 可以配合indexOf(String s)的使用&#xff0c;如果包含&#xff0c;返回的值是包含该子字符串在父类字符串中起始位置&#xff1b;如果不包含必定全部返回值为-1 public void test02() {String str1"张三";String str2"是…

速看!销冠高效给客户群发消息的秘诀

你是不是也有过这样的疑问&#xff1a;明明都是给客户群发消息&#xff0c;为什么别人的成交率那么高&#xff0c;自己却效果一般呢&#xff1f; 今天就给大家分享销冠常用的高效群发消息秘诀&#xff0c;让大家都能更好地与客户进行沟通&#xff0c;提高成交率&#xff01; …

不显示_电脑不显示桌面图标怎么办?

在现在这个社会时代中&#xff0c;人们对电脑的使用频率非常的高&#xff0c;电脑可以说已经成为了大家在生活中不可或缺的必备品。但是在使用电脑过程中的时候也都容易出现故障。那么&#xff0c;若碰上 电脑开机后只显示桌面的背景而没有任何程序和应用的情况&#xff0c;莫急…

Xshell 的基本使用

软件长这样 Xshell 链接地址 一、输入 ifconfig 查看 linux ip 地址 二、远程连接服务器 三、测试连接

Java中String类的concat方法___java的String字符串的concat()方法连接字符串和“+“连接字符串解释

Java中String类的concat方法 在了解concat&#xff08;&#xff09;之前&#xff0c;首先需要明确的是String的两点特殊性。 长度不可变值不可变 这两点从源码中对String的声明可以体现&#xff1a; private final char[] value ;其中final对应值的不可更改的特性&#xff1b…

大于小于优化_架构 - 以MySQL为例,详解数据库索引原理及深度优化

一、摘要本文以MySQL数据库为研究对象&#xff0c;讨论与数据库索引相关的一些话题。特别需要说明的是&#xff0c;MySQL支持诸多存储引擎&#xff0c;而各种存储引擎对索引的支持也各不相同&#xff0c;因此MySQL数据库支持多种索引类型&#xff0c;如BTree索引&#xff0c;哈…

c++byte数组和文件的相互转换_终于!word、excel、ppt文件相互转换技巧来了!

不知道大家在用Office软件的时候&#xff0c;有没有遇到过这样的问题。做了个Word文档总结&#xff0c;却需要转换成PPT上台汇报&#xff1b;做了个Word表格统计&#xff0c;却需要转换成Excel进行分析&#xff1b;做了个Excel图表分析&#xff0c;却需要放到Word或PPT上&#…

java多线程之ThreadLoal详解

一、ThreadLocal简介 多线程访问同一个共享变量时特别容易出现并发问题&#xff0c;特别是在多个线程需要对一个共享变量进行写入时。为了保证线程安全&#xff0c;一般使用者在访问共享变量时需要进行适当的同步 同步一般是通过加锁来实现的,但这对用户有一定要求,加重了使用…