(21)面向对象-6.类成员(下)——final修饰符

一、final修饰符定义:

  • final关键字可用于修饰类、变量和方法
  • final修饰变量时,表示该变量一旦获得了初始值就不可被改变(严格来说:final修饰得变量不可被改变,一旦获得初始值,该final变量得值就不能被重新赋值)
  • final既可以修饰成员变量(类变量和实例变量),也可以修饰局部变量和形参

二、final成员变量语法规定:
final修饰的成员变量必须由程序员显式地指定初始值,系统不会对final成员进行隐式处初始化

2、final修饰的类变量、实例变量能制定初始值的地方如下:

  • 类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地方的其中之一指定
  • 实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定
    注意:如果普通初始化块已经为某个实例变量指定了初始值,则不能再在构造器中为该实例变量制定初始值

下面程序演示了final修饰成员变量的效果:

package lextends;
public class FinalVariableTest {
    //定义成员变量时指定默认值,合法
    final int a = 6;
    //下面变量将在构造器或初始化块中分配初始值
    final String str;
    final int c;
    final static double d;

    //既没有指定默认值,又没有在初始化块、构造器中指定初始值
    //下面定义的ch实例是不合法的
    //final char ch;
    //初始化块,可对没有指定默认值的实例变量指定初始值
    {
        //在初始化块中为实例变量指定初始值,合法
        str = "Hello";
        //定义a实例变量时已经指定了默认值
        //不能为a重新赋值,因此下面赋值语句非法
        //a=9;
    }

    //静态初始化块,可对没有指定默认值的类变量指定初始值
    static {
        //在静态初始化块中为类变量指定初始值,合法
        d = 5.6;
    }

    //构造器,可以对既没有指定默认值,又没有在初始化块中,指定初始值的实例变量指定初始值
    public FinalVariableTest() {
        //如果在初始化块中已经对str指定了初始值
        //那么在构造器中不能对final变量重新赋值,下面赋值语句非法
        //str="java"
        c = 5;
    }

    public void changeFinal() {
        //普通方法不能为final修饰的成员变量赋值
        //d=1.2
        //不能在普通方法中为final成员变量指定初始值
        //ch = 'a';
    }
public static void mian(String[] args){
    FinalVariableTest ft= new FinalVariableTest();
    System.out.println(ft.a);
    System.out.println(ft.c);
    System.out.println(ft.d);}
}

3、如果打算在构造器、初始化块对final成员变量进行初始化,则不要在初始化之前就访问成员变量的值。

package lextends;
public class FinalErrorTest {
    //定义一个final修饰的实例变量
    //系统不会对final成员变量进行默认初始化
    final int age;
    {
        //age没有初始化,所以此处代码将引起错误,因为它试图访问一个未初始化的变量
        //只要把定义age时的final修饰符去掉,程序就正确了
        System.out.println(age);
        
        age=6;
        System.out.println(age);
    }
    public static void main(String[] args){
        new FinalErrorTest();
    }
}

三、final局部变量
1、定义:系统不会对局部变量进行初始化,局部变量必须由程序员显示初始化。因此使用final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值。

下面程序示范了final修饰局部变量、形参:
(final修饰形参的情形,因为在调用该方法时,由系统根据传入的参数来完成初始化,因此使用final修饰符不能被赋值。)

package lextends;
public class FinalLocalVariable {
    public void test(final int a){
        //不能对final修饰的形参赋值,下面语句非法
        //a=5;
    }
    public static void mian(String[] args){
        //定义final局部变量时指定默认值,则str变量无法重新赋值
        final String str="hello";
        //下面赋值语句非法
        //str="Java";
        
        //定义final局部变量时没有指定默认值,则d变量可被赋值一次
        final double d;
        d=5.6;
        //对final变量重新赋值,下面语句非法
        //d=6.4;
    }
}

四、final修饰基本类型变量和引用类型变量的区别

  • 使用final修饰的引用类型变量不能被重新赋值,但可以改变引用类型变量所引用对象的内容
  • 例如下面的iArr变量所引用的数组对象,final修饰后的iArr变量不能被重新赋值,但iArr所引用数组的数组元素可以被改变
eg.
//final修饰数组元素,iArr是一个引用变量
final int[] iArr={5,6,12,9};
System.out.println(Arrays.toString(iArr));
//对数组元素进行排序,合法
Arrays.sort(iArr);
System.out.println(Arrays.toString(iArr));
//对数组进行元素赋值,合法
iArr[2]=-8;
System.out.println(Arrays.toString(iArr));
//下面语句对iArr重新赋值,非法
//iArr=null;

五、可执行”宏替换“的final变量
1、对于一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。

  • 使用final修饰符修饰
  • 在定义该final变量时指定了初始值
  • 该初始值可以在编译时就被确定下来

2、final修饰符有一个重要用途就是定义”宏变量“。当定义final变量时就为该变量指定了初始值,而且该变量可以在变量时就确定下来,那么这个final变量本质上就是一个”宏变量“,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。

3、

eg.
String s1="疯狂Java";
//s2变量引用的字符串可以在编译时就确定下来
//因此s2直接引用变量池中已有的"疯狂Java"字符串
String s2="疯狂"+"Java";
System.out.println(s1==s2);//true

//定义两个字符串直接量
String str1="疯狂";
String str2="Java";
String s3=str1+str2;
System.out.println(s1==s3);//false

对于s3而言,它的值由str1和str2进行连接运算得到的,由于str1、str2只是两个普通变量,编译器不会执行”宏替换“,因此编译器无法确定s3的值,也就无法让s3指向字符串池中缓存的"疯狂Java"。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值