文章目录

1.什么final关键字概念

2.final关键字基本用法

3.深入理解final关键字

4.final 关键字的最佳实践

什么是final关键字(概念

谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用final关键字 。final 是 Java 中的一个关键字,可以用于修饰类、方法变量。当一个类被声明final 时,它意味着该类不能被继承。当一个方法声明final 时,它意味着该方法不能被重写。当一个变量声明final 时,它意味着该变量的值不能被修改

 final关键基本用法

常见有5种用法,我们来归纳总结一下:

1. 用来修饰一个

2. 用来修饰一个方法

3. 用来修饰成员变量

4. 用来修饰局部变量

5. 用来修饰方法参数

final饰修类 

如果声明一个类为final类,  那么这个就是最终类,不能被继承

public final class ParentClass {
    public void happy() {
        System.out.println("高兴");
    }
}

当写一个类去继承它的时候

public class ChildClass extends ParentClass{
 
}

就会报错错误

注意一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写。

final类中的成员变量可以根据需要设为final,但是final类中的所有成员方法都会被隐式地指定final方法。 在使用final修饰类的时候,一定要谨慎选择,除非这个类以后不会用来继承或者出于安全考虑,尽量不要将类设计final类。

final修饰方法 

final用来修饰一个方法的时候这个方法就是最终方法,那么很明显就是说不能被覆盖重写。

public class ParentClass {
 
    public void happy() {
        System.out.println("高兴");
    }
    
    //用final关键字修饰的方法
    protected final void play(){
        System.out.println("开心的玩耍");
    }
 
}

我们继承类中去看下 play()方法是不可以被override的,也就是报错说明 final修饰的方法,是一个最终方法,不能被子类覆盖重写。

使用final方法的原因两个第一个原因是把方法锁定,以防任何继承修改它的含义;第二个原因效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“
因此,如果只有在想明确禁止 该方法在子类中覆盖的情况下才将方法设置为final的。即父类的final方法是不能被子类覆盖的,也就是子类是不能够存在父类一模一样的方法的。

final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。(注:类的private方法会隐式地被指定为final方法)

final修饰变量

final成员变量表常量,只能被赋值一次赋值后值不再改变。
当final修饰一个基本数据类型时,表示基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用指向对象内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化。
final修饰一个成员变量(属性),必须要显示初始化这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。

class Animal {
    private final int count = 0;
    public Animal() {
        count = 1; //报错
        final Object object = new Object();
        object = new Object(); //报错
    }
}

深入理解final关键字 

类的final变量和普通变量的区别

当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量需要保证在使用之前被初始赋值即可)必须在定义时或者构造器中进行初始赋值,而且final变量一旦被初始赋值之后,就不能再被赋值了。
那么final变量和普通变量到底有何区别呢?下面请看一个例子

public class Test {
    public static void main(String[] args) {
        String a = "helloworld";
        final String b = "hello";
        String c = "hello";
        String x = b + "world";
        String y = c + "world";
        System.out.println(a == x);
        System.out.println(a == y);
    }
}

输出结果true ; false

大家可以先想一下这道题的输出结果为什么第一个比较结果true,而第二个比较结果fasle。这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型时,如果在编译期间能知道它的确切值,则编译器会把它当做编译常量使用。也就是说在用到该final变量的地方,相当于直接访问这个常量,不需要运行确定。这种和C语言中的宏替换有点像。因此在上面的一段代码中,由于变量b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的值。而对于变量d访问需要运行通过链接来进行。想必其中的区别大家应该明白了,不过要注意,只有在编译期间能确切知道final变量值的情况下,编译器才会进行这样的优化,比如下面的这段代码就不会进行优化

public class Test {
    public static void main(String[] args) {
        String a = "helloworld";
        final String b = getHello();
        String x = b + "world";
        System.out.println(a == x);
    }
    public static String getHello() {
        return "hello";
    }
}

这段代码的输出结果false这里要注意一点就是:不要以为某些数据是final就可以在编译知道其值,通过变量b我们知道了,在这里是使用getHello()方法对其进行初始化,他要在运行期才能知道其值。

被final修饰的引用变量指向对象内容可变 

在上面提到被final修饰的引用变量一旦初始赋值之后就不能再指向其他的对象,那么该引用变量指向对象内容可变吗?看下面这个例子

public class Test {
    public static void main(String[] args) {
       final Object object = new Object();
        System.out.println(++object.i);
    }
}
class Object {
    public int i = 0;
}

输出结果: 1

这段代码可以顺利编译通过并且有输出结果,输出结果为1。这说明引用变量被final修饰之后,虽然不能再指向其他对象,但是它指向的对象的内容可变的。

 final参数问题

在实际应用中,我们除了可以用final修饰成员变量、成员方法、类,还可以修饰参数、若某个参数被final修饰了,则代表了该参数是不可改变的。如果在方法中我们修改了该参数,则编译器提示你:The final local variable i cannot be assigned. It must be blank and not using a compound assignment。看下面的例子

public class TestFinal {
    public static void main(String[] args) {
        TestFinal testFinal = new TestFinal();
        int i = 0;
        testFinal.changeValue(i);
        System.out.println(i);
    }

    public void changeValue(final int i) {
        //final参数不可改变
        i++; //报错,因为参数i已经被final修饰了
        System.out.println(i);
    }
}

上面这段代码changeValue方法中的参数i用final修饰之后,就不能在方法中更改变量i的值了。值得注意的一点,方法changeValue和main方法中的变量i根本就不是一个变量,因为java参数传递采用的是值传递,对于基本类型的变量,相当于直接将变量进行了拷贝。所以即使没有final修饰的情况下,在方法内部改变了变量i的值也不会影响方法外的i。

原文地址:https://blog.csdn.net/weixin_62079735/article/details/129427420

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_45692.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注