final
final可用于修饰类, 变量和方法。用于表示它修饰的类,方法,变量不可改变。
final成员变量
final修饰的成员变量必须由程序员显式的指定初始值。
类变量: 只能在 静态初始化块 或 声明类变量 时指定初始值。
实例变量: 只能在 非静态初始化块, 声明该实例变量 或 构造器中 指定。
初始化之前不能使用变量。
public class FinalVarTest {
final int a = 1;
final String str;
final String str2;
final static int b;
{
str = "hello";
}
static {
b = 2;
}
public FinalVarTest(){
str2 = "1";
}
public FinalVarTest(String a){
str2 = "3";
}
public static void main(String[] args){
FinalVarTest varTest1 = new FinalVarTest();
FinalVarTest varTest2 = new FinalVarTest("b");
System.out.println(varTest1.str2); // 1
System.out.println(varTest2.str2); // 3
}
}
final局部变量
final修饰的局部变量, 赋值后不能被修改。
public static void main(String[] args){
final String s1 = "1";
final String s2;
s2 = "2";
}
final 修饰形参
public void test(final int a){
a = 2; //报错, 不能修改
}
形参是根据传入的参数完成初始化, 不能被赋值。
final 修饰引用类型变量
引用类型变量,保存的只是一个引用,final只保证所引用的地址不会改变,即一直引用一个对象,但这个对象可以发生改变。
public static void main(String[] args){
final int[] arr = {3, 4, 1, 2};
System.out.println(Arrays.toString(arr)); //[3, 4, 1, 2]
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); //[1, 2, 3, 4]
arr[2] = 8;
System.out.println(Arrays.toString(arr)); //[1, 2, 8, 4]
final Dog dog = new Dog("1", "haha");
dog.setId("2");
System.out.println(dog.getId()); // 2
dog = null; //报错, 不能修改
}
可执行"宏替换"
当final变量的值在编译阶段就被确定下来, 则相当于一个直接量。本质上就是一个"宏变量"。
编译器会把用改变量的地方直接替换成该变量的值。
final方法
final方法不可被重写。
Object 类的 getClass() 方法,就是 final 修饰, 不能被子类重写
public final native Class<?> getClass();
如果父类的 final方法是 private 方法, 则子类可以定义跟这个方法完全相同的方法,private方法子类无法访问, 等于定义一个新方法.
final不能被重写,重载是不影响的。
public final void testFun(){}
public final void testFun(int a){}
final类
final修饰的类,不能有子类。
public final class FinalVarTest {}
class Sub extends FinalVarTest{} //编译错误, 不能继承
不可变类
不可变类 immutable , 创建实例后,实例变量是不可改变的。
Java的8个包装类和 java.lang.String 都是不可变类。
String sx = new String("hello");
String 类提供实例变量保存 “hello”, 无法修改这个实例变量的值,String类没有提供修改他们都方法。
创建自定义的不可变类, 遵守下面规则:
- 使用 private 和 final 修饰符来修饰该类的成员变量。
- 提供带参的构造器, 根据参数初始化成员变量
- 为该类成员变量提供 getter 方法, 不提供 setter 方法, 普通方法不能修改 final 成员变量
- 如有必要,可以重写Object类的 hastCode() 和 equals() 两个方法。
public class Dog {
private final String id;
private final String name;
public String getId() {
return id;
}
public String getName() {
return name;
}
public Dog(String id, String name) {
this.id = id;
this.name = name;
}
//重写 equals 方法
public boolean equals(Object obj){
//同一个对象
if(this == obj){
return true;
}
// obj是 Dog对象
if(obj != null && obj.getClass() == Dog.class){
Dog dog = (Dog) obj;
//当前对象的id 和 obj 对象的 id相等时 返回 true
if(this.getId().equals(dog.getId())){
return true;
}
}
return false;
}
}
不可变类的实例状态不可改变, 可以方便被多个对象共享。
如果频繁使用, 可以考虑缓存这种不可变类实例。
java.lang.Integer 使用了缓存策略, 使用 valueOf()方法创建Integer对象,则会缓存该方法创建的对象。
地址: https://blog.youkuaiyun.com/yonggang7/article/details/86556484