关于 final 关键字 && 类的初始化顺序
1、final 关键字
1.1、final 修饰变量和对象
-
当用 final 修饰对象,对于基本类型,final 使数值恒定不变
。 -
对于对象引用,final 使引用恒定不变。一旦引用被初始化指向了某个对象,它就不能改为指向其他对象
。 但是,对象本身是可以修改的
,Java 没有提供将任意对象设为常量的方法。 -
在参数列表中,
将参数声明为 final ,意味着:在方法中不能改变参数指向的对象或基本变量
。
示例:
package com.ttt.gof;
import com.alibaba.fastjson.JSON;
import com.qiuwan.gof.entity.User;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TestFinal {
public static void main(String[] args) {
User user = new User();
user.setUserId(123);
user.setUserName("张三");
final User finalUser = user;
log.info("finalUser = {}", JSON.toJSONString(finalUser));
user.setUserName("李四");
log.info("user = {}", JSON.toJSONString(user));
log.info("finalUser = {}", JSON.toJSONString(finalUser));
finalUser.setUserName("王五");
log.info("finalUser = {}", JSON.toJSONString(finalUser));
// finalUser = new User(); // 这种写法报异常 Exception: Cannot assign a value to final variable 'finalUser'
// finalUser = user; // 这种写法报异常 Exception: Cannot assign a value to final variable 'finalUser'
/*********************************/
System.out.println();
/*********************************/
Long rLong = 10L;
final Long mLong = rLong;
log.info("mLong = {}", mLong);
rLong = 20L;
log.info("rLong = {}", rLong);
log.info("mLong = {}", mLong);
// mLong = 20L; // 这种写法报异常 Exception: Cannot assign a value to final variable 'mLong'
// mLong = rLong; // 这种写法报异常 Exception: Cannot assign a value to final variable 'mLong'
/*********************************/
System.out.println();
/*********************************/
String str = "张三";
final String fStr = str ;
final String f_Str = "王五";
log.info("fStr = {}", fStr);
log.info("f_Str = {}", f_Str);
str = "李四";
// fStr = str; // 这种写法报异常 Exception: Cannot assign a value to final variable 'fStr'
// f_Str = str; // 这种写法报异常 Exception: Cannot assign a value to final variable 'f_Str'
// fStr = "马六"; // 这种写法报异常 Exception: Cannot assign a value to final variable 'fStr'
// f_Str = "马六"; // 这种写法报异常 Exception: Cannot assign a value to final variable 'f_Str'
log.info("fStr = {}", fStr);
log.info("f_Str = {}", f_Str);
}
}
打印结果:
15:02:51.529 [main] INFO com.ttt.gof.TestFinal - finalUser = {
"userId":123,"userName":"张三"}
15:02:51.538 [main] INFO com.ttt.gof.TestFinal - user = {
"userId":123,"userName":"李四"}
15:02:51.538 [main] INFO com.ttt.gof.TestFinal - finalUser = {
"userId":123,"userName":"李四"}
15:02:51.538 [main] INFO com.ttt.gof.TestFinal - finalUser = {
"userId":123,"userName":"王五"}
15:02:51.539 [main] INFO com.ttt.gof.TestFinal - mLong = 10
15:02:51.539 [main] INFO com.ttt.gof.TestFinal - rLong = 20
15:02:51.539 [main] INFO com.ttt.gof.TestFinal - mLong = 10
15:02:51.543 [main] INFO com.ttt.gof.TestFinal - fStr = 张三
15:02:51.543 [main] INFO com.ttt.gof.TestFinal - f_Str = 王五
15:02:51.543 [main] INFO com.ttt.gof.TestFinal - fStr = 张三
15:02:51.543 [main] INFO com.ttt.gof.TestFinal - f_Str = 王五
Process finished with exit code 0
1.2、final 修饰的方法
-
final 修饰的方法,其子类无法通过覆写而改变方法的行为
。这是出于继承的考虑,确保方法的行为不会因为继承而改变。只有在为了明确禁止覆写方法时,才使用 final. -
类中所有的 private 方法都隐式的指定为 final
。因为不能访问 private 方法,所以不能覆写它。可以给 private 方法添加 final 修饰,但是并不能给方法带来额外的含义。
1.3、final 类
-
当一个类是 final (final 关键字在类定义之前),就意味着它不能被继承
。之所以这么做,是因为类的设计就是永远不需要改动,或者是出于安全考虑不希望它有子类。 -
final 类的属性可以根据个人选择是或不是 final。这同样适用于不管类是否是 final 的内部 final 属性。然而,
由于 final 类禁止继承,类中所有的方法都被隐式地指定为 final,所以没有办法覆写它们
。你可以在 final 类中的方法加上 final 修饰符,但不会增加任何意义。
2、类的初始化顺序
静态成员
>> 静态代码块(多个静态代码块时,按代码顺序)
>> 普通成员
>> 非静态代码块
>> 构造函数
示例:
package com.ttt.gof;
public class Insect {
private int i = 10;
protected int j;
// 父类构造函数
Insect() {
System.out.println("i = " + i + ", j = " + j);
j = 40;
}
// 静态变量
private static int x1 = printInit("static Insect.x1 init");
static int printInit(String s) {
System.out.println(s);
return 58;
}
// 父类代码块
{
System.out.println("Insect ordinary coding chunk");
}
static {
System.out.println("Insect static coding chunk");
}
}
package com.ttt.gof;
public class Beetle extends Insect {
private int k = printInit("Beetle.k.initialized");
// 子类构造函数,最后执行
public Beetle() {
System.out.println("k = " + k);
System.out.println("j = " + j);
}
// 子类静态变量
private static int x2 = printInit("static Beetle.x2 init");
// 子类代码块
{
System.out.println("Beetle ordinary coding chunk");
}
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle beetle = new Beetle();
}
}
控制台打印结果:
static Insect.x1 init
Insect static coding chunk
static Beetle.x2 init
Beetle constructor
Insect ordinary coding chunk
i = 10, j = 0
Beetle.k.initialized
Beetle ordinary coding chunk
k = 58
j = 40
.