匯出 (0) 列印
全部展開

資料型別 (C# 與 Java 的比較)

這個主題討論 Java 和 C# 之間在資料表示、配置和記憶體回收方式上某些主要的相似與差異性。

複合資料型別

將類別當做使用欄位、方法和事件之複合資料型別的概念方面,Java 和 C# 都很相似 (類別繼承會在標題為繼承和衍生類別 (C# 與 Java 的比較) 的主題中分開討論)。C# 引入結構的概念,可以當做不支援繼承的已配置堆疊之複合資料型別。在大部分其他方面,結構與類別非常相似。結構提供將相關欄位和方法群組在一起的輕量方法,以便在緊密迴圈和非常要求效能的其他案例中使用。

C# 可讓您建立解構函式方法,此方法的呼叫時機是在類別的執行個體被記憶體回收之前。在 Java 中, finalize 方法可用來包含在物件由記憶體回收之前清除資源的程式碼。在 C# 中,這項功能是由類別解構函式執行。解構函式就像是不含引數和前置字元為波狀符號 (~) 的建構函式。

內建資料型別

C# 可提供 Java 中的所有資料型別,並且額外支援不帶正負號的數字以及新的 128 位元高精度浮點型別。

對於 Java 中的每個基本資料型別,核心類別庫會提供代表此資料型別的包裝函式類別做為 Java 物件。例如,Int32 類別包裝 int 資料型別,而 Double 類別則是包裝 double 資料型別。

另一方面,C# 中的所有基本資料型別就是 System 命名空間中的物件。對於每個資料型別,會提供一個簡短名稱或別名。例如,intSystem.Int32 的簡短名稱,而 double 則是 System.Double 的簡短形式。

下表中提供了 C# 資料型別及其別名的清單。您可以發現,清單中的前八個可對應到 Java 中的基本型別。但是請注意,Java 的 boolean 在 C# 中是稱為 bool

簡短名稱 .NET 類別 型別 寬度 範圍 (位元)

byte

Byte

不帶正負號的整數

8

0 至 255

sbyte

SByte

帶正負號的整數

8

-128 至 127

int

Int32

帶正負號的整數

32

-2,147,483,648 至 2,147,483,647

uint

UInt32

不帶正負號的整數

32

0 至 4294967295

short

Int16

帶正負號的整數

16

-32,768 至 32,767

ushort

UInt16

不帶正負號的整數

16

0 至 65535

long

Int64

帶正負號的整數

64

-922337203685477508 至 922337203685477507

ulong

UInt64

不帶正負號的整數

64

0 至 18446744073709551615

float

Single

單精度浮點數型別

32

-3.402823e38 至 3.402823e38

double

Double

雙精度浮點數型別

64

-1.79769313486232e308 至 1.79769313486232e308

char

Char

單一 Unicode 字元

16

用於文字中的 Unicode 符號

bool

Boolean

邏輯布林型別

8

true 或 false

object

Object

所有其他型別的基底型別

string

String

字元的順序

decimal

Decimal

以 29 位有效數字表示十進位數字的精確小數型別或整數型別

128

±1.0 × 10e-28 至 ±7.9 × 10e28

由於 C# 將所有基本資料型別以物件表示,因此您可以在基本資料型別上呼叫物件方法。例如:

static void Main()
{
    int i = 10;
    object o = i;
    System.Console.WriteLine(o.ToString());
}    

這項作業可在自動 Boxing 和 Unboxing 的協助下完成。如需詳細資訊,請參閱 Boxing 和 Unboxing (C# 程式設計手冊)

常數

Java 和 C# 都能夠宣告在編譯階段指定值並且無法在執行階段變更的變數。Java 會使用 final 欄位修飾詞 (Modifier) 宣告這類變數,而 C# 則會使用 const 關鍵字。除了 const 以外,C# 也提供 readonly 關鍵字以宣告能夠在執行階段指定一次值的變數 (不論是在宣告陳述式或建構函式中)。在初始化後,readonly 變數的值就無法變更。當分開編譯的模組需要共用像是版本號碼的資料時,這種情況下 readonly 變數就很有用。如果使用新的版本號碼更新和重新編譯模組 A,模組 B 就能夠使用這個新常數值進行初始化而不需要重新編譯。

列舉型別

列舉型別 (或列舉) 是用來群組具名常數,作法與在 C 和 C++ 中的用法類似,但是它們無法用於 Java。下列程式碼範例將會定義簡單的 Color 列舉型別。

public enum Color
{
    Green,   //defaults to 0
    Orange,  //defaults to 1
    Red,     //defaults to 2
    Blue     //defaults to 3
}  

整數值也可以指派給列舉型別,如以下列舉宣告所示:

public enum Color2
{
    Green = 10,
    Orange = 20,
    Red = 30,
    Blue = 40
}

下列程式碼範例會呼叫 Enum 型別的 GetNames 方法,以顯示列舉型別的可用常數。接著程式碼將指派一個值給列舉型別並顯示該值。

class TestEnums
{
    static void Main()
    {
        System.Console.WriteLine("Possible color choices: ");

        //Enum.GetNames returns a string array of named constants for the enum.
        foreach(string s in System.Enum.GetNames(typeof(Color)))
        {
            System.Console.WriteLine(s);
        }

        Color favorite = Color.Blue;

        System.Console.WriteLine("Favorite Color is {0}", favorite);
        System.Console.WriteLine("Favorite Color value is {0}", (int) favorite);
    }
}

輸出

Possible color choices:

Green

Orange

Red

Blue

Favorite Color is Blue

Favorite Color value is 3

字串

字串型別在 Java 和 C# 中展現類似的行為,其中僅有些微不同。兩者的字串型別是不變的,也就是說字串一旦建立後便無法變更字串值。在兩者的執行個體中,似乎可以使用方法來修改字串的實質內容,但實際上這個方法是建立新字串以供傳回之用,它並不會變更原來的字串。C# 與 Java 會使用不同的方法比較字串值。若要在 Java 中比較字串值,程式開發人員必須在 == 運算子根據預設比較參考型別時,呼叫字串型別上的 equals 方法。在 C# 中,程式開發人員則可以直接使用 ==!= 運算子來比較字串值。即使字串在 C# 中是參考型別,根據預設,==!= 運算子仍會比較字串值,而非參考。

和在 Java 中一樣,C# 程式開發人員不應使用字串型別來串連字串,避免每次串連字串時都建立新字串類別的負荷。程式開發人員可以使用 StringBuilder 類別來代替,此類別在功能上等同於 Java 的 StringBuffer 類別。

字串常值

C# 提供避免在字串常數內使用逸出序列 (例如定位字元是 "\t" 或反斜線字元是 "\") 的能力。若要這樣做,只要在指派字串值之前使用 @ 符號來宣告逐字規範字串即可。下列範例說明如何使用逸出字元以及如何指派字串常值:

static void Main()
{
    //Using escaped characters:
    string path1 = "\\\\FileShare\\Directory\\file.txt";
    System.Console.WriteLine(path1);

    //Using String Literals:
    string path2 = @"\\FileShare\Directory\file.txt";
    System.Console.WriteLine(path2);
}

轉換和轉型

Java 和 C# 在資料型別自動轉換和轉型時都遵守類似的規則。

C# 和 Java 一樣,同時支援隱含的和明確的型別轉換。進行擴展轉換時,此轉換是隱含轉換。例如,以下從 intlong 的轉換是隱含轉換,和在 Java 中一樣:

int int1 = 5;
long long1 = int1;  //implicit conversion

以下是 .NET Framework 資料型別之間的隱含轉換清單:

來源型別 目標型別

Byte

short、ushort、int、uint、long、ulong、float、double 或 decimal

Sbyte

short、int、long、float、double 或 decimal

Int

long、float、double 或 decimal

Uint

long、ulong、float、double 或 decimal

Short

int、long、float、double 或 decimal

Ushort

int、uint、long、ulong、float、double 或 decimal

Long

float、double 或 decimal

Ulong

float、double 或 decimal

Float

double

Char

ushort、int、uint、long、ulong、float、double 或 decimal

使用與 Java 相同的語法來轉型想要明確轉換的運算式:

long long2 = 5483;
int int2 = (int)long2;  //explicit conversion

下表列出明確轉換。

來源型別 目標型別

Byte

sbyte 或 char

Sbyte

byte、ushort、uint、ulong 或 char

Int

sbyte、byte、short、ushort、uint、ulong 或 char

Uint

sbyte、byte、short、ushort、int 或 char

Short

sbyte、byte、ushort、uint、ulong 或 char

Ushort

sbyte、byte、short 或 char

Long

sbyte、byte、short、ushort、int、uint、ulong 或 char

Ulong

sbyte、byte、short、ushort、int、uint、long 或 char

Float

sbyte、byte、short、ushort、int、uint、long、ulong、char 或 decimal

Double

sbyte、byte、short、ushort、int、uint、long、ulong、char、float 或 decimal

Char

sbyte、byte 或 short

Decimal

sbyte、byte、short、ushort、int、uint、long、ulong、char、float 或 double

實值和參考型別

C# 支援兩種變數型別:

  • 實值型別

    這些是內建的基本資料型別 (例如 char、int 和 float) 以及結構 (Struct) 宣告的使用者定義型別。

  • 參考型別

    類別以及從基本型別建構的其他複雜資料型別。這類型別的變數不包含該型別的執行個體,而只包含執行個體的參考。

如果建立兩個實值型別的變數 i 和 j (如下所示),那麼 i 和 j 彼此之間完全無關聯:

int i = 10;
int j = 20;

它們的記憶體位置並不相同:

實值型別個別的記憶體位址

如果變更其中一個變數的值,另一個變數當然不會受到影響。例如,如果運算式如下所示,那麼變數之間仍然不會有關聯:

int k = i;

也就是說,如果變更 i 的值,k 將會仍然是當初指派給 i 的值。

i = 30;

System.Console.WriteLine(i.ToString());  // 30
System.Console.WriteLine(k.ToString());  // 10

不過,參考型別就完全不同了。例如,您可以如以下所示宣告兩個變數:

Employee ee1 = new Employee();
Employee ee2 = ee1;

現在,由於在 C# 中類別是參考型別,因此 ee1 也稱為 Employee 的參考。上述兩行程式碼中的第一行會在記憶體中建立 Employee 的執行個體,並且將 ee1 設定為參考這個執行個體。因此,當您將 ee2 設為等於 ee1 時,它會包含記憶體中這個類別參考的複本。此時如果變更 ee2 上的屬性,ee1 上的屬性將會反映這些變更,這是因為這兩個都指向記憶體中的同一個物件,如下所示:

參考型別的記憶體位置

Boxing 和 Unboxing

將實值型別轉換成參考型別的過程稱為 Boxing。而反向的作法,即將參考型別轉換成實值型別,則稱為 Unboxing。這在下列程式碼中說明:

int i = 123;      // a value type
object o = i;     // boxing
int j = (int)o;  // unboxing

Java 要求您以手動方式執行這類的轉換。基本資料型別便可轉換成包裝函式類別物件,作法是建構這類物件或 boxing。同樣地,可從包裝函式類別物件擷取基本資料型別的值,作法是呼叫這類物件上的方法或 Unboxing。如需 Boxing 和 Unboxing 的詳細資訊,請參閱 Boxing 轉換 (C# 程式設計手冊)Unboxing 轉換 (C# 程式設計手冊)

請參閱

社群新增項目

新增
顯示:
© 2014 Microsoft