Tại sao trong một chuyển đổi Java qua trình bao bọc Integer, trường hợp 'char' không biên dịch, nhưng quá trình biên dịch vẫn ổn khi chuyển đổi qua Byte?


18

Không biên dịch:

void test(Integer x) {
      switch (x) {
          case 'a':
      }
}

Biên dịch OK:

void test(Byte x) {
      switch(x) {
          case 'a':
      }
}

1
Số nguyên là 4 byte trong khi char là 2 byte. Vì vậy, trong trường hợp đầu tiên, bất kể bạn viết ký tự nào, nó nhỏ hơn số nguyên. Tuy nhiên, trong trường hợp thứ hai, ký tự mà bạn đã viết có thể lớn hơn byte tối đa, làm cho trường hợp đó không bao giờ được thực thi.
Jaroslaw Pawlak

Lời giải thích đó không chính xác. Thật vậy, trong ví dụ thứ 2, mã trong 'a'trường hợp sẽ được thực thi trong trường hợp đó xlà byte 97. (Hãy thử nếu bạn không tin tôi.) Để biết giải thích thực sự, hãy xem câu trả lời của tôi.
Stephen C

Câu trả lời:


19

Các lý do khá phức tạp, nhưng tất cả đều nằm trong chi tiết ( bản in đẹp nếu bạn muốn) của Đặc tả ngôn ngữ Java.

Đầu tiên, JLS 14.11 nói như sau về các switchcâu lệnh:

"Mọi hằng số trường hợp liên quan đến câu lệnh chuyển đổi phải được gán tương thích với loại Biểu thức của câu lệnh chuyển đổi ( §5.2 )."

Điều này có nghĩa là 'a'cần phải được gán IntegerByte tương ứng.

Nhưng điều đó không đúng:

  • Bạn sẽ nghĩ rằng vì 'a' nên được gán cho một Integerchar-> int chuyển nhượng là hợp pháp. (Mọi chargiá trị sẽ phù hợp với một int.)

  • Bạn sẽ nghĩ rằng vì 'a' KHÔNG nên được gán cho một Bytechar-> byte chuyển nhượng KHÔNG hợp pháp. (Hầu hết các chargiá trị sẽ không vừa với một byte.)

Trong thực tế, cả hai điều này đều không đúng. Để hiểu lý do tại sao, chúng ta cần đọc JLS 5.2 thực sự về những gì được phép trong bối cảnh chuyển nhượng.

"Bối cảnh chuyển nhượng cho phép sử dụng một trong những điều sau đây :

  • chuyển đổi nhận dạng (§5.1.1)
  • một chuyển đổi nguyên thủy mở rộng (§5.1.2)
  • chuyển đổi tham chiếu mở rộng (§5.1.5)
  • chuyển đổi tham chiếu mở rộng theo sau là chuyển đổi unboxing
  • một chuyển đổi tham chiếu mở rộng theo sau là một chuyển đổi unboxing, sau đó là một chuyển đổi nguyên thủy mở rộng
  • chuyển đổi quyền anh (§5.1.7)
  • một chuyển đổi quyền anh theo sau là một chuyển đổi tham chiếu mở rộng
  • một chuyển đổi unboxing (§5.1.8)
  • một chuyển đổi unboxing theo sau là một chuyển đổi nguyên thủy mở rộng. "

Để đi từ 'a'đến Integer, chúng tôi sẽ cần phải 1 mở rộng chargiá trị cho một intsau đó hộp intmột Integer. Nhưng nếu bạn xem xét các kết hợp chuyển đổi được phép, bạn không thể thực hiện chuyển đổi nguyên thủy mở rộng theo sau là chuyển đổi quyền anh.

Do đó 'a'để Integerkhông được phép. Điều này giải thích lỗi biên dịch trong trường hợp đầu tiên.

Bạn sẽ nghĩ rằng 'a'để Bytelà không được phép vì đó sẽ bao gồm một chuyển đổi thu hẹp nguyên thủy ... mà không có trong danh sách ở tất cả. Trong thực tế, nghĩa đen là một trường hợp đặc biệt. JLS 5.2 tiếp tục nói như sau.

"Ngoài ra, nếu biểu thức là biểu thức không đổi ( §15.28 ) của kiểu byte, short, char hoặc int:

  • Một chuyển đổi nguyên thủy thu hẹp có thể được sử dụng nếu biến có kiểu byte, ngắn hoặc char và giá trị của biểu thức hằng được biểu diễn trong loại biến.

  • Chuyển đổi nguyên thủy thu hẹp theo sau là một chuyển đổi quyền anh có thể được sử dụng nếu biến là loại Byte, Shorthoặc Character, và giá trị của biểu thức liên tục được biểu diễn trong các loại byte, short, hoặc char tương ứng."

Thứ hai trong số này áp dụng 'a'cho Byte, bởi vì:

  • một ký tự là một biểu thức không đổi, và
  • giá trị 'a'97thập phân, nằm trong phạm vi cho byte( -128đến +127).

Điều này giải thích tại sao không có lỗi biên dịch trong ví dụ thứ hai.


1 - Chúng tôi không thể mở rộng thành 'a'một Charactervà sau đó mở rộng Characterra IntegerCharacterkhông phải là một kiểu con của Java Integer. Bạn chỉ có thể sử dụng chuyển đổi tham chiếu mở rộng nếu loại nguồn là kiểu con của loại mục tiêu.


Chúng ta có thể sử dụng intnhư loại chuyển đổi? (kể từ khi char -> intmở rộng nguyên thủy được phép)
AjahnCharles
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.