1. final data
在compile-time就已经确定了值并且不能在run-time被改变
1.1 基本类型final
final data需要在定义的时候就赋值, 并且如果在类中试图修改final,编译器会报错
private final int a = 0;一般final与static一起使用 => 该字段在内存中只有唯一的空间,并且其中的值不能修改可以用于设计一些package范围内的常量使用
(ps: 避免在程序代码中直接出现基本类型的数值,可以用这种final static的方法作为类的field提供给函数引用)
像这样的写法应该避免:
if ( "spring".equals(getSeason()) ){
//...
}应该用类似这样的写法:private static final String SPRING = "spring";
// ...
if (SPRING.equals(getSeason()) ){
// ...
}
1.2 引用类型final
这个是容易混淆的地方,举个例子
我们随便建一个类
public class MyDemo {
private int id = 100;
public MyDemo() {
}
public int changeId(){
this.id = 200;
return this.id;
}
} 然后在main里面建立一个final引用并企图修改m1public static void main(String[] args){
final MyDemo m1 = new MyDemo();
MyDemo m2 = new MyDemo();
m1 = m2; // error!
}这里编译器会直接提示错误,不能将final变量重新赋值,这与我们之前正常的理解一致然后我们调用MyDemo中的方法修改id
int id = m1.changeId();
System.out.println(id); // 200我们发现id被修改了!因此,对于引用类型或者说非primitive类型的final data来说,其实应该理解为:
final变量的指向不能改变,即引用不能改变,不能让它重新指向另一个对象,但是对象本身的值确实可以改变的(这里需要有一点java内存模型的知识)。
so 想通过final是无法达到控制对象不能改变的目的的!
事实上在java中除了enum,也没有能够直接使得对象不可更改的方法,只能通过将其中的每一个member设置为final来达到目的。
1.3 blank final
当然,final并不一定要在definition的时候就赋值,这种就是blank final
但是,至少它必须在构造函数中赋值,否则编译器会报错╮(╯▽╰)╭
private final String name;
public MyDemo() {
name = "ParanoidQian";
}
1.4 final arguments
在函数中不能改变参数的值,或者参数的指向
e.g.
public void f(final int i){
i++; // error!
}2. final method
两个理由会使用到final method:
1. prevent method from being inherited and changing its meaning. 也就是不允许这个方法被继承类重写
2. allow compiler to turn the method into inline method. 就是为了效率,便于编译器在编译时将方法变为内联方法,现在基本不需要,交给jvm去做吧
关于第一点需要注意的是:
类中的private方法默认是不被子类继承的,但是!……如果你在子类中有一个函数签名一致的方法,编译器不会报错,为什么呢?编译器会认为这不是继承而来的,而是子类自己的方法,与父类的方法完全没有关系
重写(overriding)只对作为父类接口(interface)的部分才有意义,即你必须能够在子类中向上转换对象并能够调用同样的父类方法,这样才能称之为overriding
3. final class
you define a class final to state that you don't want to inherit from this class or allow anyone to do so.
即final class不可以被继承,那么默认的类内部所以的methods都是final的,不可以被继承(当然,private天然不可被继承)
例如下面的做法会被编译器直接报错;
final class Dinasour{ ... }
// error!
class Further extends Dinasour{ ... }
4. 总结
It can seem to be sensible to make a method final while you're desiging a class. You might feel that no one could possibly want to override your methods. Sometimes this is true.
But be careful with your assumptions. In general, it's difficult to anticipate how a class can be resued, especially a general-purpose class. If you define a method as final, you might prevent the possibly of reusing your class through inheritance in some
other programmer's project simply because you couldn't imagine it being used that way.
总而言之,轻易少用final,为良好的继承和软件重用留条出路!
本文详细解析Java中final关键字的应用场景与限制,包括基本类型final、引用类型final、blankfinal、final方法与final类的理解及使用注意事项,强调合理使用final以促进代码的复用性和安全性。
264

被折叠的 条评论
为什么被折叠?



