文章目录
- 一、 final的意义
- 二、 final的使用
- (1) final修饰类
- (2) final修饰方法
- (3) final修饰变量
- 1. 修饰成员变量
- 1.1 举例1
- 1.2 举例2
- 2. 修饰局部变量
- 2.1 举例1
- 2.2 举例2
- (4)final搭配static
- (5)总结
- 三、 笔试题
- (1)题1
- (2)题2
一、 final的意义
final
:最终的,不可更改的
final
可以用来修饰的结构:类、方法、变量(成员变量、局部变量)
二、 final的使用
(1) final修饰类
表示这个类不能被继承,没有子类。提高安全性,提高程序的可读性。
例如:String类、System类、StringBuffer类
final class Eunuch{//太监类}
class Son extends Eunuch{//错误}
【举例】
正常情况下:
class A{}class B extends A{}
若此时类A前面有final修饰,则B无法继承于A。如下:
💬什么样的类需要用final去修饰呢?
功能不需要再被扩展了,比如String
类、StringBuffer
类、StringBuilder
类。
会发现String加了一个final修饰:
public final class String...
这就意味着不能去声明一个类去继承于String。
Stirng类用final修饰,没有必要再进行功能的扩展。
(2) final修饰方法
表示这个方法不能被子类重写。
例如:Object类中的getClass()
class Father{public final void method(){System.out.println("father");}
}
class Son extends Father{public void method(){//错误System.out.println("son");}
}
【举例】
正常情况下:
class C{public void method(){}
}class D extends C{//此时可以public void method(){}
}
若是method()方法前面有final
修饰,就不能重写了。如下:
💬什么样的方法需要用final去修饰呢?
当这个方法已经设计的很完备了,也没有扩展的必要性,就可以用final修饰。
比如Object类中的getClass()
。
可以看一下,首先Ctrl+N
调出搜索框,输入“Object”:
然后Ctrl+F12
,搜索”getClass“:
然后可以看到getClass被final修饰,表示这个方法不能被重写了。这个方法的作用就是获取当前对象所属的类,不需要重写。
native
表示调用的是本地的方法,会调用底层C、C++相关的代码。
native修饰的getClass()方法若是调用的时候,这个方法的栈帧会进入栈中,此时它入的栈叫做本地方法栈。
这个本地方法,就是指native修饰的方法。
为啥getClass()方法没有方法体?因为它调用的是底层的C、C++,不是用java代码写的,所以没有方法体。它会链接到相关dll文件中的C、C++代码。
在早期,Java发展不成熟的时候,会用到native。
(3) final修饰变量
final修饰某个变量(成员变量或局部变量),一旦赋值,它的值就不能被修改,即常量
,常量名建议使用大写字母。
例如:final double MY_PI = 3.14;
如果某个成员变量用final修饰后,没有set方法,并且必须初始化(可以显式赋值、或在初始化块赋值、实例变量还可以在构造器中赋值)
1. 修饰成员变量
1.1 举例1
public class FinalTest {public static void main(String[] args) {E e=new E();System.out.println(e.MIN_SCORE); //可以调用}
}class E{//成员变量final int MIN_SCORE=0;
}
常量MIN_SCORE可以被调用,但是不能更改:
若此时将常量的显示赋值删掉,发现不可以:
没有默认值吗?
对于final
修饰的成员变量,这时候默认值就不好使了。即使想用默认值0,也需要写出来。
若用方法赋值,不可以:
方法需要用对象去调用,而调用对象的时候,这个值该有就应该得有了。
之前说过给类的实例变量赋值的位置,其中默认初始化、显示初始化、代码块中初始化、构造器中初始化,它们在造对象过程中实现;而通过“对象.属性”或“对象.方法”进行赋值的时候,对象已经有了。
现在我们给常量赋值,意思就是当创建完对象的时候,这些属性的值就应该要有了。
后续调用方法(比如setRight()方法),体现为修改这个值。
而在声明它的时候没有赋值,而在有了对象之后,方法里面又不能修改这个值。
当对象创建完,属性的值就应该确定下来了。
💬有哪些位置可以给成员变量赋值?
- 显式赋值
- 代码块中赋值
- 构造器中赋值
class E{//成员变量//1.默认赋值--NO//final int MIN_SCORE;//2.显示赋值--YESfinal int MIN_SCORE=0;//3.代码块中赋值--YESfinal int MAX_SCORE;{MAX_SCORE=100; //一旦赋值就不可以再次赋值}//4.构造器中赋值--YESfinal int LEFT;public E(){ //用此构造器造完对象LEFT就赋完值了LEFT=2;}public E(int left){ //不同构造器都需要对常量LEFT赋值,每造一个对象就会拥有一份LEFT,所以每个对象的LEFT可以不同,但是一旦赋值不可更改LEFT=left;}//5.方法赋值--NO/*final int RIGHT; //没有在允许的位置赋值public void setRIGHT(int right){RIGHT=right; //有了对象之后,不能在方法里面修改常量的值}*/}
1.2 举例2
public final class Test {public static int totalNumber = 5;public final int ID;public Test() {ID = ++totalNumber; // 可在构造器中给final修饰的“变量”赋值}public static void main(String[] args) {Test t = new Test();System.out.println(t.ID);}
}
2. 修饰局部变量
final修饰局部变量:一旦赋值就不能修改
2.1 举例1
- 方法内声明的局部变量:在调用局部变量前,一定需要赋值。而且一旦赋值,就不可更改。
【举例】
一般情况下:
class F{public void method(){int num=10;num++;System.out.println(num);}
}
若此时给num加上final,就不可以对num更改了:
如下:
class F{public void method(){final int num=10; //写两行也没事,只要在调用它之前赋上值就行,一旦赋值不可更改//num++;System.out.println(num);}
}
- 方法的形参:在调用此方法时,给形参进行赋值。而且一旦赋值,就不可更改。
【举例】
一般情况下:
class F{public void method(int num){num++;System.out.println(num);}
}
若是给num加上final
,num就是一个常量,这个常量还是在调用的时候赋的,那么赋完值之后就不要更改了。
如下:
class F{public void method(final int num){//num++; //赋完值之后就不要更改了System.out.println(num);}
}
2.2 举例2
public class TestFinal {public static void main(String[] args){final int MIN_SCORE ;MIN_SCORE = 0;final int MAX_SCORE = 100;MAX_SCORE = 200; //非法}
}
- 错误演示:
class A {private final String INFO = "atyuyi"; //声明常量public void print() {//The final field A.INFO cannot be assigned//INFO = "雨翼轻尘"; }
}
(4)final搭配static
final
与static
搭配:修饰成员变量时(不能是局部变量,static不能修饰局部变量),此成员变量称为:全局常量
。(只有一个且不能改变)
这个变量兼具final和static的特点。
比如:Math的PI (直接通过类来调用且不能变)
在实际写代码的时候,若是在修饰类、修饰方法的时候忘记使用不碍事,但是修饰变量的时候记得加上,而且变量名要大写。
(5)总结
1、 final
的理解:最终的
2、final
可以用来修饰的结构:类、方法、变量(成员变量、局部变量)
3、具体说明:
-
final修饰类:表示此类不能被继承。
比如:String、StringBuffer、StringBuilder类 -
final修饰方法:表示此方法不能被重写
比如:Object类中的getClass() -
final修饰变量:既可以修饰成员变量,也可以修饰局部变量。
此时的"变量"其实就变成了"常量",意味着一旦赋值,就不可更改。-
final修饰成员变量: 有哪些位置可以给成员变量赋值?
> 显式赋值
> 代码块中赋值
> 构造器中赋值 -
final修饰局部变量:一旦赋值就不能修改
> 方法内声明的局部变量:在调用局部变量前,一定需要赋值。而且一旦赋值,就不可更改
> 方法的形参:在调用此方法时,给形参进行赋值。而且一旦赋值,就不可更改
-
4、 final
与static
搭配:修饰成员变量时,此成员变量称为:全局常量。
比如:Math的PI
三、 笔试题
(1)题1
排错
public class Something {public int addOne(final int x) {//return ++x; //不可以return x + 1; //可以,x值没有变}
}
(2)题2
排错
public class Something {public static void main(String[] args) {Other o = new Other();new Something().addOne(o);}public void addOne(final Other o) {// o = new Other();o.i++; //让i++可以,因为i是变量,o不能变}
}
class Other {public int i;
}
局部变量o指向一个Other对象,Other对象里面有一个i,i没有用final修饰,表示它是一个变量。
将o加了一个final,意味着它的地址不能变了,而o指向的对象的属性可以变化。
如下: