java:final

java:final

1 final变量

final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常,由final定义的变量为常量。程序中若再次对定义为final的变量赋值,编译器将不会接受。

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

package com.base2;
import static java.lang.System.out;

import java.util.Arrays;
import java.util.Random;

public class UseFinal {
    static Random r=new Random();
    private final int VALUE_1=9;
    private static final int VALUE_2=10;
    private final FT f=new FT();
    private FT f1=new FT();
    private static final int[] a={1,3,7};
    private final int i4=r.nextInt(20);
    private static final int i5=r.nextInt(20);
    public String toString(){
        return i4+" "+i5+" ";
    }
    public static void main(String[] args) {
        UseFinal u=new UseFinal();
//        u.f=new FT();
        //可以对final的数组进行赋值修改
        for (int i = 0; i < 3; i++) {
            a[i]=7;
            u.a[i]=0;
        }
        out.println(Arrays.toString(a));
        out.println(Arrays.toString(u.a));
    }
}

class FT{
    int i=0;
}
[0, 0, 0]
[0, 0, 0]

如果修改为:

private final int[] a={1,3,7};
public static void main(String[] args) {
    UseFinal u=new UseFinal();
//        u.f=new FT();
    //可以对final的数组进行赋值修改
    for (int i = 0; i < 3; i++) {
        u.a[i]=7;
    }
    out.println(Arrays.toString(u.a));
}
[7, 7, 7]

被定义为final的常量定义时需要使用大写字母命名,并且在中间使用下划线。被定义为final的对象引用只能指向唯一一个对象,不可以再将它指向其他的对象,但是一个对象本身的值却是可以改变的。为了使一个变量真正做到不可更改,可以将常量声明为static final。

先举例:

package com.base2;
import java.util.Random;
import static java.lang.System.out;

public class FinalStaticData {
    //实例化一个Random类对象
    private static Random r=new Random();
    //随机产生0~10之间的随机数赋予定义为final的a1(nextInt(1):总是0)
    private final int a1=r.nextInt(10);
    //随机产生0~10之间的随机数赋予定义为final的a2
    private static final int a2=r.nextInt(10);
    public static void main(String[] args) {
        FinalStaticData f1=new FinalStaticData();
        out.println(f1.a1);
        out.println(f1.a2);
        FinalStaticData f2=new FinalStaticData();
        out.println(f2.a1);
        out.println(f2.a2);
    }
}
4
2
5
2

可知,定义为final的常量不是恒定不变的,但是static final,开辟的是恒定不变的区域,再次实例化1个FinalStaticData对象,任然指向一个内存区域。

注意:
在java中定义全局变量,通常使用public static final修饰,这样的常量只能在定义时被赋值。
可以将方法的参数定义为final类型,这预示着无法在方法中更改参数引用所指向的对象。

总结:程序哪些地方可以定义final数据
在这里插入图片描述
如果方法中的参数是final,就不可以在方法的内部,再对该final变量赋值了。
在这里插入图片描述
在这里插入图片描述
2 final方法

定义为final的方法不能被重写。将方法定义为final类型可以防止子类修改该类的定义与实现方式,同时定义为final的方法执行效率要高于非final方法。如果父类的某个方法被设置为private修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为private的方法隐式被指定为final类型,这样无须将一个定义为private的方法再定义为final类型。
在这里插入图片描述
在这里插入图片描述
在父类中被定义为private final的方法似乎可以被子类覆盖,实例如下(或者说父类中private修饰符,让final直接无效,相当于是一个private方法,子类不会继承private方法,也就不算重写了):

package com.base2;

public class FinalMethod {
    public static void main(String[] args) {
        Son s=new Son();
        s.doit();
    }
}

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 Son extends Parents{
    public void doit(){
        System.out.println("子类.doit()");
    }
//    final void doit2(){//final方法不能覆盖
//
//    }
    public void doit3(){
        System.out.println("子类.doit3()");
    }
}
子类.doit()

如果把上述的代码修改为:
在这里插入图片描述
在这里插入图片描述
所以,可以理解为public\protected\private和final同时存在时,private会使得final失效(private带有final的效果),而private又具有不会被子类继承的效果,所以子类可以看成能够重写父类中private final方法(或者说就是子类新的方法,根本没有重写),其余的方法则不行。

如下例子可知:

package com.base2;

public class FinalMethod {
    public static void main(String[] args) {
        Son s=new Son();
        s.doit();
        Parents p=s;
        s.doit();
        s.doit2();
    }
}

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 Son extends Parents{
    public void doit(){
        System.out.println("子类.doit()");
    }
    public void doit3(){
        System.out.println("子类.doit3()");
    }
}
子类.doit()
子类.doit()
父类.doit2()

由上可知,覆盖(重写)本质上必须满足向上转型,向上转型时(Parents p=s;),对象调用方法,先在父类中找,父类要找到,再去子类中找到,最后调用的就是父类中的方法。可见,子类对象Parents p=s;调用s.doit();实际上只是子类生成的一个新的方法。

3 final类

定义为final的类不能被继承。语法如下:

final class 类名{}

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

final class myFinal {
    int a=3;
    void doit(){}
    public static void main(String[] args) {
        myFinal m=new myFinal();
        m.a++;
        System.out.println(m.a);
    }
}
4
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值