在Java中,final是一个保留字,它可以用来修饰类、方法和变量。final的含义是不可变或不可继承,具体的作用和用法如下:
final类:final类是指不能被其他类继承的类,例如String类就是一个final类。final类的所有方法都隐含地是final的,但是它的变量不一定是final的,除非显式地声明为final。final类的好处是可以提高性能和安全性,因为它避免了继承带来的多态性和动态绑定的开销,也防止了子类对父类的修改和扩展。
final方法:final方法是指不能被子类重写的方法,例如Object类的getClass方法就是一个final方法。final方法的好处是可以防止子类对父类方法的修改和覆盖,保证了父类方法的行为和逻辑的一致性。final方法也可以提高性能,因为编译器可以对final方法进行优化,例如内联等。
final变量:final变量是指只能被赋值一次的变量,它可以是局部变量、成员变量或静态变量。final变量的好处是可以保证变量的不可变性,避免了变量值的意外修改和错误,也方便了编译器的优化。final变量的赋值时机和方式有以下几种情况:
final变量在编译期间能确定其值的情况下,会被当作编译期常量使用,直接替换到使用的地方,不需要运行时确定。例如,final int a = 10; 这样的变量就是一个编译期常量,它的值在编译时就已经确定,不会在运行时分配内存空间和赋值。编译期常量的好处是可以提高性能和节省内存,也可以用来定义接口中的常量,因为接口中的变量默认都是public static final的。
final变量在编译期间不能确定其值的情况下,会在运行时进行初始化赋值,不能再次赋值。例如,final int b = new Random().nextInt(); 这样的变量就是一个运行时常量,它的值在编译时无法确定,只能在运行时分配内存空间和赋值。运行时常量的好处是可以保证变量的唯一性和不可变性,也可以用来定义类中的常量,因为类中的变量可以根据不同的构造方法进行不同的初始化。
final变量的类型是引用类型时,其指向的对象的内容是可变的,但是不能再指向其他对象。例如,final String c = "hello"; 这样的变量就是一个引用类型的final变量,它指向的是一个字符串对象,这个对象的内容是可以改变的,例如可以通过反射等方式修改它的值,但是这个变量不能再指向其他的字符串对象,例如不能再写c = "world"; 这样的语句。引用类型的final变量的好处是可以保证变量的引用不变,避免了引用的混乱和错误,也可以用来定义不可变类,因为不可变类的所有成员变量都必须是final的。
下面是一段代码,用来说明final变量的用法和效果:
// 编译期常量,直接替换为"hello"
// 运行时常量,运行时赋值
// 引用类型的final变量,指向的对象内容可变,但不能再指向其他对象
// x和a指向的是同一个字符串常量
// y和b指向的是不同的字符串对象
// 比较x和a的引用,结果为true
// 比较y和b的引用,结果为false
// 比较x和c的引用,结果为true
// 比较y和c的引用,结果为false
// 试图修改a的值,编译错误,不能对final变量赋值
// 试图修改c的值,编译错误,不能对final变量赋值
// 试图修改c指向的对象的值,运行时错误,字符串对象是不可变的
这段代码的运行结果为什么一个是true一个是false,是因为final变量b在编译期间就被替换为"hello",所以x和a指向的是同一个字符串常量,而c在运行时才初始化,所以y和a指向的是不同的字符串对象。这也说明了final变量的赋值时机和方式对于变量的引用和值有着不同的影响。