Java 面向对象 final关键字
final关键字可以用来修饰类, 成员变量/局部变量,方法,形参
final修饰类
final class Person {
    
}
final`修饰的类,会成为一个最终类,即不能被继承,但是该类可以继承父类和实例化
public class Test {
    public static void main(String[] args) {
		
    }
}
class Man {
}
final class Person extends Man {
}
class Student extends Person{
}
上面的代码,会运行异常:java: 无法从最终Person进行继承
final修饰方法`,不能修饰构造方法(final方法是约束子类不能覆盖,但是构造方法本身不允许子类继承,只能被重写)
class Person {
    final public String work() {
        return "工作";
    }
}
final修饰的方法,无法被子类重写(override),可以被继承
class Person {
    final public String work() {
        return "工作";
    }
}
class Student extends Person{
    public String work() {
        return "学习";
    }
}
上面的代码,会运行异常:java: Student中的work()无法覆盖Person中的work() 被覆盖的方法为final
final修饰成员变量
final修饰的属性又称为常量,一般用XX_XX_XX来进行命名
- 
final修饰的普通属性在定义时,必须赋予初始值- 
直接赋值 class Person { final public double PI = 3.14; }
- 
构造器 class Person { final public double PI; public Person(double pi) { this.PI = pi; } }
- 
代码块 class Person { final public double PI; { PI = 3.14; } }
 
- 
- 
final修饰的静态属性在定义时,必须赋予初始值- 
直接赋值 class Person { final static public double PI = 3.14; }
- 
静态代码块 class Person { final static public double PI; static { PI = 3.14; } }
 
- 
- 
final修饰的基本类型变量,变量不可改变
- 
final修饰的引用类型变量,引用本身不可改变,但是被引用的值可以被修改
class Student{
    private String name;
    public Student(String name) {
        this.name = name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return this.name;
    }
}
class Person {
    final Student student = new Student("smile");
    public void run() {
        System.out.println("初始值" + student);
        student.setName("易文杰");
        System.out.println("修改后的值" + student);
    }
}
上面代码,会输出初始值smile 修改后的值易文杰 表示:引用类型变量,引用本身不可改变,被引用的值可以被修改
class Person {
    final public int age = 20;
    Person(int age) {
        this.age = age;
    }
}
上面代码,会运行异常Cannot assign a value to final variable 'age'
final`修饰局部变量,在定义时,该变量可以不被直接初始化,但是在使用该变量之前,该变量必须完成初始化
class Person {
    public void run() {
        final int AGE;
        
        final String NAME;
        
        NAME = "smile";
    }
}
final修饰形参,形参只能被使用,不能被修改
class Person {
    public String work(final String work) {
        work = "打工";
        return work;
    }
}
上面的代码会报错:Cannot assign a value to final variable 'work'
内存模型中的final
对于 final 变量,编译器和处理器都要遵守两个重排序规则:
- 
构造函数中final 变量的赋值,与把此被构造对象的引用赋值给某变量,两操作不可重排序。 
- 
首次读一个包含 final 变量的对象,与随后首次读这个 final 变量,两个操作不可重排序。 
实际上,这两个规则也正是针对 final 变量的写与读。写的重排序规则可以保证,在对象引用对任意线程可见之前,对象的 final 变量已经正确初始化了,而普通变量则不具有这个保障;读的重排序规则可以保证,在读一个对象的 final 变量之前,一定会先读这个对象的引用。如果读取到的引用不为空,根据上面的写规则,说明对象的 final 变量一定以及初始化完毕,从而可以读到正确的变量值。
如果 final 变量的类型是引用型,那么构造函数内,对一个 final 引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
实际上,这正是为保证 final 变量在对其他线程可见之前,能够正确的初始化完成。
final对象的好处
- 
final 关键字,提高了性能,JVM 和 Java 应用都会缓存 final 变量。 
- 
final 变量,可以安全的在多线程环境下进行共享,而不需要额外的同步开销。 
final和static一起搭配使用。
public class Test {
    public static void main(String[] args) {
        System.out.println(Status.SUCCESS);
    }
}
class Status {
    final static public int SUCCESS = 200;
    static {
        System.out.println("类被加载");
    }
}
上面的代码中,当我们直接使用final 修饰的静态属性的时候,不会导致类被加载。输出如下:200
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号