Java final关键字
- 基本介绍
- final修饰类
- final修饰方法
- final修饰属性
- final修饰局部变量
- final不能修饰抽象类和接口
- final使用注意事项和细节讨论
- 非静态情况下final的使用
- 静态情况下final的使用
- final修饰类后可以实例化
- final其它细节
- final和static一起使用
- 一起使用前
- 一起使用后
- 练习
- 练习1
- 练习2
- 选择题
基本介绍
final修饰类
// 如果我们要求A类不能被继承可以用final修饰
final class A {
}
//修饰A类后,B类不能再继承A类了
class B extends A {
}
final修饰方法
class C {
/**
* 如果我们要求hi不能被子类重写,可以用final关键字修饰
*/
public final void hi() {
}
}
class D extends C {
@Override
public void hi() {
System.out.println("D类重写了C类的hi()");
}
}
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;
}
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);
}
}
此处被final修饰的NUM,也被称为局部常量
final不能修饰抽象类和接口
/**
* final 不能修饰抽象类和接口
*/
final abstract class E{}
final interface F{}
final使用注意事项和细节讨论
非静态情况下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;
}
}
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 {
}
画蛇添足:
一个类已经是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
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
阅读代码,看看是否有问题
解析:有误
因为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;
}
}