-
final
可以加在成员变量、方法、类上,在java中的final
,通常他指的是 "这是无法改变的" 的意思 -
final
加在成员变量上-
当final加在成员变量上时,意义就是指这个变量的值一旦被初始化之后,就不允许再被改变
-
如果
final
是加在基本类型(int、boolean、Integer...)上,因为这些变量中存的是实际的值,所以实际上是不允许改变他的值 -
但是如果
final
是加在对象类型上,因为这些变量中存的是 "对象的引用",所以实际上是不允许这个对象的引用改变,但是对象自己内部的成员变量还是能够被改变的-
这一限制同样适用数组,因为他也是指向对象的引用
-
不允许这个对象的引用改变的意思是指,当宣告
final Tank tank = new Tank()
之后,可以任意的执行tank.setXXX()
去改变tank内部的变量值,但是不能够执行tank = new Tank()
,将tank引用指向另一个new Tank()
对象
-
-
简单的说,当
final
加在基本类型上时,就是不允许赋予新值,而final
加在对象类型或是数组上时,就是不允许换新 -
事实上,在Java中也没有任何手段可以避免这件事,除非程序员自己对成员变量做了访问限制,直接不允许外部的人调用改变成员变量
class Tank { int level = 2; } public class Main { public static void main(String[] args) { final int i = 1; final Tank tank = new Tank(); System.out.println("i: " + i + ", Tank.level: " + tank.level); //i = 10; //过不了编译,因为final的基本类型的值是存的实际的值 tank.level = 20; //虽然tank被加上了final关键字,但是因为引用没改变,所以可以改变其内部的值 System.out.println("i: " + i + ", Tank.level: " + tank.level); //过不了编译,因为tank是一个对象类型 //所以加上final关键字时,表示不允许他去更换引用 //也就是说,tank只能永远指向当初new出来的那个Tank(),而不能再去指向另一个新new出来的Tank() //tank = new Tank(); final int[] a = new int[10]; //编译失败,理由和tank一样,因为a也是一个引用(指向数组对象们) //所以只能改这10个数组内部的值,但不能将a指向另一个new int[20] //a = new int[20]; a[0] = 10; System.out.println("a[0]: " + a[0]); a[0] = 20; //因为数组和对象一样都是存放引用,所以和对象一样,也可以改变其内部的值 System.out.println("a[0]: " + a[0]); } }
i: 1, Tank.level: 2 i: 1, Tank.level: 20 a[0]: 10 a[0]: 20
-
-
被设置为final的成员变量,不一定要在设置变量时就初始化,也可以选择在构造器裡进行初始化,如此给了我们写代码弹性的空间
-
final的用意是确保一个变量 "被初始化后",其值不会被改变,并没有限制初始化一定得在设置变量时初始化,所以也可以选择在构造器初始化
-
但要注意,因为只有这两种地方 (设置变量时,构造器) 会初始化变量,所以必须要在这裡的其中一个地方初始化final变量,否则编译器会报错
class Tank { final int x; //x在构造器裡才初始化 final int y = 2; //y在设置变量时就先初始化 //final int z; //编译失败,因为z没有在宣告变量时或构造器中的其中一个地方初始化 Tank(){ x = 1; //y = 3; //编译过不了,因为y已经被初始化过了,不允许再次初始化 } } public class Main { public static void main(String[] args) { final Tank tank = new Tank(); System.out.println(tank.x + tank.y); //输出1, 2 } }
-
-
-
final
加在方法参数上-
和成员变量一样,如果方法参数是基本类型,其值就不允许修改,如果方法参数是对象类型,其对象引用就不允许修改 (但对象裡的变量能够被修改)
class Tank { public int y = 2; } public class Main { public static void main(String[] args) { Tank tank = new Tank(); printInt(1); printTank(tank); } public static void printTank(final Tank tank) { //final加在方法参数上 System.out.println("tank.y: " + tank.y); tank.y = 20; System.out.println("tank.y: " + tank.y); } public static void printInt(final int i) { //final加在方法参数上 System.out.println("i: " + i); // i = 10; //编译过不了 System.out.println("i: " + i); } }
i: 1 i: 1 tank.y: 2 tank.y: 20
-
-
final
加在方法上-
final加在方法上的意义是把此方法锁定,即是禁止任何继承的子类@Override他,修改此方法的实现逻辑
-
但是如果此final方法是public的话,子类仍然可以去使用他
-
说穿了,final只是去限制子类不能去@Override改写此方法的具体逻辑而已,至于能不能调用此方法,那就看父类是设置为public/private,不关final的事情
-
-
其实,类中所有的private方法都隐式的被加上了final关键字,因为继承的子类虽然能获得这些private方法,但是因为private的关系,所以子类不能去取用他们,而因为无法取用,所以自然也就无法改写他们的实现逻辑,也达到了final的意义 (禁止子类改写此方法)
-
因此虽然说可以对所有的private方法自行手动加上final,不过不会增加任何意义,所以还是别加的好
-
class Parent { public void publicPrint() { System.out.println("public Parent"); } private void privatePrint() { System.out.println("private Parent"); } public final void publicFinalPrint() { System.out.println("public final Parent"); } } class Child extends Parent { //成功Override publicPrint()方法 @Override public void publicPrint() { System.out.println("public Child"); } //无法Override privatePrint()方法 //无法Override publicFinalPrint()方法,但是可以调用他 public void test() { super.publicFinalPrint(); } } public class Main { public static void main (String[] args) { Child child = new Child(); //仍然可以在子类中调用被宣告为final的父类方法 //final只是限制子类不能去更改这个方法的实现逻辑而已,没有限制能不能调用 //限制能不能调用,那个是public/private负责的 child.publicFinalPrint(); } }
-
-
-
final
加在类上-
当final加在类上,表示不允许任何人来继承此类,也就是不允许改写此类的意思
-
也就是说出于某种考虑,你对该类的设计永不需要任何变动,或者出于安全的考虑,你不希望他有子类
final class Parent { //Parent类设为final类 } //编译不通过,即不允许Child类继承Parent类 //class Child extends Parent {}
-
-
Java - final关键字
最新推荐文章于 2023-12-16 16:29:51 发布