概述
final 大家肯定都不陌生,我们从一道面试题开始深入了解它。
public class demo1 {
public static void main(String[] args) {
Test myClass1 = new Test ();
Test myClass2 = new Test ();
System.out.println(myClass1.i);
System.out.println(myClass1.j);
System.out.println(myClass2.i);
System.out.println(myClass2.j);
System.out.println(myClass2.i);
}
}
class Test {
public final double i = Math.random();
public static double j = Math.random();
}
myClass1.i 0.09703899009363104
myClass1.j 0.7525357662552306
myClass2.i 0.8764762570323944
myClass2.j 0.7525357662552306
myClass2.i 0.8764762570323944
final的作用是用来保证变量不可变 而static作用于成员变量用来表示只保存一份副本
使用场景
1.修饰类
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
2、修饰方法
使用final修饰的方法可以防任何继承类修改它,即父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一样的方法。但有种特殊情况当在父类的方法是私有方法 子类可以存在同方法名的方法此时的这个方法是子类本身的一个新方法。
public class B extends A {
public static void main(String[] args) {}
public void test() { }
}
class A {
/**
* 因为private修饰,子类中不能继承到此方法,因此,子类中的getName方法是重新定义的、
* 属于子类本身的方法,编译正常*/
private final void test() { }
/* 因为pblic修饰,子类可以继承到此方法,导致重写了父类的final方法,编译出错
public final void test() {} */
}
3、修饰变量
final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值,而且final变量一旦被初始化赋值之后,就不能再被赋值了
final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后其对象的引用地址值不能发生变化,但该引用所指向的对象的内容是可以发生变化的
public class Test {
public static void main(String[] args) {
final MyClass myClass = new MyClass();
System.out.println(++myClass.i); // 1
/* 编译报错
*myClass = new MyClass();
*/
}
}
class MyClass {
public int i = 0;
}
当修饰指定字符串时会类似字符串常量:
public class Test {
public static void main(String[] args) {
String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2;
String e = d + 2;
System.out.println((a == c)); // true
System.out.println((a == e)); //false
}
}
只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的类似常量的优化
final在修饰局部引用变量时,只是表明该变量在本方法体内是不能改变的,同时对局部以外的同名变量也是没有任何影响的,java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响。
后续
final 一般还用来修饰内部类这个以后在谈到内部类的时候再详细介绍了