2016-03-27 22 views
23

Tôi đã cố gắng để loại bỏ các phần fractional từ một double trong trường hợp nó là toàn bộ sử dụng:Java - hành vi kỳ lạ hành ternary

(d % 1) == 0 ? d.intValue() : d 

Và gặp phải những hành vi sau đây mà tôi không hiểu:

public static void main(String[] args) { 
    Double d = 5D; 
    System.out.println((d % 1) == 0);        // true 
    System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // 5 
    System.out.println((d % 1) == 0 ? d.intValue() : d);   // 5.0 
} 

Như bạn có thể thấy trên dòng thứ ba, toán tử chọn giá trị else - 5.0 ngay cả khi điều kiện (d % 1) == 0 được đáp ứng.

Điều gì đang xảy ra ở đây?

+3

Nó chọn 'd.intValue()' trong cả hai trường hợp, nó chỉ thực hiện chuyển đổi để đảm bảo đối số thứ hai và thứ ba có cùng loại. – Keppil

+0

Có thể được coi là bản sao của http://stackoverflow.com/questions/8002603/why-does-the-ternary-operator-unexpectedly-cast-integers (và tất cả các bản sao của nó) ... – Marco13

+0

@ Marco13, tôi đã không biết rằng việc truyền là vấn đề khi đăng câu hỏi. có lẽ nó là một bản sao của hindsight .. – Daniel

Trả lời

35

Kiểu trả về của toán tử điều kiện bậc ba phải sao cho cả toán hạng 2 và 3 có thể được gán cho nó.

Vì vậy, trong trường hợp thứ hai của bạn, kiểu trả về của các nhà điều hành là Object (vì cả hai d.intValue()"not whole" phải gán với nó) trong khi trong trường hợp thứ ba đó là Double (vì cả hai d.intValue()d phải gán với nó).

In một Object có loại thời gian chạy là Integer mang đến cho bạn 5 khi in một Double mang đến cho bạn 5.0.

+0

Nhưng tại sao nó được đúc thành 'Object' chứ không phải' String' khi cả hai có thể được gán cho một 'String'? – Daniel

+3

@Daniel Trên thực tế, 'Integer' không thể được gán cho một' String', nó phải được chuyển thành một String (ví dụ, bằng cách sử dụng 'Integer''s' toString') đầu tiên. Nó chỉ được chuyển thành một String trong ví dụ của bạn để in bằng println. – Eran

3

Nó chọn chính xác. Sau đó, nó kết thúc tốt đẹp nó trong đôi. Đây là 3 điểm chính:

  1. Nếu toán hạng thứ hai và thứ ba có cùng loại, đó là loại biểu thức có điều kiện. Nói cách khác, bạn có thể tránh toàn bộ mớ hỗn độn bằng cách chỉ đạo xóa tính toán loại hỗn hợp.

  2. Nếu một trong các toán hạng là loại T trong đó T là byte, ngắn hoặc char và toán hạng khác là biểu thức liên tục của kiểu int có giá trị đại diện trong loại T, loại biểu thức điều kiện là T

  3. Nếu không, quảng bá số nhị phân được áp dụng cho các loại toán hạng và loại biểu thức có điều kiện là loại được thăng hạng của toán hạng thứ hai và thứ ba.

11

Loại biểu thức a ? b : c luôn giống như c hoặc cha mẹ chung gần nhất của bc.

System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // Comparable a parent of Integer and String 
System.out.println((d % 1) == 0 ? d.intValue() : d);   // Double is a widened int 

BTW d % 1 sẽ chỉ kiểm tra xem nó là một tổng thể không, không phải là nó đủ nhỏ để vừa trong một giá trị int. Một kiểm tra an toàn hơn là để xem nếu giá trị là như nhau khi cast vào một int hay long

hoặc bạn có thể ngăn chặn nó mở rộng long trở lại một đôi với

double d = 5.0; 
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d)); 
+1

Cảm ơn, trong trường hợp của tôi (số đại diện cho csat) giá trị tối đa có thể là 5 vì vậy cuộc sống đơn giản hơn rất nhiều so với .. – Daniel

1

Trong trường hợp của bạn đối số thứ hai và thứ ba của toán tử ternery là các loại "int" và "Double". Java phải chuyển đổi các giá trị này thành cùng một loại để chúng có thể được trả về từ toán tử bậc ba.Các quy tắc để thực hiện điều này được đưa ra trong đặc tả ngôn ngữ Java. https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

Trong trường hợp của bạn, các quy tắc này dẫn đến việc chuyển đổi cả hai tham số thành loại "double" ("Double" là unboxed, int là giá trị được chuyển đổi).

Khắc phục là bỏ các đối số cho toán tử bậc ba sao cho chúng cùng loại (có thể có nhiều dấu ngoặc ở dưới mức cần thiết nghiêm ngặt, tôi hơi yếu về quy tắc ưu tiên toán tử java).

System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d);