Overview of Content
本文將帶您深入研究 Java 的基礎類型、編碼、浮點數、參考類型和變數作用域
我們將從 Java 字元編碼、常見編碼和手動運算 Unicode 編碼轉 UTF8 開始,深入瞭解 Java 編碼的概念。接著,我們將探討 Java 浮點數的計算方式、浮點數誤差和 Java 提供的特殊數字
然後,我們會討論參考類型,包括基本類型和參考類型,以及物件的預設參考 this
最後,我們將探討變數作用域,包括一般變數和靜態變數,以及變數的初始化和預設值。無論您是初學者還是有經驗的開發者,本文都將為您提供深入且全面的Java知識,助您更好地理解和應用基礎概念。
寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀
Java 基礎類型
Java 語言將資料類型分為 基本類型、參考類型,如下表展示… 並本篇會依據幾個特別、大家容易稿混的類型進行說明
A. 基本類型 如下表
基本類型 | 補充 |
boolean | - |
float | 數值類型(浮點數) |
double | 數值類型(浮點數) |
byte | 數值類型(整數類) |
short | 數值類型(整數類) |
int | 數值類型(整數類) |
long | 數值類型(整數類) |
char | 數值類型(字符類) |
● Java 編譯器會將 Java 編譯為 Bytecode 時,會用 int、byte 來表示 boolean
B. 參考類型 如下表
參考類型 | 稱呼 |
class | 類別 |
interface | 界面 |
array | 陣列 |
Java 編碼
Java 字元編碼、常見的編碼:Unicode 產生
● char 是字元類型,Java 大多採用 Unicode
字元編碼
Unicde
編碼也就是UTF-16BE
● 字元編碼 是什麼概念?
用一串特定的二進位碼來標示特定得字元,就像是一個 Mapping 表單一樣
● 常見的 字元編碼 如下表
字元編碼 | 字元、字節數 | 簡單介紹 |
ASCII | 7 bit | 當今最通用單字節碼,美國資訊互換標準程式碼,是為 羅馬字母編制的編碼,主要用於表達現代英語、西歐語言 |
ISO-8859-1 (Latin-1 ) | 8 bit | 國際標準化組織 (IOS) 為 西歐語言 的字元碼制定的編碼,與 ASCII 相容 |
GB2312 | 2 byte | 簡中編碼,與 ASCII 相容 |
GBK | 2 byte | 漢字編碼,與 GB2312 相容 |
Unicode , UCS | 2 or 4 byte (後面說明) | 收入全世界所有語言的編碼,UCS (Universl Character Set) 是指採用 Unicode 字元編碼的通用字元集,單位為碼元(Code point ) |
UTF8 、UTF16 | 1~16 byte | 將 Unicode 轉換為「作業系統」支援的編碼!單位為碼點(Code unit ) |
●
Unicode
分為 2 種字元編碼● 使用 2byte 編碼:又稱為
UCS-2
,也是 Java 採用的位元組編碼方案● 使用 4byte 編碼:又稱為
UCS-4
● Java
語言如果要使用 Unicode
則需要 使用 \u
開頭標注
● Unicode 產生是因為,原本在 1990 年左右有兩個團隊(ISO/IEC
、Unicode Consortium
)都打算統一字元集合… 其思想很簡單,單純的使用 Mapping 的方式,將碼點(Code point
)對應上碼元(Code unit
)
ISO/IEC
搶先在 1990 年發布第一套字元集編碼UCS-2
,這種編碼的碼元就是兩個 Byte 大小
然而兩個團隊很快意到一個世界不需要兩種統一編碼,最後決定合併,才發佈了 Unicode 1.0
(也就是 UCS-2
),然而人類的字元統計過後漸漸超過 2 Byte,後來才出現 UCS-4
編碼
● UTF-16 可以說是容納
UCS-2
、UCS-4
編碼UTF-16 會依照字元在哪個碼點(
Code point
)去對應到UCS-2
、UCS-4
編碼● 像是 Java、JavaScript 兩種語言,在計算字元長度時就是使用 UTF-16 的「碼元」作為長度計算
手動運算 Unicode 編碼轉 UTF8
● UTF8
就是以 1 個 Byte 為單位對 UCS
(Unicode) 編碼,使用遮罩的方式將 UCS
編碼資料填入 UTF8
編碼;範例如下… 我們將 Unicode 編碼轉 UTF8
USC-2 編碼範圍(16 進位) | UTF8 遮罩(2 進位) |
0000-007F | 0xxx xxxx |
0080-07FF | 110x xxxx 10xx xxxx |
0800-FFFF | 1110 xxxx 10xx xxxx 10xx xxxx |
● 「漢」USC-2
轉「漢」UTF8
A. Unicode
編碼為 16 進位資料 0x6C49
B. 對照上表找到編碼範圍:0x6C49
至於 USC-2
編碼範圍 0800-FFFF
C. 將 「漢」的 0x6C49
轉為 2 進位 0110 110001 001001
D. 將其套上 UTF8
遮罩就變為 E6 B1 89
,也就是「漢」這個字使用在 UTF8 上表示時的編碼
「漢」Unicode 編碼 | 「漢」2 進位 | 「漢」USC-2 編碼區間 | 「漢」UTF8 遮罩 | 套上遮罩後 |
0x6C49 | 0110 110001 001001 | 0800-FFFF | 1110 xxxx 10xx xxxx 10xx xxxx | 1110 0110 1011 0001 1000 1001 |
Java 浮點數類型
Java 的浮點數類型有兩種,分別是 float
、double
類型,這裡我們就要說明浮點數的計算方式、浮點數誤差、Java 提供的特殊數字
Java 計算浮點數的方式:浮點數規則
● Java 語言的 float
、double
類型 遵循 IEEE754
標準,該標準分別為 32、64 位元浮點數規定二進位資料表示形式,主要由 3 個元素組成,如下表
元素 | 說明 | bit 數量(加起來總共 32 bit) |
S | 符號位元,表示正負 | 1 |
E | 指數 | 8 |
M | 尾數 | 23 |
// 32 bit 的 float 的二進位表示,透過固定規則就可以轉換為浮點數
SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMM
● float 類型的二進位資料 儲存規則,會牽涉到 隱含位元
、階碼
● 隱含位元:尾數 M
之前有一個 隱含位元,隱含位元為 1.
or 0.
兩種,而使用哪個取決於指數 M
、E
元素 M 值 | 元素 E 值 | 隱含位元 |
非 0 | 1 ~ 254 | 1. |
非 0 | 其他 | 0. |
● 階碼:階碼採用移碼表示,對應表如下
元素 M 值 | 元素 E 值 | 階碼 |
非 0 | 1 ~ 254 | E-127 |
非 0 | 0 | -126 |
● 換算格式:(-1)S * 2階碼 * (隱含位元);範例如下
● 5.0f
的轉換
● 二進位: 0 10000001 01000000000000000000000
查表可對應到:隱含位元
1.
、階碼為E-127
● 隱含位元:由於 E
為 10000001
也就是 129,在 1 ~ 254
之間,所以隱含位元為 1.
● 套上公式計算:(-1)0 * 2129-127 * 1.01000000000000000000000
,也就是 22 * 1.01000000000000000000000
透過位元移動 2 位,所以最終就是 101.000000000000000000000
也就是 5(解答!)
浮點數誤差
● 由上 Float 浮點數計算規則可知,尾數數值越多,精度越高,而 double 精度又比 float 高,測試範例如下
● float 精度測試
public void testFloat() {
float res = 0, testTime = 26;
while (testTime > 0) {
res += 0.1f;
testTime--;
}
System.out.println("float add 26 times: " + res);
}
● double 精度測試
public void testDouble() {
double res = 0, testTime = 26;
while (testTime > 0) {
res += 0.1f;
testTime--;
}
System.out.println("double add 26 times: " + res);
}
● 在某些場合會特別注重浮點數的誤差(像是銀行的業務),如果要表示任意精度的資料,可以使用
BigDecimal
類
Java 提供的特殊數字
● 在浮點數計算中,如果 科符記號 E
為 255,那就用來表示一些 特殊數字,如下表
特殊數字 | 二進位 |
Float.NaN 非數字 | 0111 1111 1100 0000 0000 0000 0000 0000 |
Float.POSITIVE_INFINITY 正無窮大 | 0111 1111 1000 0000 0000 0000 0000 0000 |
Float.NEGATIVE_INFINITY 負無窮大 | 1111 1111 1000 0000 0000 0000 0000 0000 |
public void testSpecialNum() {
float nan = (float) (0.0 / 0.0);
System.out.println(nan);
float pos = (float) (1.0 / 0.0);
System.out.println(pos);
float neg = (float) (-1.0 / 0.0);
System.out.println(neg);
}
● 計算、程式中,科學記號的差異
差異在 底數,程式中,科學記號 E 的底數為 10,這是為了符合一般人的計算標準;而在 電腦中則是使用 2 進位作為科學記號 E 的底數(方便電腦識別)
Java 參考類型
Java 是物件導向語言,隱藏了物件在 JVM 內的真實地址,使用 參考類型 (引用的概念)
像是 C 語言,就把變數地址暴露給開發者使用
而 Java 的參考類型有 3 個
● 類別(Class
)參考
● 界面(Interface
)參考
● 陣列參考(在 Java 中,陣列也被視為物件)
● 類別類型、類別參考類型
class Hello { public static void main(String[] args) { // Hello hello,中的 Hello 是類別「參考」類型 // new Hello(),中的 Hello 則是「類別類型」 Hello hello = new Hello(); } }
基本類型、參考類型
● 基本類型:也就是 Java 的基礎八大類型(布林、整數、浮點數...),在記憶體中佔有實體位置,數據多大就佔多少空間位置
● 參考類型:參考類型包裝多個基礎類型(也可以包裝其他參考類型),在記憶體中佔固定大小位置(指針),指針指向 JVM 堆區中的實體位置
// 參考類型
class Hello {
// 基本類型
int foo = 100;
long bar = 30000L;
// 參考類型
int[] fooArray = {10, 20, 30};
String object = "HelloWorld";
public static void main(String[] args) {
Hello hello = new Hello();
}
}
參考類型須使用
new
關鍵字創建下圖中,類別「參考類型」在 JVM 模型中的位置,類別「參考類型」是放在方法區的 對象(物件)類型
物件的預設參考:this
「物件」說的是實體資料(
instance
),反觀「類」則是物件的模板
● 當物件建立好後,JVM 會分類一個參考自身物件得引用 this
,透過 this
可以傳遞、訪問當前物件(instance)
● 物件建立完成後才會建立出
this
引用,如果在物件尚未建立完成時去使用子類,則很可能導致無法取得當前引用
class Hello {
Hello() {
// 將自身引用傳入到令一個物件,令一個物件就可以調用該 instance
new World().startHello(this);
}
String getMsg() {
return "Hello";
}
}
class World {
public void startHello(Hello hello) {
System.out.println(hello.getMsg());
}
}
變數作用域
● 變數的作用域是指 它的存在範圍,不在範圍內部可訪問
● 變數存活的生命週期,不同描述的變數會有不同的生命週期限制,一般變數生命週期都至於花括號 { }
之中
一般變數、靜態變數
● 一般變數:一般變數區域會 存在 JVM 堆區、棧區,常見如下表
變數區域 | 作用區域 | 生命週期 |
全域變數 (堆區) | 這裡的全域,是指 Java 類中的全域,作用域是整個類中 | 與物件同進退 |
區域變數 | 只存在花括號之間的變數,外部不可使用 | 只存在 {} 中 |
方法參數 | 作用域是方法開始、到結束 | 只存在 {} 中 |
例外處理參數 | catch 區塊內的變數 | 只存在 {} 中 |
class Hello {
// 全域變數 msg
String msg = "My message";
void myFunction(int value) { // 方法參數 value
// 區域變數 showValue
int showValue = value * value;
try {
// 區域變數 str
String[] str = msg.split(" ");
// 區域變數 firstStr
String firstStr = str[0];
System.out.println("Show value " + showValue + ", msg: " + firstStr);
} catch (Exception e) {
// 例外處理參數 e
e.printStackTrace();
}
}
}
● 當基礎類型、引用類型傳入方法時,是不同的狀態!
● 基礎類型傳入方法時,是使用 複製數值 的方式來將參數傳入,修改方法內的參數,並不會影響外部變數
● 引用類型傳入方法時,是直接將 引用傳入,所以在內部可以直接修改引用的物件的成員
● 靜態變數:靜態變數 存在 JVM 的方法區之中,在方法區中的變數,會被所有的類共同使用,不需要建立物件實體(instance)
class Hello {
static String HELLO_WORLD = "Hello World";
public static void main(String[] args) {
Hello.HELLO_WORLD = "This is main";
}
}
變數的初始化、預設值
● 區域變數是沒有初始化數值的!必須手動初始化
● 而 Java 會對類的全域變數給予初始化值,如下表
類型 | 預設初始化值 |
byte 、short 、int 、long | 0 |
float | 0.0f |
double | 0.0d |
char | \u0000 |
boolean | false |
參考類型(物件) | null |
參考陣列(物件) | 預設也為 null,在初始化過後,如果仍沒有給元素賦值,那就使用該元素預設的初始化值 |
更多的 Java 語言相關文章
Java 語言深入
● 在這個系列中,我們全方位地探討了 Java 語言的各個核心主題,旨在幫助你徹底掌握這門強大的編程語言。無論你是想深入理解 Java 的基礎類型與變數作用域,還是探索異常處理與運算子的細節,這些文章都將為您提供寶貴的知識
此外,我們還涵蓋了物件創建、函數式編程、註解應用以及泛型的深入分析,幫助您提升在實際開發中的技能和效率
點擊以下連結,開始你的學習之旅~
● 深入探索 Java 基礎類型、編碼、浮點數、參考類型和變數作用域 | 探討細節
● 深入了解 Java 應用與編譯:從原始檔到命令產出 JavaDoc 文件 | JDK 結構
● 深入理解 Java 運算子與修飾符 | 重要概念、細節 | equals 比較
● 深入探索 Java 物件創建與引用細節:Clone 和finalize 特性,以及強、軟、弱、虛引用
● 認識 Java 函數式編程:從 Lambda 表達式到方法引用 | 3 種方法引用
Java IO 相關文章
● 探索 Java IO 的奧秘,了解檔案操作、流處理、NIO等精彩內容!
深入 Java 多執行緒
● 這一系列文章將帶你深入了解 Java 多執行緒技術的各個方面,從基礎知識到進階應用,涵蓋了多執行緒編程的核心概念與實踐
深入 Java 物件導向
● 探索 Java 物件導向的奧妙,掌握介面、抽象類、繼承等重要概念!幫助你針對物件導向設計有更深入的了解!