java编程思想-关于final

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引用并企图修改m1
public 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,为良好的继承和软件重用留条出路!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值