1. 关于final

  • final修饰的类不能被继承
  • final修饰的方法不能被重载(可以重写)
  • final修饰的变量不能被改变(修饰引用变量时不能改变引用所指向的对象,但是可以修改引用指向对象的内容)

2. 关于abstract

  • abstract用来修饰类、接口和方法,接口即使没有用abstract修饰也会隐式的指明为abstract
  • abstract修饰的类为抽象类,不能被实例化,因此只能通过实例化其子类来使用该抽象类

3. 总结

  • 由于final修饰的类不能别继承
  • 但是abstract修饰的类必须被继承后才能使用,否则没有意义
  • 所有final和abstract不能同时修饰一个类

2. final修饰的变量如何初始化

1. 只有final修饰的变量

  • 在定义处直接通过”=”进行赋值
  • 通过类的构造方法进行赋值,但是要注意类中所有的构造方法都必须对final修饰的变量进行赋值
  • 在非静态块中初始化```java public class Demo02 { private final int a; {
    1. a = 10;
    } } ```

2. 同时有static和final修饰的变量

  • 只能在定义处通过”=”赋值(不准确,下面有补充)
  • 原因:
    • static修饰的变量可以不赋初值,是在构造器之前完成初始化,其执行时机是在类加载时执行,并且会被初始化为0/null,后续过程中如果发现用户给变量赋了初值,则会改为用户赋的值
    • final修饰的变量可以不赋初值,但必须初始化,在运行时被初始化,可以直接通过”=”初始化,也可以通过构造方法初始化
    • static final修饰的变量在javac(编译)时生成ConstantValue属性,在类加载过程中通过ConstantValue属性值给该字段赋值ConstantValue属性没有默认值,只能通过”=”显式的赋值
  • 理解:
    • static修饰的变量可以不赋初值,但是会被初始化为0/null,并且在构造器之前完成初始化
    • final修饰的变量如果不赋初值则必须在所有的构造器中为其初始化
    • 所以static final修饰的变量必须通过”=”赋值,否则将无法初始化,而final修饰的变量必须初始化,所以只能在定义处通过”=”赋值
  • 补充:static final修饰的变量可以在静态块中初始化```java public class Demo02 { private static final int b; static {
    1. b = 20;
    } } ```

Java程序的初始化规则

1. 变量的初始化规则,一下规则优先级依次递减

  • 静态对象(变量)优先于非静态对象(变量),其中静态对象(变量)只初始化一次,而非静态对象(变量)可能会初始化多次
  • 父类优先于子类进行初始化
  • 按照成员变量的定义顺序进行初始化。即使变量定义散布于方法定义,它们依然在任何方法(包括构造方法)被调用之前初始化

2. Java程序初始化不同模块的执行顺序

  1. 父类的静态常量
  2. 父类静态代码块
  3. 子类静态常量
  4. 子类静态代码块
  5. 父类非静态变量
  6. 父类非静态代码块
  7. 父类构造函数
  8. 子类非静态变量
  9. 子类非静态代码块
  10. 子类构造函数

public final 修饰的变量建议加上static

  1. public class A{
  2. public static final int num = 10;
  3. // ...
  4. }
  • 如果不加static,则在其他类中要使用num值就必须先new对象再通过对象来拿属性值,而new对象会浪费内存
  • 加上static可以节省内存:
    • 不需要new对象直接通过A.num拿值
    • static是共享变量,在内存中只会存在该变量的一份存储
  • final修饰的变量不可变,因此不存在并发冲突问题

**在对象数组中 实际存放的不是对象本身,而放的是对象引用的地址。 **