2016-10-06 18 views
14

Tại sao tôi có thể làm điều này:Tại sao tôi có thể gán một số nguyên cho một biến kiểu ngắn nhưng không phải là một tham số phương thức kiểu ngắn?

short a = 5; 

Nhưng không này:

void setNum(short a); 

setNum(5); 

Nó ném:

chuyển đổi tổn hao có thể xảy ra từ int ngắn

Tôi hiểu rằng 5 là một số nguyên theo nghĩa đen và bạn phải ca st nó. Tôi cũng hiểu rằng nếu giá trị không phải là một hằng số thì rõ ràng là nó cần phải ném lỗi đó bởi vì có lẽ giá trị đạt đến giới hạn của một loại ngắn. Nhưng tại sao nếu trình biên dịch biết tôi đang đi qua một hằng số mà một đoạn ngắn có thể giữ (như trong bài tập) nó không cho phép nó biên dịch? Ý tôi là, sự khác biệt giữa chúng là gì?

+5

Trình biên dịch tuân theo đặc tả ngôn ngữ, mà dường như không gọi cho chuyển đổi trong trường hợp này. Điều đó có vẻ hơi không nhất quán, nhưng có lẽ không phải là một câu trả lời hay cho * tại sao * spec là như thế này (trừ khi ai đó đào lên một cái gì đó từ một danh sách gửi thư đặc tả ngôn ngữ Java). – Thilo

+1

Đây chỉ là một đoán, nhưng: Trong ví dụ đầu tiên, có thể '5' có thể được đọc dưới dạng' short' literal * khi phân tích cú pháp *, trong khi trong ví dụ thứ hai, trình phân tích cú pháp không biết loại đối số phương thức, do đó, nó mặc định được phân tích cú pháp dưới dạng chữ 'int'. –

+0

@ChrisMartin Vâng, những gì một trình phân tích cú pháp không nhất quán sau đó, như Thilo nói – GabrielBB

Trả lời

9

Để hiểu được lý do tại sao sự phân loại-chuyển đổi hoạt động trong khi gọi một bị từ chối, người ta phải tham khảo các chủ đề Java Language Specification cho cả narrowing primitive conversions và ngữ cảnh của chuyển đổi đó: assignment contextinvocation context.

Theo JLS, việc chuyển đổi nguyên thủy thu hẹp được cho phép trong bối cảnh phân nếu:

Chuyển đổi nguyên thủy thu hẹp có thể được sử dụng nếu loại biến là byte, short, hoặc char, và giá trị của biểu thức hằng số là biểu thị trong loại biến.

... khớp với trường hợp của bạn với int hằng số 5 khi được gán cho short a.

Không chuyển đổi nguyên thủy thu hẹp như vậy được phép trong bối cảnh gọi, điều này giải thích tại sao cuộc gọi của bạn để setNum(short) không thành công khi vượt qua được int liên tục 5.

Nhưng tại sao nếu trình biên dịch biết tôi đang chuyển một hằng số mà một đoạn ngắn có thể giữ (như trong bài tập), nó không cho phép biên dịch? Ý tôi là, sự khác biệt giữa chúng là gì?

JLS không được muốn trình biên dịch gánh nặng với logic bổ sung này. Trong trường hợp yêu cầu, đối số khớp với tham số chính thức là một biểu thức - trình biên dịch đã phải xác định loại, nhưng nó không cần phải kiểm tra xem giá trị của biểu thức cũng có thể thu hẹp một cách an toàn hay không. Trong trường hợp này, là một hằng số, rõ ràng là chúng tôi rằng có thể, nhưng trong ngữ cảnh thực thi trình biên dịch được phép không bận tâm đến việc kiểm tra đó và thực tế là chính xác để không cho phép nó. Rõ ràng là khi biểu thức được cho phép, sẽ dễ dàng hơn khi các lỗi bị rớt ở nơi không thể thu hẹp mà không làm mất độ chính xác, vì vậy JLS và trình biên dịch chỉ không cho phép nó trong mọi trường hợp.

Điều này cũng đúng trong numeric context, vì vậy việc kê khai:

short a = 5;short b = a * 5; 

... được tương tự không được phép, dù đã được bao gồm rõ ràng của các hằng số mà thu hẹp một cách chính xác.

0

Khi bạn nhập 5, đây sẽ tự động là số nguyên. Tôi không chắc bạn đang sử dụng IDE gì cho bạn lỗi, nhưng lý do cảnh báo bạn là vì bạn đang chuyển đổi dung lượng lưu trữ lớn hơn thành giá trị nhỏ hơn, mặc dù không phải trong trường hợp của bạn, dữ liệu. Số này được gọi là thu hẹp chuyển đổi.

Số nguyên có thể chứa 32 bit dữ liệu, trong khi quần short chỉ có thể chứa 16 bit dữ liệu. Vì vậy, ví dụ (trong thực tế các con số sẽ lớn hơn nhiều), một int có giá trị bằng 50, và sau đó bạn đưa nó vào một đoạn ngắn, dữ liệu sẽ được cắt thành "5" vì ngắn không có phân bổ bộ nhớ đủ lớn.

mã mà bạn đăng sẽ không hoạt động vì khi bạn xác định thời gian ngắn như sau:

short a = 5; 

Bạn đang trực tiếp tạo ra một đoạn ngắn, và con số này đủ nhỏ mà ngắn có thể giữ nó. Khi bạn nhập "5" một mình làm đối số phương thức, nó được xử lý dưới dạng số nguyên và JVM không biết rằng nó nhỏ và an toàn để tạo ngắn. Để làm cho "5" phù hợp làm đối số cho phương pháp, bạn cần phải biến nó thành một đoạn ngắn bằng cách sử dụng một chuyển đổi thu hẹp, như sau:

setNum((short) 5); 

Nhưng như đã nói, nếu bạn thực sự không biết giá trị của int, và bạn không chắc chắn nó đủ nhỏ để được biến thành một đoạn ngắn, điều này có thể tạo ra các lỗi trong mã của bạn vì một số số sẽ bị cắt nhỏ.

(Here là một số tài liệu Oracle về vấn đề này)

+5

Điều đó không giải thích được khi chuyển đổi tiềm ẩn (và an toàn) được cho phép trong ví dụ đầu tiên nhưng không được phép trong ví dụ thứ hai. – Thilo

+1

Thực tế ví dụ của bạn với 50 bị cắt xuống 5 là sai - nếu bất cứ điều gì nó sẽ là 2 (50 = 0x32 nếu tôi đếm chính xác) nếu được lưu trữ trong một số nguyên 4 bit – ToVine

+0

@To Vineyard vâng, nó được dự định là một siêu ví dụ cơ bản để có được điểm trên – StaticShadow

Các vấn đề liên quan