**final修饰符,可以修饰变量、方法、类,
final关键字表示修饰的变量、方法、类,不可再被改变。**
一、final变量
1、final修饰成员变量
成员变量是随着类的初始化和对象的初始化而初始化的。
当类初始化的时候,系统会为类变量(static)分配内存,并分配默认值;
当创建对象的时候,系统会为对象的实例变量分配内存,并分配默认值。
也就是说,静态初始化块可对类变量赋值
普通初始化块、构造器,可以对实例变量赋值‘’
JAVA语法规定:final修饰的成员变量必须有程序显式的赋值 color=#00ffff
==>>类变量:必须在声明该类变量时或者在静态代码块,其中两者之一
指定
==>>实例变量:必须在声明时、构造器、非静态初始化块,三者之一指定
package codes.AutoBoxing_UnBoxing;
public class finalVeriable {
//①类变量,声明时初始化
final static int a=123;
final static int b;
//②类变量,静态初始化块初始化
static {
b=1234;
}
//①成员变量,声明时初始化
final int c=100;
final int d;
final int e;
//②成员变量,构造器初始化
finalVeriable(){
d=200;
}
//③成员变量非静态代码块
{
e=300;
}
public static void main(String args[]){
System.out.println(a);
System.out.println(b);
finalVeriable fv=new finalVeriable();
System.out.println(fv.c);
System.out.println(fv.d);
System.out.println(fv.e);
}
}
3、final修饰基本变量和引用类型变量的区别
基本类型变量:基本变量的值不能被改变
引用变量:它保存的仅仅是一个引用,final只保证引用类型变量所引用的地址不会变,即一直引用同一个对象,但这个对象完全可以发生改变。
4、可执行“宏替换”的final变量
无论是类变量、成员变量,还是局部变量,只要
①final修饰
②声明时就赋值
③值在编译时就能确定;
那么,它就是不再是一个变量,而是一个直接量。
public class FinalLocalTest {
//s1为普通的字符串直接量,放在字符串池中
String s1="HelloWorld";
String s2="Hello";
String s3="World";
final String s4="Hello";
final String s5="World";
String s6="Hello"+"World";
//s2和s3都是普通变量,编译器不会提供"宏替换",因此编译器无法在编译时确定s7的值
//s7无法指向字符串池中缓存的"HelloWorld"
String s7=s2+s3;
//编译器可以对s4和s5执行“宏替换”,在编译阶段就可确定s8
String s8=s4+s5;
public static void main(String args[]){
FinalLocalTest ft=new FinalLocalTest();
//输出true
System.out.println(ft.s1==ft.s6);
//输出false
System.out.println(ft.s1==ft.s7);
//输出true
System.out.println(ft.s1==ft.s8);
}
}
二、final方法
final修饰的方法不可被重写。
被private final修饰的方法,仅仅是不能被重写,是可以被重载的。
三、final类
final修饰的类不可以有子类。例如Java.lang.Math就是一个final类,它不可以有子类。
四、不可变类(immutable)
不可变类指的是,创建该类的对象后,该对象的实例变量是不可变的;
JAVA提供的8个包装类和java.lang.String类都是不可变类,当创建其实例后,其实例的实例变量都是不可改变的。
code1如下,试图定义一个名为Person的不可变类,但因为Person类包含了一个引用类型的成员变量(Name),且这个引用类是可变类,所以导致Person01这个类也变成了可变类。
由于Person类在初始化的时候,Person类的实例变量name,引用了该Name的一个对象,所以当这个可变对象的变化的时候,Person类的实例变量name也随之改变了。
//修改前 达不到实现不可变类的目的
class Name{
private String firstName;
private String lastName;
Name(String firstName,String lastName){
this.firstName=firstName;
this.lastName=lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class Person {
private final Name name;
Person01(Name name){
this.name=name;
}
public Name getName() {
return name;
}
public static void main(String args[]){
Name name01=new Name("孙","悟空");
Person p1=new Person(name01);
//输出 悟空
System.out.println(p1.getName().getLastName());
/*********************************************/
p1.getName().setLastName("八戒");
//输出 八戒
System.out.println(p1.getName().getLastName());
}
}
为了保持Person对象的不可变性,必须保持好Person对象引用类型的成员变量name ,让程序无法访问到name成员变量,也就无法利用name成员变量的可变性来改变Person对象了。
Person类改写了设置name实例变量的方法,也改写了name的getter方法。
直接利用已有的可变对象,是有风险的
//修改后达到,实现不可变类的目的
class Name{
private String firstName;
private String lastName;
Name(String firstName,String lastName){
this.firstName=firstName;
this.lastName=lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class Person01 {
private final Name name;
public Person01(Name name){
this.name=new Name(name.getFirstName(),name.getLastName());
}
public Name getName() {
return new Name(name.getFirstName(),name.getLastName());
}
public static void main(String args[]){
Name name01=new Name("孙","悟空");
Person01 p1=new Person01(name01);
//输出 悟空
System.out.println(p1.getName().getLastName());
/*********************************************/
p1.getName().setLastName("八戒");
//输出 悟空
System.out.println(p1.getName().getLastName());
}
}