Java SE final修饰符

本文详细解析了final关键字在Java中的应用,包括修饰变量、方法及类的不同情况,以及如何使用final定义宏变量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

final修饰变量时,表示该变量一旦获得了初始值就不可被改变。final既可以修饰成员变量,也可以修饰局部变量,形参。


final成员变量

对于final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值。 所以 final修饰的成员变量必须有程序员显式地指定初始值。系统不会对final成员变量进行隐式初始化。

类变量: 必须在静态初始化块中指定初始值 或者 声明该类变量的时候指定初始值。
类变量不能在非静态初始化块中指定初始值,因为类变量在类初始化阶段就已经被初始化了。
实例变量:必须在非静态初始化块声明该实例变量、 或者 构造器中指定初始值。
如果非静态初始化块已经为某个实例变量指定了初始值,则不能再在构造器中为该实例变量指定初始值。


final 形参

public void test (final int a) {
    //不能对final修饰的形参赋值,下面语句非法
    //a = 5;
}

形参在调用该方法时,由系统根据传入的参数来完成初始化,因此使用final修饰的形参不能被赋值。


final修饰引用类型变量

使用final修饰基本类型变量时,不能对基本基本类型变量重新赋值。
对于引用类型而言,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,既一直引用同一个对象,但这个对象完全可以发生改变。

class  A {
    public static void main(String[] args)  {
        final int[] iArr = {1,6,12,9};   //final修饰数组变量,iArr只是一个引用变量
        System.out.println("Arrays.toString(iArr)");
        Arrays.sort(iArr);    //对数组元素进行排序,合法
        System.out.println("Arrays.toString(iArr)");
        iArr[2] = 10;  //对数组元素赋值,合法
        System.out.println("Arrays.toString(iArr)");
        iArr = null//对iArr重新赋值,非法。

        final Person p = new Person(45);    //final修饰Person变量,p是一个引用变量
        p.setAge(23);     //改变Person对象的age实例变量,合法
        System.out.println(p.setAge());
        p = null;           // 对p重新赋值,非法
    }
}

可执行“宏替换”的final变量

当一个final变量在编译之前就被指定好初始值且定下来,这时final变量就不再是一个变量,而是相当于一个直接量。final修饰符的一个重要用途就是定义“宏变量”,当定义这个final变量时久违该变量指定了初始值,那么该初始值在编译时就会确定下来,那么这个final变量实质上就是一个“宏变量”,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。

final int a = 5;
System.out.println(a);     //当程序执行System.out.println(a);代码时,实际转换成执行System.out.println(5)

java会使用常量池来管理曾经出现过的字符串直接量,例如执行String a = “java”;语句之后,常亮池汇总就会缓存一个字符串“java”; 如果程序再执行String b = “java”;系统将会让b直接指向常量池中的”java”字符串。 因此 a==b将会返回true。

class  B {
    public static void main(String[] args)  {
        String s1 = "学习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
    }
}   

s1是一个普通的字符串直接量“学习java” .s2直接指向常量池缓存池中的“学习java” 因此第一个输出true

str1和str2都是两个普通变量,编译器不会执行“宏替换“因此编译器无法在编译时确定s3的值。所以第二个输出false 。 想让第二个输出ture 只要将str1 str2使用final修饰即可,编译器就会在编译器对str1和str2执行“宏替换“”,这样在编译阶段就可以确定str3的值。

PS:对于实例变量来说,在定义该变量的时候赋值,在构造器和非静态初始化块、这三个地方赋值的效果基本一样,但是只有在定义该变量的时候指定初始值才会有“宏变量”的效果


final方法

final修饰的方法不可以被重写.

public class A {
    public final void test();
}
class B extends A {
    public void test();                    //编译错误,无法被重写。
}
public class A {
    private final void test();
}
class B extends A {
    public void test();                    //可以编译。
}

private修饰的方法只能在当前类中可见,其他子类无法访问。
因为子类中定义一个与父类private方法相同方法名 ,相同形参列表,相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法。

public class A {
    private final void test(){};
    public final void test(String arg){};     //对
}

不能重写,但是可以被重载。


final类

final修饰的类不可以有子类。比如String类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值