Java中final作用于變量、參數(shù)、方法及類該如何處理
Java中方法用final修飾參數(shù)的作用
在方法參數(shù)前面加final關(guān)鍵字就是為了防止數(shù)據(jù)在方法體重被修改。
主要分為兩種情況:第一,用final修飾基本數(shù)據(jù)類型;第二,用final修飾引用數(shù)據(jù)類型。
第一種情況,修飾基本數(shù)據(jù)類型,這時參數(shù)的值在方法體內(nèi)是不能被修改的,即不能被重新賦值。否則編譯就不通過。
第二種情況,修飾引用類型。這時參數(shù)變量所引用的對象是不能被改變的。但是對于引用數(shù)據(jù)類型,如果修改其屬性的話是完全可以的。
所以,final這個關(guān)鍵字,想用的話就用基本數(shù)據(jù)類型,還是很有作用的。
final變量:
對于基本類型使用final:它就是一個常量,數(shù)值恒定不變
對于對象引用使用final:使得引用恒定不變,一旦引用被初始化指向一個對象,就無法再把 它改為指向另一個對象。然而,對象自身卻是可以被修改的,java并沒有提供使任何對象恒定不變的途徑。這一限制同樣也使用數(shù)組,它也是對象。
例子:
class Value{
int i;
public Value(int i){
this.i = i;
}
}
public class FinalData {
private static Random random = new Random(47);
private String id;
public FinalData(String id){
this.id = id;
}
private final int valueOne = 9;
private static final int VALUE_TWO = 99;
public static final int VALUE_THREE = 39;
private final int i4 = random.nextInt(20);
static final int INT_5 = random.nextInt(20);
private Value v1 = new Value(11);
private final Value v2 = new Value(22);
private static final Value VAL_3 = new Value(33);
private final int[] a = {1, 2, 3, 4, 5, 6};
public String toString(){
return id + ": " + "i4 = " + i4 + ", INT_5 = " + INT_5;
}
public static void main(String[] args) {
FinalData fd1 = new FinalData("fd1");
//! fd1.valueOne++; // 因為valueOne是基本類型常量,其數(shù)值恒定不變
fd1.v2.i++; //final修飾的對象的內(nèi)容可以改變
fd1.v1 = new Value(9);
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++;
//! fd1.v2 = new Value(0); // 因為v2是final修飾的引用類型,其引用不能被修改指向另一個對象
//! fd1.VAL_3 = new Value(1); // 表示占據(jù)一段不能改變的內(nèi)存空間
//! fd1.a = new int[3]; // final修飾的數(shù)組
System.out.println(fd1);
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData("fd2");
System.out.println(fd1);
System.out.println(fd2);
}
}
/*output:
fd1: i4 = 15, INT_5 = 18
Creating new FinalData
fd1: i4 = 15, INT_5 = 18
fd2: i4 = 13, INT_5 = 18
*/
分析:
對于fd1,fd2兩個對象,其中i4是唯一的,即每個對象都有一個i4,但INT_5被聲明為static,即是類共享的,fd1和fd2共享INT_5,在裝載時已經(jīng)被初始化,而不是每次創(chuàng)建新對象時初始化(例如i4);但它同時被設(shè)置成final,所以它的引用是不可改變的,即不能被修改指向另一個對象。
空白final:
被聲明為final但又沒有給定初值。必須在域的定義或者每個構(gòu)造器中使用表達式對final進行賦值,這正是final域在使用前總是初始化的原因。
final參數(shù):
這意味著你無法在方法中更改參數(shù)引用,使其指向另一個參數(shù),但可以修改final對象所指向的內(nèi)容
例子:
class Gizmo{
int i = 0;
public void spin(){}
}
public class FinalArguments {
void with(final Gizmo g){
//! g = new Gizmo(); // 無法修改final修飾的引用,使它指向另一個對象
g.i++; // 但可以修改final對象所指向的內(nèi)容
}
void without(Gizmo g){
g = new Gizmo();
g.spin();
}
// int g(final int i){
// //! i++; //因為參數(shù)i是常量值
// }
int g(final int i){
return i + 1;
}
public static void main(String[] args) {
FinalArguments bf = new FinalArguments();
bf.without(null);
bf.with(null);
}
}
分析:
參數(shù)被聲明為final,若是基本參數(shù),那它就是一個常量,不能被修改;若是一個引用變量,那么它就不能被修改指向另一個對象,但可以修改該引用所指對象的內(nèi)容。
fianl方法:
使用原因:
- 把方法鎖定,以防任何繼承類修改它的含義,即該方法不會被繼承的類覆蓋
- 效率,若一個方法指明為final,那么就同意編譯器將針對該方法的所有調(diào)用轉(zhuǎn)為內(nèi)嵌調(diào)用。
類中所有的private方法都隱式地指定為final,由于無法取用private方法,所以也就無法覆蓋它。可以對private方法添加final修飾詞,但這并不會給該方法帶來任何額外的意義。
例子:
class WithFinals{
private final void f(){
System.out.println("WithFinals.f()");
}
private void g(){
System.out.println("OverridingPrivate.f()");
}
}
class OverridingPrivate extends WithFinals{
private final void f(){
System.out.println("OverridingPrivate.f()");
}
private void g(){
System.out.println("OverridingPrivate.g()");
}
}
class OverridingPrivate2 extends OverridingPrivate{
/*
* 當(dāng)使用Override注解強制使f()方法覆蓋父類的f()方法時,會報錯
* 因為它不知道父類是否有該方法,對于g()方法來說,它只是生成了一個新的方法,
* 并沒有覆蓋掉父類中的g()方法。
*/
//@Override
public final void f(){
System.out.println("OverridingPrivate2.f()");
}
public void g(){
System.out.println("OverridingPrivate2.g()");
}
}
public class FinalOverridingIllusion{
public static void main(String[] args) {
OverridingPrivate2 op2 = new OverridingPrivate2();
op2.f();
op2.g();
// 可以向上轉(zhuǎn)型
OverridingPrivate op = op2;
//! op.f(); // 父類中final方法對子類來說是不可見的
//! op.g();
WithFinals wf = op2;
// wf.f();
// wf.g();
}
}
/*output:
OverridingPrivate2.f()
OverridingPrivate2.g()
*/
分析:
覆蓋何時發(fā)生:
1,子類中出現(xiàn)與父類完全一致的方法
2. 子類可以通過向上轉(zhuǎn)型為父類,并調(diào)用父類中的那個方法
若父類中某個方法被聲明為final或者private,那么這個方法對子類來說是不可見的,就算在子類中創(chuàng)建了與父類一模一樣的方法,這也是一個新的方法,而不是從父類中覆蓋的方法。
final類:
即該類不能被繼承,不管是你還是別人,也就是這個類不需要做任何變動,也不需要任何子類,例如String類。
例子:
class SmallBrain{}
final class Dinosaur{
int i = 7;
int j = 1;
SmallBrain x = new SmallBrain();
void f(){}
}
// error: The type Further cannot subclass the final class Dinosaur
// Dinosaur類不能有子類
// class Further extends Dinosaur{}
public class Jurassic {
public static void main(String[] args) {
Dinosaur n = new Dinosaur();
n.f();
n.i = 40;
n.j++;
}
}
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
SpringBoot攔截器實現(xiàn)項目防止接口重復(fù)提交
基于SpringBoot框架來開發(fā)業(yè)務(wù)后臺項目時,接口重復(fù)提交是一個常見的問題,本文主要介紹了SpringBoot攔截器實現(xiàn)項目防止接口重復(fù)提交,具有一定的參考價值,感興趣的可以了解一下2023-09-09
Java獲取年月日(格式:xxxx年xx月xx日)的方法詳解
在開發(fā)應(yīng)用程序時,經(jīng)常需要獲取當(dāng)前的年、月、日,并以特定格式進行展示或處理,本文將介紹如何獲取年月日,并將其格式化為“xxxx年xx月xx日”的形式,幫助你在應(yīng)用程序中處理日期信息,需要的朋友可以參考下2023-10-10
Springboot中如何使用Redisson實現(xiàn)分布式鎖淺析
redisson是redis的java客戶端程序,國內(nèi)外很多公司都有在用,下面這篇文章主要給大家介紹了關(guān)于Springboot中如何使用Redisson實現(xiàn)分布式鎖的相關(guān)資料,需要的朋友可以參考下2021-10-10
Java實現(xiàn)駝峰下劃線互轉(zhuǎn)的使用示例
駝峰和下劃線互轉(zhuǎn)場景是在不同命名規(guī)范的情況下,需要進行字段名稱的轉(zhuǎn)換,本文就來介紹一下Java實現(xiàn)駝峰下劃線互轉(zhuǎn)的使用示例,感興趣的可以了解一下2023-12-12
Mybatis批量插入index out of range錯誤的解決(較偏的錯誤)
這篇文章主要介紹了Mybatis批量插入index out of range錯誤的解決(較偏的錯誤),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
java中獲取當(dāng)前服務(wù)器的Ip地址的方法
本篇文章主要介紹了java中獲取當(dāng)前服務(wù)器的Ip地址的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
spring中@Autowire和@Resource的區(qū)別在哪里(推薦)
這篇文章主要介紹了spring中@Autowire和@Resource的區(qū)別在哪里?本文結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-02-02

