Cách gỡ rối những lỗi thường gặp trong Java [5] – Multicast

images

Các Cast (ép kiểu) được sử dụng để chuyển đổi một giá trị từ kiểu này sang kiểu khác. Qua bài viết này chúng ta sẽ nắm bắt rõ hơn về cast và những lỗi mà chúng ta thường gặp phải khi sử dụng cast.

Chương trình dưới đây sử dụng 3 cast liên tục. Thử đoán xem nó in nội dung gì?

public class Main
{
    public static void main(String[] args) {
       System.out.println((int)(char)(byte) -1);
    }
}

–   Chương trình này gây rối khi ta cắt nó thành các phần nhỏ bằng bất kỳ cách nào. Nó bắt đầu với giá trị int –1, sau đó cast (ép kiểu) int thành byte, rồi thành char và cuối cùng trở lại int. Cast thứ nất thu hẹp giá trị từ 32 bit xuống thành 8, cast thứ hai mở rộng nó từ 8 bit lên 16 và cast cuối cùng mở rộng nó từ 16 trở lại 32 bit. Giá trị có kết thúc trở lại nơi nó đã bắt đầu hay không? Nếu bạn chạy chương trình, bạn đã thấy rằng không phải như vậy. Nó in 65535, nhưng tại sao?

–   Cách hoạt động của chương trình phụ thuộc nhiều vào hành vi mở rộng dấu của các cast. Java sử dụng số học nhị phân bù hai, do đó giá trị int –1 có tất cả 32 bit được xác lập. Cast từ int sang byte thì đơn giản. Nó thực hiện một phép chuyển đổi nguyên thủy thu hẹp, cắt bỏ tất cả ngoại trừ 8 bit bậc thấp. Điều này để lại một giá trị byte với 8 bit được xác lập vốn tượng trưng cho –1.

–   Cast từ byte sang char phức tạp hơn bởi vì byte là một kiểu có dấu và char là một kiểu không dấu. Thường có thể chuyển đổi từ một kiểu số nguyên sang một kiểu số nguyên mở rộng hơn trong khi giữ lại giá trị số, nhưng không thể biểu diễn một giá trị byte âm dưới dạng một char. Do đó, sự chuyển đổi từ byte sang char không được xem là một sự chuyển đổi nguyên thủy mở rộng, nhưng là một sự chuyển đổi nguyên thủy mở rộng và thu hẹp: byte được chuyển đổi thành int và int thành char.

–   Tất cả điều này nghe có vẻ hơi phức tạp. Thật may, có một quy tắc đơn giả mô tả cách mở rộng dấu khi chuyển đổi các kiểu số nguyên hẹp hơn sang kiểu số nguyên rộng hơn: Việc mở rộng dấu được thự hiện nếu kiểu của giá trị gốc có dấu; không mở rộng nếu nó là một char, bất kể kiểu mà nó được chuyển đổi sang. Biết quy tắc này sẽ giúp dễ dàng giải bài toán.

–   Bởi vì byte là một kiểu có dấu, việc mở rộng dấu xảy ra khi chuyển đổi giá trị byte –1 thành char. Giá trị char vừa có được sẽ có 16 bit được xác lập, dó đó nó bằng với (2^16) –1, tức là 65535. Cast từ char sang  int cũng là một sự chuyển đổi nguyên thủy mở rộng, do đó quy tắc cho chúng ta biết rằng việc mở rộng không được thực hiện thay vì mở rộng dấu. Giá trị int vừa có được là 65535, đây chỉ là những gì mà chương trình in ra.

–   Mặc dù có một quy tắc đơn giản hơn mô tả cách mở rộng dấu của các chuyển đổi nguyên thủy mở rộng giữa các kiểu số nguyên có dấu và không dấu, tố nhất không viết các chương trình phụ thuộc vào nó. Nếu bạn thực hiện một chuyển đổi mở rộng qua lại một char, vốn là kiểu số nguyên không dấu duy nhất, tốt nhất nên là cho ý định của bạn trở nên rõ ràng.

–   Nếu bạn chuyển đổi từ một giá trị char c sang một kiểu rộng hơn và bạn không muốn mở rộng dấu, xem xét việc sử dụng một bit mask để tạo tính rõ ràng, mặc dù không bắt buộc:

int i = c & 0xffff;

Hoặc, viết một chú thích mô tả cách chuyển đổi:

int i = c;   // Sign extension is not performed

–   Nếu bạn chuyển đổi từ một giá trị char sang một kiểu số nguyên rộng hơn và bạn muốn mở rộng dấu, hãy ép kiểu char sang short vốn có cùng chiều rộng như một char nhưng có dấu. Với tính tinh vi của mã này, bạn cũng nên viết một chú thích:

int i = (short)c;    //Cast causes sign extension

–   Nếu bạn chuyển đổi ưừ một giá trị byte b sang char và không muốn mở rộng dấu, bạn phải sử dụng một bit mask để khử nó. Đây là một cách diễn đạt thông thường, do đó không cần chú thích:

char c = (char)(b & 0xff);

–   Nếu bạn chuyển đổi từ một byte sang char và bạn muốn mở rộng dấu, viết một chú thích:

char c = (char)b;   // Sign extension is performed

Bài học rút ra khá đơn giản: Nếu bạn không thể biết những gì một chương trình thực hiện khi xem qua nó, có lẽ nó sẽ không thực hiện theo những gì bạn muốn. Chúng ta phải cố gắng đạt được sự rõ ràng. Mặc dù một quy tắc đơn giản mô tả cách mở rộng dấu của các phép chuyển đổi mở rộng bao gồm các kiểu số nguyên có dấu và không dấu, nhưng hầu hết những người lập trình không biết điều đó. Nếu chương trình phụ thuộc vào nó, hãy làm cho ý định của bạn trở nên rõ ràng.

Advertisements

About thanhcuong1990

Handsome and talent!! ^^
This entry was posted in Java and tagged . Bookmark the permalink.

One Response to Cách gỡ rối những lỗi thường gặp trong Java [5] – Multicast

  1. codingvn says:

    Anh cho em hỏi là tại sao khi em viết
    byte b = 2;
    char c = (char) (b & oxff);
    thì không được

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s