小议Java中final关键字使用时的注意点

作者:zeyu203 时间:2022-12-04 08:40:45 

final 类
final 类不能被继承,同时,一旦用 final 修饰了类,也就意味着 final 类中的所有方法都被隐式地指定为 final 方法

final 方法
在类继承的过程中,对于父类中的 final 方法,子类不能修改和覆盖。
private 方法都被隐式指定为 final 方法。
有两个原因使用 final 方法:

  • 锁定方法,防止被子类修改其含义

  • 在早期的 java 实现版本中,final 方法被实现为内嵌调用,可以提升性能

final 变量
final 关键字用来修饰变量是最常用的用法,如果修饰成员变量,则必须在定义时或者构造方法中初始化,且一经初始化此后不能再进行任何赋值。
针对基本类型和类对象有着不同的含义:

  • 对于基本类型,final 变量一经初始化,此后不能再改变该变量的值

  • 对于类对象,已经初始化后,不能让这个变量再指向另一个对象,但他指向的对象的内容是可以改变的

static final 域称为编译期常量,一般全部大写。

示例


class Glyph {
void draw() {
 System.out.println("Glyph.draw()");
}
Glyph() {
 System.out.println("Glyph() before draw()");
 draw();
 System.out.println("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph {
private int redius = 1;
RoundGlyph(int r) {
 radius = r;
 System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw() {
 System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}
public class RolyConstructors {
public static void main(String[] args) {
 new RoundGlyph(5);
}
}

输出结果:


Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5

上面的代码展示了类初始化过程以及隐藏的灾难性问题。
main 函数中以参数 5 调用 RoundGlyph 的构造函数创建了 RoundGlyph 对象,在 RoundGlyph 构造方法执行前调用了其父类 Glyph 的构造方法。
然而,在父类 Glyph 的构造方法中调用了 draw 方法,由于多态性,此时实际上调用了子类的 draw 方法,然而子类的 redius 此时还没有通过构造器初始化,因此输出了:


RoundGlyph.draw(), radius = 0

这显然不是我们想要的结果,因此需要注意:

  • 用尽可能简单的方法初始化类成员

  • 在构造器中最好只调用 final 方法

第二条的原因是 final 不会应用多态性,因此可以保证调用的是当前对象的相应方法,而不是初始化工作还没有进行的子类的覆盖方法。

总结final的内存分配方式:
1.修饰变量:
通常情况下,final变量有3个地方可以赋值:直接赋值,构造函数中,或是初始化块中。
(1)初始化:
由于在java的语法中,声明和初始化是联系在一起的,
也就是说:如果你不显示的初始化一个变量,系统会自动用一个默认值来对其进行初始化。(如int就是0)
对于final变量,在声明时,如果你没有赋值,系统默认这是一个空白域,在构造函数进行初始化,
如果是静态的,则可以在初始化块。
(2)内存:
常量(final变量)和非final变量的处理方式是不一样的。
每一个类型在用到一个常量时,都会复制一份到自己的常量池中。
常量也像类变量(static)一样保存在方法区,只不过他保存在常量池。
(可能是,类变量被所有实例共享,而常量池是每个实例独有的。)
2.修饰方法:
保存在方法区,并且可以被函数代码直接替换,而不用等到执行时再决定具体是那个函数。
3.修饰类:
保存在方法区。

标签:Java,final
0
投稿

猜你喜欢

  • java格式化数值成货币格式示例

    2023-01-31 06:27:45
  • springmvc之获取参数的方法(必看)

    2023-12-20 09:25:59
  • 详解SpringCloud微服务之Rest

    2023-10-20 00:49:36
  • C#实现FTP上传文件的方法

    2021-11-13 10:46:56
  • struts2的国际化实现网站整体中英文切换实例代码

    2023-08-31 02:37:40
  • Android实现截屏功能

    2022-10-25 04:36:52
  • 简单了解Spring beanfactory循环依赖命名重复属性

    2023-10-27 19:39:14
  • Mybatis延迟加载的实现方式

    2023-08-19 11:07:32
  • Springboot如何使用mybatis实现拦截SQL分页

    2021-08-15 13:16:56
  • Android自定义View实现打字机效果

    2022-01-13 11:03:41
  • 为Android系统添加config.xml 新配置的设置

    2022-02-19 23:31:48
  • Java NIO实战之多人聊天室

    2022-02-28 15:05:00
  • Android进阶从字节码插桩技术了解美团热修复实例详解

    2022-05-27 18:06:07
  • SpringBoot 文件上传和下载的实现源码

    2021-05-28 14:12:46
  • SpringBoot参数校验的最佳实战教程

    2023-11-28 21:13:47
  • JAVA使用Gson解析json数据实例解析

    2021-08-23 14:50:56
  • 为spring get请求添加自定义的参数处理操作(如下划线转驼峰)

    2021-12-04 13:01:43
  • SpringBoot整合Mybatis自定义拦截器不起作用的处理方案

    2023-03-19 04:35:14
  • C#窗体间通讯的几种常用处理方法总结

    2021-10-26 05:48:49
  • Idea自动生成Entity实现过程详解

    2022-06-03 12:18:24
  • asp之家 软件编程 m.aspxhome.com