跳至主要内容

2.1 Basics

用 reference 操作 object

  • 在Java中,一切都被視為 object
  • String s;
    • 此處建立的 只是 reference,並不是 object
    • 若此時向 s 發送消息會有 runtime error
    • 安全的做法是建立 reference 的同時便初始化
      • String s = “asdf“;

必須由你建立所有object

一旦建立 reference,就希望它與一個 object 關聯

  • 通常用 new 來實現
  • new 的意思為 給我一個新的 object

String s = “asdf”; 可以改寫為 String s = new String(“asdf“);

Object 的儲存位置

程式運行時,java是怎麼將物件放在記憶體的

  • register (寄存器):
    • 最快的儲存區,因為它直接在CPU的內部,但數量極為有限
    • 無法直接控制,但 C/C++ 允許向 compiler 建議分配方式
  • stack:
    • 位於通用 RAM
    • 透過 stack pointer 的上下移動可以分配/釋放內存
    • 速度僅次於 register
    • Java 系統必須知道儲存在 stack 內的所有項目的確切生命週期才能正確移動 stack pointer,限制程式的靈活性
    • 某些資料存在 stack 中,尤其是 reference,但 java object 並不會放在這
  • heap:
    • 也位於 RAM 的通用內存池,用來存放所有 Java object
    • 相較於 stack 的好處是編譯器不需要知道數據存活多長時間,因此具備更大的彈性
    • 使用 new 便可以自動分配
    • 這種彈性也需要付出相對的代價: 分配及清理會比 stack 用掉更多時間
  • 常量儲存
    • 通常放在 code 內部
    • 由於 code 區塊不會被改變,,因此這做法提供對常量不變性的保護
  • 非 RAM 儲存
    • 在 process 控制之外的資料
    • 例如 stream, file

Object 中的特例: 基本類型 (Primitive)

在程式設計中經常用到一系列小而簡單的類型,可以把他們想像成 基本類型

  • 因為用 new 將這類的 object 儲存在 heap 中往往不是很有效
  • Java 與 C++ 採用相同的方法,不用 new 來創造 variables,而是建立 non-reference 的”自動” variables
  • 這種 variables 直接儲存 value 並放在 stack 中,因此更加有效率

基本類型一覽

Java 每種 primitive 的大小是不隨硬體架構變化的

Primitive大小MinMax包裝器類型
boolean---Boolean
char16 bitsUnicode 0Unicode 2^16 - 1Character
byte8 bits-128+127Byte
short16 bits-2^15+2^15-1Short
int32 bits-2^31+2^31-1Integer
long64 bits-2^63+2^63-1Long
float32 bitsIEEE 754IEEE 754Float
double64 bitsIEEE 754IEEE 754Double
void---Void
  • 所有類型都有正負號 ⇒ Java 沒有 unsigned
  • boolean 佔的空間沒有明確指定,僅定義為能夠取字面值 truefalse

包裝器 (Wrapper)

  • 所有的 primitives 都有對應的包裝器,用來在 heap 建立一個非 primitive 的 object
char c = 'x';
Character ch = new Character(c);
Character ch = new Character('x');

// Java SE5 自動包裝功能會自動將 primitive 轉換為包裝器類型
Character ch = 'x';
// 反向轉換
char c = ch;

高精度數字

  • Java 提供兩個高精度計算用的 class
    • BigInteger: 支援任意長度的整數而不會丟失資料
    • BigDecimal: 支援任意長度的浮點數,可以進行精確的貨幣計算
  • 雖然大體上屬於 “包裝器類“,但是沒有對應的 primitives
  • 這兩個 class 提供的方法讓可以用相同於 intfloat 的方式來操作
    • 但必須要 call function 的方式來調用,由於複雜度提升因此運算速度也比較慢

Java 中的 Array

  • Java 會確保 array 被初始化
  • 不能在範圍之外訪問
  • 當創建一個 array,實際上就是創建了一個 array 的 reference

Java 的作用域

Java 的作用域與 C / C++ 的區別

  • C / C++ 中,作用域由大括號的位子決定
{
int x = 12;
// Only x available
{
int q = 96;
// Both x and q available
}
//Only x available
// q is "out of scope"
}
  • 在C / C++ 中可以在較內層的作用域重複定義變數,Java 中不能這樣寫
{
int x = 12;
{
int x = 96; // Illegal
}
}

Object 的作用域

  • Java Object 不具備和基本類型一樣的生命週期,當用 new 建立 Java object時他可以存活於作用域外
{
String s = new String("a string");
// End of scope
}
  • reference 在作用域外就會消失,但 s 指向的 String object 仍會在記憶體裡
  • Java 的 垃圾回收器(GC),會監視用 new 建立的 object,並且回收已經不會再被引用的 object,消除了因程式人員忘記釋放記憶體導致的 memory leak 問題