Java的final关键字

final可以修饰域、方法、类,有不可改变之意,下面会依次讲解。

一、域

final修饰域分两种情况:

  • 1.final修饰基本类型,则基本类型的数值不可改变。
  • 2.final修饰对象引用,则对象引用不可改变;一旦引用已经初始化完成指向一个对象,就不能让这个引用指向另一个对象了;但是对象本身却是可以被改变的。

读者可以结合下面的例子更直观的理解上面的概念:

/**
 * @Description 木头
 * @Author .Mark
 * @Date 2019年2月22日
 */
class Wood {
    String kind;
    
    Wood(String kind) {
        this.kind = kind;
    }

    @Override
    public String toString() {
        return kind;
    }
}

/**
 * @Description 木制椅子
 * @Author .Mark
 * @Date 2019年2月22日
 */
public class WoodenChair {
    // 靠背的数量
    private final int numOfBackrest = 1;

    // 椅子腿儿的数量
    public final static int NUM_OF_LEG = 4;

    // 材质
    private final Wood wood = new Wood("花梨木"); 
    
    public static void main(String[] args) {
        WoodenChair woodenChair = new WoodenChair();
        
        // final修饰的基本类型,数值不可以改变
        // woodenChair.numOfBackrest = 2;
        
        // final修饰的对象,引用不可以更改
        // woodenChair.wood = new Wood("紫檀木");
        
        System.out.print("最初我想用" + woodenChair.wood + "做一把椅子,");
        
        // finnal修饰的对象,对象本身是可以被修改的
        woodenChair.wood.kind = "紫檀木";
        System.out.println("但后来还是觉得用" + woodenChair.wood + "更好。");
    }
}

// output: 最初我想用花梨木做一把椅子,但后来还是觉得用紫檀木更好。

final对基本类型的修饰,通常使用例子中对“椅子腿儿数量”的声明方式。public使得其他人可以直接访问这个域;static使得所有对象共享一份存储空间;final使得这个域的值恒定。

二、空白final

我是第一次接触空白final的用法,并没有经验但又觉得这个概念有用,所以就摘了《Java编程思想》的讲解出来解释它。

Java允许生成“空白final”,所谓空白final是指被声明为final但又未给定初值的域。无论什么情况,编译器都保证空白final在使用前必须被初始化。但是,空白final在关键字final的使用上提供了更大的灵活性,为此,一个类中的final域就可以做到根据对象而有所不同,却又保持其恒定不变的特性。下面即为一例:

class Poppet {
    private int i;
    
    Poppet(int ii) {
        i = ii;
    }
}

public class BlankFinal {
    // Initiallized final
    private final int i = 0;
    
    // Blank final
    private final int j;
    
    // Blank final reference
    private final Poppet p;
    
    // Blank finals MUST be initialized in the constuctor;
    public BlankFinal() {
        // Initialize blank final
        j = 1;
        // Initialize blank final reference
        p = new Poppet(1);
    }
    
    public BlankFinal(int x) {
        // Initiallize blank final
        j = x;
        
        // Initiallize blank final reference
        p = new Poppet(x);
    }
    
    public static void main(String[] args) {
        new BlankFinal();
        new BlankFinal(47);
    }
}

必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总被初始化的原因所在。

三、方法

final修饰的方法,子类不能对它进行重写。

/**
 * @Description 树
 * @Author .Mark
 * @Date 2019年2月23日
 */
class Tree {
    // 树高
    private double height;
    
    public final void grow(double increment) {
        height += increment;
    }
}

/**
 * @Description 白杨
 * @Author .Mark
 * @Date 2019年2月23日
 */
public class Poplar extends Tree {
    // 子类不能重写父类的final方法
    // public final void grow(double increment) { }
    
    public static void main(String[] args) {
        Poplar poplar = new Poplar();
        // 但是子类可以正常调用父类的final方法
        poplar.grow(1.0);
    }
}

private方法实际上已经被隐式的声明为final的了,你可以为private方法加上final修饰符,但实际上这个final起不到任何作用。如下示例:

/**
 * @Description 树
 * @Author .Mark
 * @Date 2019年2月23日
 */
class Tree {
    // 树高
    private double height;
    
    private final void grow(double increment) {
        height += increment;
    }
}

/**
 * @Description 白杨
 * @Author .Mark
 * @Date 2019年2月23日
 */
public class Poplar extends Tree {
    public final void grow(double increment) { }
}

这里容易产生个错觉,即子类可以重写父类的private方法。但实际上因为子类不能继承父类private的属性和方法,所以这里也就谈不上什么重写,而只是重新写了一个和父类一样的方法,这个方法和父类的那个方法没有任何关系。

四、类

final修饰的类,不能被继承。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值