Java final关键字

  • 基本介绍
  • final修饰类
  • final修饰方法
  • final修饰属性
  • final修饰局部变量
  • final不能修饰抽象类和接口
  • final使用注意事项和细节讨论
  • 非静态情况下final的使用
  • 静态情况下final的使用
  • final修饰类后可以实例化
  • final其它细节
  • final和static一起使用
  • 一起使用前
  • 一起使用后
  • 练习
  • 练习1
  • 练习2
  • 选择题


基本介绍

java中final 类 java final class_java中final 类

final修饰类

// 如果我们要求A类不能被继承可以用final修饰
final class A {
}

//修饰A类后,B类不能再继承A类了
class B extends A {
}

java中final 类 java final class_赋值_02

final修饰方法

class C {
    /**
     * 如果我们要求hi不能被子类重写,可以用final关键字修饰
     */
    public final void hi() {
    }
}

class D extends C {
    @Override
    public void hi() {
        System.out.println("D类重写了C类的hi()");
    }
}

java中final 类 java final class_赋值_03

final修饰属性

public class Exercise01 {
    @Test
    public void test() {
        G g = new G();
        g.TAX_RATE = 5;
        System.out.println(g.TAX_RATE);

    }
}
class G {
    /**
     * 当不希望类的某个属性的值被修改,可以用final修饰
     */
    public final double TAX_RATE = 0.08;
}

java中final 类 java final class_赋值_04

final修饰局部变量

@Test
    public void test2() {
        H h = new H();
        h.cry();
    }
/**
 * 当不希望某个局部变量被修改的时候,可以使用final修饰
 */
class H {
    public void cry() {
        final double NUM = 0.01;
        NUM = 0.9;
        System.out.println("NUM=" + NUM);
    }
}

java中final 类 java final class_java中final 类_05


此处被final修饰的NUM,也被称为局部常量

final不能修饰抽象类和接口

/**
 * final 不能修饰抽象类和接口
 */
final abstract class E{}

final interface F{}

java中final 类 java final class_java_06

final使用注意事项和细节讨论

java中final 类 java final class_java_07

非静态情况下final的使用

class AA {
    /**
     * ①定义时:如public final double TAX RATE=0.08;
     * ②在构造器中
     * ③在代码块中。
     */
    public final double TAX_RATE = 0.08;
    /**
     * 这里没赋初始值,可以在构造器中赋值
     */
    public final double TAX_RATE2;
    /**
     * 这里没赋初始值,可以在代码块中赋值
     */
    public final double TAX_RATE3;


    public AA() {
        TAX_RATE2 = 1.1;
    }

    // 代码块
    {
        TAX_RATE3 = 2.2;
    }

}

静态情况下final的使用

class BB {
    /**
     * 如果final修饰的属性是静态的,则初始化的位置只能是
     * ①定义时
     * ②在静态代码块不能在构造器中赋值。
     */
    public static final double TAX_RATE = 0.08;

    public static final double TAX_RATE2;
    public static final double TAX_RATE3;

    static {
        TAX_RATE2 = 3.3;
    }

    /**
     * 如果final修饰的常量是静态的(static),那么构造器赋值不被允许
     */
    public BB() {
        TAX_RATE3 = 4.4;
    }
}

java中final 类 java final class_System_08

final修饰类后可以实例化

@Test
    public void test2() {
        CC cc = new CC();
    }
    /**
 * final类不能继承, 但是可以实例化对象。
 */
final class CC {

}

final其它细节

@Test
    public void test3() {
        EE ee = new EE();
        ee.cal();
    }
class DD {
    /**
     * 如果类不是final类,但是含有final方法,
     * 则该方法虽然不能重写,但是可以被继承。[A3类]
     */
    public final void cal() {
        System.out.println("cal()方法");
    }

}

class EE extends DD {

}

java中final 类 java final class_java_09


画蛇添足:

一个类已经是final类了,就没有必要再将方法修饰成final方法

final class AAA {
    /**
     * 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。
     */
    public final void find() {
    }

}

final和static一起使用

一起使用前
public class Exercise03 {
    @Test
    public void test2() {
        System.out.println(BBB.num);
    }
}
class BBB {
    /**
     * final和static往往搭配使用,
     * 效率更高,不会导致类加载.
     * 底层编译器做了优化
     */
    public static int num = 100;

    static {
        System.out.println("BBB静态代码块被执行");
    }
}

输出结果

BBB静态代码块被执行
100
一起使用后
public class Exercise03 { 
    @Test
    public void test2() {
        System.out.println(BBB.num);
    }
}
class BBB {
    /**
     * final和static往往搭配使用,
     * 效率更高,不会导致类加载.
     * 底层编译器做了优化
     */
    public final static int num = 100;

    static {
        System.out.println("BBB静态代码块被执行");
    }
}

输出结果

100

可以看到,一起使用后,静态代码块就没加载了

练习

练习1

java中final 类 java final class_java_10

package com.homework;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/11/18 18:39
 */
public class HomeWork01 {
    @Test
    public void test() {
        Circle circle = new Circle();
        double area = circle.area(3);
        System.out.println(area);

    }
}

class Circle {
    private double redius;

    // 定义赋值
    //private final double PI = 3.14;
    private final double PI;

    public Circle() {
        // 构造器赋值
        //PI = 3.14;
    }

    // 代码块赋值
    {
        PI = 3.14;
    }

    public double getRedius() {
        return redius;
    }

    public void setRedius(double redius) {
        this.redius = redius;
    }

    public double area(double redius) {
        return (redius * redius * PI);
    }

}

练习2

阅读代码,看看是否有问题

java中final 类 java final class_java中final 类_11


解析:有误

因为final修饰了x,就不能再++x增加。

但是rerutn x+1 是正确的,因为会返回一个新值

package com.homework;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/11/18 18:48
 */
public class Something {
    @Test
    public void test() {
        int i = addOne(3);
        System.out.println(i);
        /**
         * 返回结果
         * 4
         */
    }

    public int addOne(final int x) {
        return x + 1;
    }
}

选择题

关于final说法正确的是? ( )

A.final类的方法肯定不能被同一个包的类访问
B.final类的方法能否被同一个包的类访问不是由final决定
C.final方法等同于private方法
D.final对象本身的引用和值都不能改变


答案解析:B

能否被同一个包的类访问,是由访问修饰符:public,default,protected,private决定的,所以A错误。
final对象的引用示例见如下代码:

package com.choice.question6;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/11/18 16:11
 */
public class TestFinal {
    private static final int x = 2;
    private static final int array[] = {1, 2, 3};
    private static final Person person = new Person("小明", 12);

    public final void getTest() {
        System.out.println("getTest()");
        System.out.println(TestFinal.x);
    }

    public static final void getTest2() {
        System.out.println("getTest2()");
        System.out.println(x);

    }


    @Test
    public void test() {
        getTest();
        getTest2();
        System.out.println(person);
        change(person);
        System.out.println(person);
    }

    // 这里更改了 final引用对象的值
    public void change(final Person p) {
        p.setName("疯狂星期四");
        p.setAge(4);
    }

    public static void main(String[] args) {
        getTest2();

    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}