文章目录

  • 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去掉再次运行,你会发现,结果同样都是: 乾坤未定你我皆是波波小菜鸡…

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

  1. java static关键字_好程序员Java教程分享static关键字的理解

    好程序员Java教程分享static关键字的理解,static关键字含义可以理解为静态的. 1. 当其修饰属性时,该属性为整个类公有,所有的对象操作的都是同一个静态属性.所以调用时应该使用类名去调用, ...

  2. 程序员应如何理解多态

    面向对象编程领域有个非常重要的概念,那就是多态,但是你真的理解这到底是什么意思吗?程序员该如何理解多态? 英文中的多态 多态一词其英文为"polymorphism",在讲解多态之前 ...

  3. 上帝视角:程序员为什么需要理解 CPU?

    来源 | 码农的荒岛求生(ID:escape-it) 可能有的同学会问,程序员写代码就好了,为什么需要去理解CPU啊?不嫌累啊?啊?啊?你倒是说啊. 计算机系统 != 汉堡包 在之前的文章中我把计算机 ...

  4. c++ include 路径_程序员应如何理解include

    相信很多同学在学习C/C++后都有这样的疑问,#include这句话到底是怎么意思?这句话的背后隐含了什么?我们常用的stdio.h存放在了哪里? 这篇文章就来解答这个问题. 谁来处理头文件 有上述疑 ...

  5. 【职场】你做程序员,真的是因为热爱吗?

    今天的这一期,我们不聊技术,我们来聊一聊我们做程序员的初心,以及如何才能高效的学习编程和技术~ 01 你的初心 前一阵子,圈子里的一位知名的博主从老东家离职了,离职的视频看了一遍,尤其是其中他的一句话 ...

  6. 想要成为真正优秀的程序员是不是真的很难?

    很多人认为要想成为一名优秀的程序员,那就需要一天24小时每天不断地编程--睁开眼睛要编程,闭上眼睛睡觉的时候还要梦到编程--我认为这是一种矫枉过正的方法.沿着这条路走,只会让你精疲力尽,犹如夸父逐日一 ...

  7. 一有问题,就想依靠别人,这根本不能算程序员。真的是代码民工。

    若想找老师,或者是想找人问,这本身就是不对的,程序员是最好的职业,前提是合格的程序员,现在很多人,一有问题,就想依靠别人,这根本不能算程序员.真的是代码民工.

  8. 程序员职业生涯真的很短吗?

    点击蓝字 关注我们 程序员职业生涯真的很短吗?是吃青春饭吗?35+ 岁真的会被优化吗?--在某乎上一搜"程序员",全是这类回答. 对于程序员,年龄真的是最大的威胁吗?其实并不是! ...

  9. Python程序员必须深刻理解的几个Warning

    Python程序员必须深刻理解的几个Warning 在Python编程中,很多时候我们会看到一些Warning输出,这些信息通常是针对我们的代码中存在的问题或潜在的风险.但是有时候我们并不希望看到这些 ...

最新文章

  1. 案例|数据中心UPS电源系统割接实施方案
  2. 编写并调试一个单道处理系统的作业调度模拟程序_操作系统系列(2):操作系统发展历史...
  3. Python中几个操作列表的内置函数filter(),map(),reduce(),lambda
  4. .net加载失败的程序集重新加载
  5. Linux的常用网络命令
  6. java optional 用法_理解、学习与使用Java中的Optional
  7. XTU1340Wave
  8. 暴雪战网怎么修改服务器,战网昵称修改服务
  9. IP/24是什么意思?
  10. 名侦探柯南之零的执行人
  11. 如何用U盘启动做系统启动盘,如何重装系统
  12. 蓝桥杯 Python 练习题 数字游戏
  13. style.left和offsetLeft 用法
  14. 诺基亚e65 ucweb 6.7正式免签名下载
  15. 郭德纲对18岁郭麒麟说的话,江湖阅历,字字珠玑,堪称郭氏家训
  16. java开发系统内核:让内核从严重错误中恢复
  17. RuntimeError: CUDA error: an illegal memory access was encountered的解决方法
  18. InfluxDB CQ时间偏移
  19. python之禅中文-python之禅怎么打出来
  20. 计算机摄影比赛,计算机与信息学院影动我心摄影大赛策划.ppt

热门文章

  1. linux 星号 通配符,如何在bash中转义通配符/星号字符?
  2. sklearn的train_test_split
  3. [转载] python元组 tuple
  4. 将八进制数制转换为二进制,十进制和十六进制数制
  5. Java类class isAnnotation()方法及示例
  6. stl string 函数_使用C ++ STL中的string :: append()函数将文本追加到字符串
  7. Everything是如何搜索的
  8. 局域网在线监控设备扫描工具V1.0软件说明
  9. MXNet结合kubeflow进行分布式训练
  10. 题解P3745期末考试