前言
我们在了解final关键字之前,可以先从它的字面意思去理解,有道翻译查询如下:
也就是说,final的中文意思就是最终的、不可改变的。在Java中,final关键字表达的也是这样的意思。final关键字修饰变量、方法和类,不管修饰什么,其本意都是指“它是无法更改的”。本文将介绍final关键字:
- final关键字修饰变量
- final关键字修饰方法参数
- final关键字修饰方法
- final关键字修饰类
(若文章有不正之处,或难以理解的地方,请多多谅解,欢迎指正)
final关键字修饰变量
只要是被final修饰的成员变量或本地变量(在方法中或在代码块中的变量称为本地变量)都称为final变量,final变量经常和static关键字一起使用,作为常量。用final关键字修饰的变量,只能进行一次赋值操作,并且生存期间不可以改变其值。
不过final关键字在基本数据类型和引用类型产生的效果还是有点区别。举个栗子:
public class Cats {
public static void main(String[] args){
final int catNum = 6;
final Cat c = new Cat("black");
catNum = 5; //Cannot assign a value to final variable 'catNum'
c.color = "white"; //正常执行
c = new Cat("brown"); //Cannot assign a value to final variable 'c'
}
}
class Cat{
String color;
public Cat(String color){
this.color = color;
}
}
从上述代码可以看出,final关键字对于基本数据类型和引用类型的效果是一样的:只能进行一次赋值操作,并且生存期间不可以改变其值。而且,虽然final关键字限制引用类型的引用地址,但并不会对引用类型的内部属性进行限制,所以c.color = "brown"是可以正常执行的。
final关键字修饰方法参数
上文提到,final关键字修饰变量时,该变量只能进行一次赋值操作,且不能改变其值。如果变量是作为参数传入的,那么我们怎么保证它的值不会改变呢?这就用到了final的第二个用法。
public static void print(final int i, final Date date){
i = 1; //Cannot assign a value to final variable 'i'
date = new Date(); //Cannot assign a value to final variable 'date'
System.out.println(i);
}
可以看到,如果我们不希望传入的参数在方法中被改变,可以在方法签名中声明该参数被final关键字修饰。
final关键字修饰方法
如果你认为一个方法的功能已经足够完整了,在方法前面声明final,代表这个方法不可以被子类的方法重写。因为final方法在编译的时候就已经静态绑定了,不需要运行时再动态绑定,所以final方法比非final方法要快一点。
class BlackCat extends Cat{
public String getColor(){
//'getColor()' cannot override 'getColor()' in 'Cat'; overridden method is final
}
}
class Cat{
private String color = "white";
final public String getColor(){
return color;
}
}
那么“在开发过程中,private修饰方法隐式等同于使用final修饰“,这是真的吗?举个栗子:
在使用final修饰方法时,子类方法是不能复写父类中用final修饰的方法:
public class Cat{
final void meow(){}
}
class BlackCat extends Cat{
void meow(){} //'meow()' cannot override 'meow()' in 'Cat'; overridden method is final
}
而使用private修饰方法时,虽然子类中可以存在于父类同名的private方法,但这个方法却不是从父类那里继承过来的了:
public class Cat{
private void meow(){}
}
class BlackCat extends Cat{
@Override //Method does not override method from its superclass
private void meow(){}
}
但是如果直接说,“private修饰方法等同于使用final修饰“,笔者不太认同,举个栗子:
public class Cat{
private void getColor(){}
private final void getFood(){}
final void getOwner(){}
}
我们进行编译之后,使用idea的插件jclasslib Bytecode Viewer查看Cat类的字节码,我们可以通过class文件中,专门描述方法的方法表的访问标志access_flags来判断:
首先是private void getColor()方法:
此次是private final void getFood()方法:
最后是final void getOwner()方法:
总结一下,所有final关键字只有明确禁止重写方法的时候,才使用其修饰方法。
final关键字修饰类
final关键字修饰类,表示这个类不可以被继承。所以如果不希望某个类有子类,就可以用final关键字来修饰。并且由于是用final关键字修饰的类,其类中的方法也会被隐式只为final方法。
在JDK中有很多类是final关键字修饰的,如String、Integer等。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
结语
本文主要对final关键字进行介绍,如果本文对你有帮助,请给一个赞吧,这会是我最大的动力~
参考资料: