Java中final关键字解析

来源:互联网 发布:蚁群算法 编辑:程序博客网 时间:2024/06/08 15:52

final关键字

final修饰方法

  • final修饰表示“最终的,最后的”
  • final修饰方法,能够被重载(多个方法,有相同名字),但是在继承该类后,不能被覆盖重写,只有我一个。
  • 能够重写继承类的方法,首先需要能够继承此方法。
    如果父类中使用final修饰方法,该方法不能被子类继承,因此,也不能够重写。此时可以在子类中定义相同的方法名和参数,但不是重写,两者不一样。

final修饰类

final修饰类,不能被继承

final修饰变量

final修饰的变量,在首次初始化后,将不能再被改变。
引用变量指向的是实际的对象,但其存储的是所指向对象的地址,因此,其值不能修改并不意味着其所指向的对象不能修改 例如:

public static void main(String[] args) {final char[] values = new char[5];values[0] = '1';values[1] = '2';values[2] = '3';values[3] = '4';values[4] = '5';System.out.println(new String(values));  // 输出: 12345 values[0] = '5';System.out.println(new String(values));  // 输出: 52345  values指向值被改变char[] newValue = new char[5];// values = newValue;   // 报错使用final修饰,不能更改}
  • 说明
    Values存储的是所指向对象的地址,不能被改变,不能再被赋予新的地址,
    但是对象中所处存储的值,是可以改变的。其值不能修改,但是其所指向的对象中的成员是可以修改的。

疑问:final修饰的变量,存储在内存的什么区。

String类与StringBuilder类中的final

在String类与StringBuilder类中,String类的不可变,与StringBuilder的可变性,与fianl关键字有很大关系。
String类与StringBuilder类都维护了一个数组,但是String类中该数组采用

private final char value[];

StringBuilder中采用

char[] value;

使用final修饰的不可变,但也不仅仅是这个原因,因为final修饰后只是value指向的地址不能改变,并不代表它所指向的对象中的属性不能改变,也就是说不代表value[]数组中的值不能改变。关键问题在于,String类中没有提供改变数组中值得方法,所以造就了String的不可变。

从类加载过程的准备阶段分析final修饰变量的不同

  • 类加载过程,主要分为加载、验证、准备、解析,初始化,五个阶段。
  • 在准备阶段会将,final修饰的变量,进行赋初始值,这里不同于一般变量,使用final修饰的变量,在该阶段直接被赋予用户指定的值,而一般变量初始值为零值。

以下为类加载过程准备阶段的说明:

  • 准备,是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。
  • 这时候进行内存分配的仅包括类变量、被static修饰的变量,不包括实例变量。实例变量在对象实例化时随着对象一起分配在Java堆中。
  • 这里不同时机分配不同的值,就造成了被static修饰的变量与实例变量,在访问时的区别,两者的加载时机不同。
  • 这里的设置类变量的初始值,“通常情况”下是数据类型的零值:
public static int value = 123;

在准备阶段过后的初始值为0,不是123。把Value赋值为123的putstatic指令是程序被编译后,存放于类构造器<clinit>()方法中,所以把value赋值为123将会在初始化阶段才会执行。

  • “特殊情况”,如果类字段的属性表中存在ConstantValue属性,那在准备阶段变量Value就会被初始化ConstantValue属性所指定的值
public static final int value = 123;
  • 编译时Javac会为value生成ContstantValue属性,在准备阶段虚拟机根据ContstantValue的设置将value复制为123。

这也是从类加载过程,分析final修饰变量的特殊之处。

参考

《深入理解Java虚拟机》

原创粉丝点击