1. 程式人生 > >6.8 final 關鍵字 和 6 . 8 . 1 f i n a l 資料

6.8 final 關鍵字 和 6 . 8 . 1 f i n a l 資料

6.8 final 關鍵字
由於語境(應用環境)不同,final 關鍵字的含義可能會稍微產生一些差異。但它最一般的意思就是宣告
“這個東西不能改變”。之所以要禁止改變,可能是考慮到兩方面的因素:設計或效率。由於這兩個原因頗
有些區別,所以也許會造成final 關鍵字的誤用。

在接下去的小節裡,我們將討論final 關鍵字的三種應用場合:資料、方法以及類。

6 . 8 . 1 f i n a l 資料
許多程式設計語言都有自己的辦法告訴編譯器某個資料是“常數”。常數主要應用於下述兩個方面:
(1) 編譯期常數,它永遠不會改變
(2) 在執行期初始化的一個值,我們不希望它發生變化
對於編譯期的常數,編譯器(程式)可將常數值“封裝”到需要的計算過程裡。也就是說,計算可在編譯期
間提前執行,從而節省執行時的一些開銷。在Java 中,這些形式的常數必須屬於基本資料型別
(Primitives),而且要用final 關鍵字進行表達。在對這樣的一個常數進行定義的時候,必須給出一個
值。
無論static 還是final 欄位,都只能儲存一個數據,而且不得改變。
若隨同物件控制代碼使用final,而不是基本資料型別,它的含義就稍微讓人有點兒迷糊了。對於基本資料類
型,final 會將值變成一個常數;但對於物件控制代碼,final 會將控制代碼變成一個常數。進行宣告時,必須將控制代碼
初始化到一個具體的物件。而且永遠不能將控制代碼變成指向另一個物件。然而,物件本身是可以修改的。Java
對此未提供任何手段,可將一個物件直接變成一個常數(但是,我們可自己編寫一個類,使其中的物件具有
“常數”效果)。這一限制也適用於陣列,它也屬於物件。
下面是演示final 欄位用法的一個例子:
//: FinalData.java
// The effect of final on fields
class Value {
int i = 1;
}
public class FinalData {
// Can be compile-time constants
final int i1 = 9;
static final int I2 = 99;
// Typical public constant:
public static final int I3 = 39;
// Cannot be compile-time constants:
final int i4 = (int)(Math.random()*20);
static final int i5 = (int)(Math.random()*20);
Value v1 = new Value();
final Value v2 = new Value();
static final Value v3 = new Value();
//! final Value v4; // Pre-Java 1.1 Error:
// no initializer
// Arrays:
final int[] a = { 1, 2, 3, 4, 5, 6 };
public void print(String id) {
System.out.println(
id + ": " + "i4 = " + i4 +
", i5 = " + i5);
}
public static void main(String[] args) {
FinalData fd1 = new FinalData();
//! fd1.i1++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(); // OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++; // Object isn't constant!
//! fd1.v2 = new Value(); // Error: Can't
//! fd1.v3 = new Value(); // change handle
//! fd1.a = new int[3];
fd1.print("fd1");
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData();
fd1.print("fd1");
fd2.print("fd2");
}
} ///:~
由於i1 和I2 都是具有final 屬性的基本資料型別,並含有編譯期的值,所以它們除了能作為編譯期的常數
使用外,在任何匯入方式中也不會出現任何不同。I3 是我們體驗此類常數定義時更典型的一種方式:public
表示它們可在包外使用;Static 強調它們只有一個;而final 表明它是一個常數。注意對於含有固定初始化
值(即編譯期常數)的fianl static 基本資料型別,它們的名字根據規則要全部採用大寫。也要注意i5 在
編譯期間是未知的,所以它沒有大寫。
不能由於某樣東西的屬性是final,就認定它的值能在編譯時期知道。i4 和i5 向大家證明了這一點。它們在
執行期間使用隨機生成的數字。例子的這一部分也向大家揭示出將final 值設為static 和非static 之間的
差異。只有當值在執行期間初始化的前提下,這種差異才會揭示出來。因為編譯期間的值被編譯器認為是相
同的。這種差異可從輸出結果中看出:
fd1: i4 = 15, i5 = 9
Creating new FinalData
fd1: i4 = 15, i5 = 9
fd2: i4 = 10, i5 = 9
注意對於fd1 和fd2 來說,i4 的值是唯一的,但i5 的值不會由於建立了另一個FinalData 物件而發生改
變。那是因為它的屬性是static,而且在載入時初始化,而非每建立一個物件時初始化。
從v1 到v4 的變數向我們揭示出final 控制代碼的含義。正如大家在main()中看到的那樣,並不能認為由於v2
屬於final,所以就不能再改變它的值。然而,我們確實不能再將v2 繫結到一個新物件,因為它的屬性是
final。這便是final 對於一個控制代碼的確切含義。我們會發現同樣的含義亦適用於陣列,後者只不過是另一種
型別的控制代碼而已。將控制代碼變成final 看起來似乎不如將基本資料型別變成final 那麼有用。
2. 空白final
Java 1.1 允許我們建立“空白final”,它們屬於一些特殊的欄位。儘管被宣告成final,但卻未得到一個
初始值。無論在哪種情況下,空白final 都必須在實際使用前得到正確的初始化。而且編譯器會主動保證這
一規定得以貫徹。然而,對於final 關鍵字的各種應用,空白final 具有最大的靈活性。舉個例子來說,位
於類內部的一個final 欄位現在對每個物件都可以有所不同,同時依然保持其“不變”的本質。下面列出一
個例子:
//: BlankFinal.java
// "Blank" final data members
class Poppet { }
class BlankFinal {
final int i = 0; // Initialized final
final int j; // Blank final
final Poppet p; // Blank final handle
// Blank finals MUST be initialized
// in the constructor:
BlankFinal() {
j = 1; // Initialize blank final
p = new Poppet();
}
BlankFinal(int x) {
j = x; // Initialize blank final
p = new Poppet();
}
public static void main(String[] args) {
BlankFinal bf = new BlankFinal();
}
} ///:~
現在強行要求我們對final 進行賦值處理——要麼在定義欄位時使用一個表達 式,要麼在每個構建器中。這
樣就可以確保final 欄位在使用前獲得正確的初始化。
3. final 自變數
Java 1.1 允許我們將自變數設成final 屬性,方法是在自變數列表中對它們進行適當的宣告。這意味著在一
個方法的內部,我們不能改變自變數控制代碼指向的東西。如下所示:
//: FinalArguments.java
// Using "final" with method arguments
class Gizmo {
public void spin() {}
}
public class FinalArguments {
void with(final Gizmo g) {
//! g = new Gizmo(); // Illegal -- g is final
g.spin();
}
void without(Gizmo g) {
g = new Gizmo(); // OK -- g not final
g.spin();
}
// void f(final int i) { i++; } // Can't change
// You can only read from a final primitive:
int g(final int i) { return i + 1; }
public static void main(String[] args) {
FinalArguments bf = new FinalArguments();
bf.without(null);
bf.with(null);
}
} ///:~
注意此時仍然能為final 自變數分配一個null(空)控制代碼,同時編譯器不會捕獲它。這與我們對非final 自
變數採取的操作是一樣的。
方法f()和g()向我們展示出基本型別的自變數為final 時會發生什麼情況:我們只能讀取自變數,不可改變
它。

相關推薦

6.8 final 關鍵字 6 . 8 . 1 f i n a l 資料

6.8 final 關鍵字 由於語境(應用環境)不同,final 關鍵字的含義可能會稍微產生一些差異。但它最一般的意思就是宣告 “這個東西不能改變”。之所以要禁止改變,可能是考慮到兩方面的因素:設計或效率。由於這兩個原因頗 有些區別,所以也許會造成final 關鍵字的誤用。

Final關鍵字類的自動加載

使用 可變 自動 lin 關鍵字 修飾 我們 pan tle Final關鍵字: 父類中的方法被聲明為 final,則子類無法覆蓋該方法。如果一個類被聲明為 final,則不能被繼承。 一般是為了防止父類的一個方法被重寫。只能用來定義類和定義方法, 不能使用final這個關

Java中的final關鍵字 Java中的抽象類

Java中的final關鍵字 使用final宣告的類不能被繼承; 使用final宣告的方法不能被子類覆蓋; 使用final宣告的變數不能被修改,即為常量; Java中的抽象類 定義:在java中,含有抽象方法的類稱為抽象類,抽象類不能生成物件; 注意點: 1,包

Java基礎4——深入理解final關鍵字static關鍵字以及初始化順序

深入理解final關鍵字和static關鍵字以及初始化順序 final關鍵字(基礎1中提到) final關鍵字可以修飾類、方法和引用。 修飾類,該類不能被繼承。並且這個類的物件在堆中分配記憶體後地址不可變。 修飾方法,方法不能被子類重寫。 修飾引用,引用無法改變,對於基本型別,無法修

第十七課 final關鍵字abstract關鍵字

 一、final關鍵字final(最終)是一個修飾符 1.final可以修飾類,函式,變數(成員變數,區域性變數) 2.被final修飾後的類不可以被其他類繼承 3.被final修飾後的函式不可以被重寫 4.被final修飾後的變數不允許被再次賦值,final在對變數進

求自然數的前n,如1+2!+3!+...+n!

#include <stdio.h> int main() {int i, j, n;float sum = 0,tmp;printf("Please input a number:");while(1){if(scanf("%d",&n) != 1 |

ACMNO.16用迭代法求 。求平方根的迭代公式為: X[n+1]=1/2(X[n]+a/X[n]) 要求前後兩次求出的得差的絕對值少於0.00001。 輸出保留3位小數 輸入 X 輸出 X的

題目描述 用迭代法求 。 求平方根的迭代公式為: X[n+1]=1/2(X[n]+a/X[n]) 要求前後兩次求出的得差的絕對值少於0.00001。 輸出保留3位小數 輸入 X 輸出 X的平方根 樣例輸入 4 樣例輸出 2.000 來

五周第四次課(1月11日) 8.6 管道符作業控制 8.7/shell變量 8.8 shell變量 8.9 環境變量配置文件

pool res boot sda gpo img ifd 變量名 選項 五周第四次課(1月11日)8.6 管道符和作業控制8.7/shell變量8.8 shell變量8.9 環境變量配置文件擴展bashrc和bash_profile的區別 http://ask.ape

64位 WIN 7/8 下VS2010配置CLAPCAK3.2.1Levmar2.6

由於在影象拼接程式中要用到LM演算法,本人程式設計能力太弱,只好藉助於庫函式。看到網上教程有用Levmar(FAQ)來做LM演算法的。Levmar可用於C++, Matlab,Perl, Python, Haskell and Tcl。本人在VS2010下程式設計,所以下面只談談如何在VS2010下

centos 6.9 x64 yum安裝PHP 7.1.8

php 安裝 centos 6.9 x64 yum安裝PHP 7.1.8安裝源yum install epel-releaserpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm根據你的需要安裝PHP的組件,下面我就安裝所有的了。yum inst

2.6相對絕對路徑;2.7CD命令;2.8創建刪除目錄mkdir rmdir;2.9rm命令

創建刪掉目錄命令 絕對路徑和相對路徑2.6 相對和絕對路徑1. 查看當前在哪個目錄下:pwd[root@hao-01 ~]# pwd/root (當前在root目錄,root目錄是在/(根)下的目錄!)絕對路徑:從/(根),開始的路徑(不管當前在哪個目錄下,都可以根據絕對路徑找到的路徑)[root@

2.6 相對絕對路徑 2.7 cd命令 2.8 創建刪除目錄mkdir/rmdir 2.9 rm

cd mkdir rmdir 2.6 相對和絕對路徑1、相對與絕對路徑絕對路徑:是從根開始的,也就是/相對路徑:是從相對當前的路徑[root@wangborambo ~]# ls .ssh/authorized_keys.ssh/authorized_keys[root@wangborambo ~

2.6 相對絕對路徑 2.7 cd命令 2.8 創建刪除目錄2.9 rm命令

ado mdi 51cto etc col 例如 sco images 圖片 絕對路徑的概念:從“/”開始的均為絕對路徑,例如我們常用的網卡配置文件/etc/sysconfig/network-scripts/ifcfg-ens33,這就是一個絕對路徑文件。相對路徑的概念:

Centos6.8 安裝mongo3.6以及許可權配置開啟外網連結

目錄 安裝環境和版本說明,以及參考文件連結 安裝MongoDB資料庫 執行MongoDB資料庫 刪除解除安裝MongoDB 配置MongoDB管理員使用者 修改配置檔案,允許外網連結 安裝配置完成,使用Robo3T測試連結 總結 安裝環境和版本說明,以及參考文件連結

Mathtype6.86.9註冊碼

數學型別6.8版本 MTWE681-003461-MDZ1Q MTWE681-010798-1CRH5 數學型別6.9版本 MTWE697-001207-BEAHM MTWE697-004306-6BOJ8 MTWE697-011578-HH7CT MTWE697-006409-95

CentOS release 6.8 (Final)下使用vsftpd 搭建ftp

啟動vsftpd service vsftpd start 如果沒有安裝則需要先安裝 yum install vsftpd* -y 安裝完成進入安裝路徑 cd /etc/vsftpd vi vsftpd.conf 貼出我自己配置的引數 local_ena

CentOS-6.4-x86_64-bin 安裝JDK1.8 Tomcat 8

JDK 安裝 JDK 安裝包:jdk-8u161-linux-x64.tar.gz 安裝在 usr/jdk(新建目錄) 解壓命令:tar -zxvf jdk-8u161-linux-x64.tar.gz 配置jdk環境:vim /etc/profile 回車 末尾加jdk環境

HashMap原始碼分析-jdk1.6jdk1.8的區別

在java集合中,HashMap是用來存放一組鍵值對的數,也就是key-value形式的資料,而在jdk1.6和jdk1.8的實現有所不同。 JDK1.6的原始碼實現: 首先來看一下HashMap的類的定義: HashMap繼承了AbstractHashMap,實現

win10 + python3.6 + tensorflow-gpu 1.8 下安裝 CUDA9.0 +CUDNN7.1.4

1.使用anaconda建立tensorflow環境,我的筆記本有塊gtx 765顯示卡,所以使用的是tensorflow gpu,並更新到1.8版本 2.官網更新最新顯示卡驅動,安裝cuda9.0    精簡安裝即可      解壓後複製到CUDA

Windows 8 Python 3.6 下安裝 TensorFlow keras

     這兩天安裝TensorFlow和keras(基於TensorFlow)踩了不少坑,特此總結。     安裝tensorflow主要有兩種方式:原環境安裝(不推薦)和虛擬環境安裝(推薦)。1、原環境安裝(各種坑):      將tensorflow作為一個普通工具包安