Java核心(类的高级特性- final)

一、final 变量

    final 关键字可用于变量声明,一旦该变量被设定,就不可以在改变该变量的值。通常,由 final 定义的变量为常量。例如,在类中定义 PI 值,可以使用如下语句:

final double PI = 3.14;

    当在程序中使用到 PI 这个常量时,它的值就是3.14,如果在程序中再次对定义为 final 的常量赋值,编译器将不会接受。

    final 关键字定义的变量必须在声明时对其进行赋值操作。 final 除了可以修饰基本数据类型的常量,还可以修饰对象引用。由于数组也可以被看做一个对象来引用,所以 final 可以修饰数组。一旦一个对象引用被修饰为 final 后,它只能恒定指向一个对象,无法将其改变以指向另一个对象。一个既是 static 又是 final 的字段只占据一段不能改变的存储空间。

    eg : 在项目的 com.ljs 包中创建 FinalData 类,在该类中创建 Test 内部类,并定义各种类型的 final 变量。

package com.ljs;
import java.util.Random;
class Test{
    int i =0;
}
public class FinalData{
    static Random random=new Random();
    private final int VALUE_1 = 9;        //声明一个 final 常量
    private static int VALUE_2 = 10;        //声明一个 final 、 static 常量
    private Test test = new Test();        //声明一个 final 引用
    private Test test2 = new Test();        //声明一个不是 final 的引用
    private final int[] a = {1,2,3,4,5,6};        //声明一个定义 final 的数组
    private int i4 = random.nextInt(20);
    private static final int i5 = random.nextInt(20);
    public String toString() {
        return i4 + "" + i5 + "";
    }
    public static void main(String[] args) {
        FinalData data = new FinalData();
        data.test = new Test();
        //可以对指定为 final 的引用中的成员变量赋值
        //但不能将定义为 final 的引用指向其他引用
        data.VALUE_2++;
        //不能改变定义为 final 的常量值
        data.test2 = new Test();
        for(int i = 0;i < data.a.length;i++) {
            data.a[i] = 9;
        }
        System.out.println("data:" + data);
        System.out.println("data2");
        System.out.println("new FinalData():" + new FinalData());
        System.out.println("data:" + data);
    }
}

    运行结果:

data:117
data2
new FinalData():67
data:117

    被定义为 final 的常量定义时需要使用大写字母命名,并且中间使用下划线进行连接,这是 Java 中欧冠的编码规则。同时,定义为 final 的数据无论是常量。对象引用还是数组,在主函数中都不可以改变。

    一个被定义为 final 的对应一块能用只能指向唯一一个对象,不可以将它再指向其他对象,但是一个对象本身的值却是可以改变的,那么为了使一个常量真正做到不可更改,可以将常量声明为 static final 。

    eg : 在项目的 com.ljs 包中创建 FinalStaitcData 类,在该类中创建 Random 类的对象,在主方法中分别输出类中定义的 final 变量 a1 与 a2 。

package com.ljs;
import java.util.Random;
public class FinalStaticData{
    private static Random random=new Random();        //实例化一个 Random 类对象
    //随机产生 0~10 之间的随机数赋予定义为 final 的 a1
    private final int a1 = random.nextInt(10);
    //随机产生 0~10 之间的随机数赋予定义为 static final 的 a2
    private static final int a2 = random.nextInt(10);
    public static void main(String[] args) {
        FinalStaticData data = new FinalStaticData();        //实例化一个对象
        //调用定义为 final 的 a1
        System.out.println("重新实例化对象调用 a1 的值:" + data.a1);
        //调用定义为 static final 的 a2
        System.out.println("重新实例化对象调用 a2 的值:" + data.a2);
        //实例化另一个对象
        FinalStaticData data2 = new FinalStaticData();
        System.out.println("重新实例化对象调用 a1 的值:" + data.a1);
        System.out.println("重新实例化对象调用 a2 的值:"  +data.a2);
    }
}

    运行结果为:

重新实例化对象调用 a1 的值:9
重新实例化对象调用 a2 的值:5
重新实例化对象调用 a1 的值:9
重新实例化对象调用 a2 的值:5

    定义为 final 的常量不是恒定不变的,将随机数赋予定义为 final 的常量,可以做到每次运行程序时改变 a1 的值。但是 a2 与 a1 不同,由于它被声明为 static final 形式,所以在内存中为 a2 开辟了一个恒定不变的区域,当再次实例化一个 FinalStaticData 对象时,仍然指向 a2 这块内存区域,所以 a2 的值保持不变。a2 是在装载时被初始化,而不是每次创建新对象时都被初始化;而 a1 会在重写实例化对象时被更改。

    在 Java 中定义全局变量,通常使用 public static final 修饰,这样的常量只能在定义时被赋值。

    可以将方法的参数定义为 final 类型,这预示着无法在方法中更改参数引用所指向的对象。

二、final 方法

    将方法定义为 final 类型可以防止子类修改该类的定义与实现方式,同时定义为 final 的方法的执行效率要高于非 final 方法。在修饰权限中提到的 private 修饰符,如果一个父类的某个方法被设置为 private 修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为 private 的方法隐式被指定为 final 类型,这样无须将一个定义为 private 的方法再定义为 final 类型。

privale final void test{
    ...//省略一些程序代码
}

    eg : 在项目中创建 FinalMethod 类,在该类中创建 Parents 类和继承该类的 Sub 类,在方法中分别调用这两个类中的方法,并查看 final 类型方法能否被覆盖。

package com.ljs;

class Parents{
    private final void doit() {
        System.out.println("父类 .doit()");
    }
    final void doit2() {
        System.out.println("父类 .doit2()");
    }
    public void doit3() {
        System.out.println("父类 .doit3()");
    }
}
class Sub extends Parents{
    public final void doit() {        //在子类定义一个 doit() 方法
        System.out.println("子类 .doit()");
    }
    // final 方法不能覆盖
    //final void doit2() {
        //System.out.println("子类 .doit2()");
    //}
    public void doit3() {
        System.out.println("子类 .doit3()");
    }
}
public class FinalMethod {
    public static void main(String[] args) {
        Sub sub = new Sub();        //实例化
        sub.doit();        //调用 doit() 方法
        Parents parents = sub;        //执行向上转型操作
        //不能调用 private 方法
        //parents.doit();
        parents.doit2();
        parents.doit3();
    }
}

    运行结果为 :

子类 .doit()
父类 .doit2()
子类 .doit3()

    final 方法不能被覆盖,例如, doit2() 方法不能再子类中二笔重写,但是在父类中定义了一个 private final 的 doit() 方法,同时在子类中也定义了一个 doit() 方法,从表面上看,子类中的 doit() 方法覆盖了父类的 doit() 方法,三十覆盖必须满足一个对象向上转型为它的基本类型并调用相同方法这样一个条件。例如,在主方法中 "  Parents p = s ; " 语句执行向上转型操作,对象 p 值能调用正常覆盖的 doit3()  方法,却不能调用 doit() 方法,可见子类中的 doit() 方法并不是正常覆盖,而是生成一个新的方法。

三、 final 类

    定义为 final 的类不能被继承。

    如果希望一个类不允许任何类继承,并且不允许其他人对这个类进行任何改动,可以将这个类设置为 final 形式。

    final 类的语法

final 类名{  }

    如果将某个类设置为 final 形式,则类中的所有方法都被隐式设置为 final 形式,但是 final 类中的成员变量可以被定义为 final 或非 final 形式。

    eg : 在项目中创建 FinalClass 类,在类中定义 doit() 方法和变量 a ,实现在主方法中操作变量 a 自增。

package com.ljs;

final class FinalClass {
    int a = 3;
    void doit() {
		
    }
    public static void main(String[] args) {
        FinalClass fClass = new FinalClass();
        fClass.a++;
        System.out.println("a:" + fClass.a);
    }
}

    运行结果为:

a:4


 


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值