- Java中final有三種主要用法:
- C++中final只有兩種:
- C++中const:
- 修飾變量(基本類型變量、成員變量):
- const與引用:
- const與指針:"const在*前,數據不能改,const在*後,指針不能改"
- const在函數中的應用:
- const修飾對象:
Java中final有三種主要用法:
-
修飾變量:final變量是不可改變的,但它的值可以在運行時刻初始化,也可以在編譯時刻初始化,甚至可以放在構造函數中初始化,而不必在聲明的時候初始化,所以下面的語句均合法:
final int i = 1; // 編譯時刻 final int i2 = (int)(Math.Random() * 10); //運行時刻 final int i3; //構造函數裏再初始化final經常和static一起用,這種用法類似C++的常量,在Java中很常見,比如
static final i = 10;但這裏同樣也是允許運行時刻初始化的。 -
修飾類對象:而如果修飾類對象,並不表示這個對象不可更改,而是表示這個這個變量不可再賦成其它對象,這就比較像 C++的
Class const * p了(這樣表明這個指向該Class的指針p不能再指向其他對象,指針常量,但是該對象中的值是可以修改的(const Class *p是常量指針,任何成員變量都不能修改))。final Value v = new Value(); v = new Value(); //不允許! v.some_method(); //允許 -
修飾方法:final修飾的方法是不能被重載的,類似於類中的private方法,所以private方法默認是final的;大致説就是變量不可修改(基本數據類型值不能修改,類類型引用不能修改),方法不可重載,類不可繼承,
C++中final只有兩種:
-
修飾類
-
修飾虛函數
C++中const:
C++中的const用處很多,包括常量聲明、變量修飾、常量引用、指針與const的組合、以及常量對象、成員函數。
修飾變量(基本類型變量、成員變量):
-
修飾基本類型變量
修飾變量也可以叫作常量的聲明,使用
const關鍵字可以修飾變量,一旦初始化後就不能再修改其值。const int MAX = 123; const double PI = 3.14; const int x = 334;以上的MAX、PI、x將都不能再修改其值;
const定義的常量和#define宏定義的常量的區別const常量有數據類型,define宏定義常量沒有,編譯器會對const常量可以進行數據類型的安全檢查,但是對於define宏定義,編譯器只是將其進行字符替換,這樣的字符替換很容易出錯。
比如以下代碼,如果使用不加括號的宏定義,將不能正確計算(a+b)/5.0,而是變成計算a+(b/5.0)了。
//define宏定義的做法 #define a 2.0 #define b 9.0 #define c1 a+b //不好的定義方法 #define c2 ((a)+(b)) //推薦的定義方法 void func1(void) { float d1 = c1/5.0; //本意是想計算(a+b)/5.0,但字符替換使計算變成了a+b/5.0 float d2 = c2/5.0; //正確計算了((a)+(b))/5.0 = (a+b)/5.0 } //推薦的const常量的做法 const float a = 2.0; const float b = 9.0; const float c = a + b; void func2(void) { float d = c/5.0; //正確計算了(a+b)/5.0 } -
修飾成員變量:在類中,使用
const修飾的成員變量只能在初始化列表中進行初始化,並且不能在構造函數中修改其值。class MyClass { public: const int x; MyClass(int value) : x(value) {} // 初始化const修飾的成員變量 };這段代碼定義了一個類
MyClass,其中有一個const修飾的整型成員變量x。在構造函數的初始化列表中對x進行初始化,且只能在初始化列表中初始化,不能在構造函數內部修改其值。
const與引用:
const引用可以綁定到臨時對象或字面量,延長其生命週期。
用這種方式聲明的引用,不能通過引用對目標變量的值進行修改,從而使引用的目標成為const,達到了引用的安全性。
const int& ref = 10; // 合法
// int& ref2 = 10; // 非法:非常量引用不能綁定字面量
int x = 10;
const int& a = x;
x = 5;
const與指針:"const在*前,數據不能改,const在*後,指針不能改"
-
常量指針:
形式:
const type* ptr(推薦) 或type const* ptr這裏可以理解為 const修飾的是type類型的數據:(const type)* ptr 或 (type const)* ptr,也就是説不能通過ptr修改值,但ptr可以指向其他地址。
int a = 10, b = 20; const int* ptr = &a; *ptr = 30; // 錯誤:不能修改指向的數據 ptr = &b; // 正確:可以改變指針指向"const在*前,數據不能改"
-
指針常量:
形式:
type* const ptr這裏可以理解為const修飾的是ptr:也就是説ptr一旦初始化指向之後就不能指向其他地址,但可以通過指針修改所指向的數據。
int a = 10, b = 20; int* const ptr = &a; *ptr = 30; // 正確:可以修改a的值 ptr = &b; // 錯誤:不能改變指針指向"const在*後,指針不能改"
-
指向常量 的 常量指針:
形式:
const type* const ptr或type const* const ptr既不能修改指針指向,也不能通過指針修改數據。
int a = 10, b = 20; const int* const ptr = &a; *ptr = 30; // 錯誤 ptr = &b; // 錯誤
const在函數中的應用:
-
const形參:避免函數內意外修改參數,常用於指針或引用傳參。
void print(const int* arr, int size) { for (int i = 0; i < size; ++i) std::cout << arr[i] << " "; // 只讀訪問 } -
const成員函數:const修飾類成員函數,實際修飾該成員函數隱含的this指針,表明在該成員函數中不能對類的任何成員進行修改。
class MyClass { int value; public: int getValue() const { return value; } // 不會修改對象狀態 }; -
const返回值:也是用const來修飾返回的指針或引用,保護指針指向的內容或引用的內容不被修改,也常用於運算符重載。
函數三種返回類型:返回值、返回引用(&)、返回指針(*);
-
返回值:
現在返回值使用const幾乎沒有意義,例如:
const int ten(){ return 10; //返回值是一個臨時對象 } //在後續的賦值中 const int x = ten();在c++11之後,臨時對象本來就不能被修改,所以
const int ten()和int ten()本質上效果一樣。 -
返回引用或者指針(這裏用引用舉例,指針一樣的道理):
引用返回值不是重新創建一個對象,而是直接把函數內部(或外部某處)的對象引用返回給調用者;
這樣將不會產生對象拷貝(性能高),調用者直接訪問的就是原對象。
給引用加
const可以保護原對象不被調用者修改,例如:class A { public: int& getValue2(){ return m_value; } const int& getValue(){ return m_value; } private: int m_value = 10; }; int main() { A a; a.getValue() = 100; //不允許修改 a.getValue2() = 111; //直接修改成員 }getValue()將不允許修改成員變量m_value,而getValue2()將會直接修改成員變量m_value;
一般get函數會被const修飾
const int& getValue const(){return m_value}這樣函數內的成員變量也會被const修飾,不允許修改。在返回const引用要注意:返回對象的生命週期必須比函數長,例如:
const int& backNum() { int num = 1; return num; //錯誤:num會在函數結束後消失,這塊內存的位置也會給其他變量用 } void otherFunc() { int a = 100; int b = 200; } int main() { const int& c = backNum(); otherFunc(); cout << c << endl; }這樣的引用指向在程序複雜的時候會造成懸空引用,未定義行為等危險。
-
const修飾對象:
const修飾的對象,其成員變量都不能被修改。
class MyClass {
public:
int x;
};
const MyClass obj; // 常量對象
// obj.x = 10; // 錯誤,常量對象的成員變量不能被修改