2013-07-11 27 views
5

Giả sử có đoạn mã sau:Tại sao công việc đúc ngầm ẩn trong khi đúc phản chiếu ném ngoại lệ?

@SuppressWarnings("unchecked") 
public static <T> T implicitCaster(Class<T> cls, Object o) { 
    return (T) o; 
} 

public static <T> T reflectionCaster(Class<T> cls, Object o) { 
    return cls.cast(o); 
} 

Mã này hoạt động như mong đợi trong cả hai trường hợp với ngoại lệ sau, được tìm thấy trong nguyên thủy:

public static void main(String[] args) { 
    System.out.println(implicitCaster(int.class, 42)); 
    System.out.println(reflectionCaster(int.class, 42)); 
} 

Cuộc gọi đầu tiên làm việc như mong đợi nhưng cuộc gọi thứ hai ném java.lang.ClassCastException.

Đây có phải là trường hợp góc trong đó autoboxing bị bỏ qua không? Hoặc là nó không thể cung cấp autoboxing trong trường hợp này, phản ánh đúc? Hoặc có điều gì khác gây ra sự không thống nhất này?

Chỉnh sửa: gọi mã này làm việc như mong đợi:

public static void main(String[] args) { 
    System.out.println(implicitCaster(Integer.class, 42)); 
    System.out.println(reflectionCaster(Integer.class, 42)); 
} 

Trả lời

3

Điều này xảy ra bởi vì các loại tẩy xoá.

Khi thời gian chạy, các thông số loại chung không tồn tại.
Truyền một đối tượng đến tham số kiểu chung không có hiệu lực. (đó là lý do bạn nhận được cảnh báo truyền không được chọn)

Do đó, hộp tự động đầu tiên của bạn 42 đến Object để chuyển cho phương thức.
Hàm sau đó trả về Object, được chuyển đến System.out.println.


cuộc gọi thứ hai của bạn gọi phương thức cast của int loại nguyên thủy.
Điều này ném một ngoại lệ, bởi vì các đối tượng không thể được đúc thành các kiểu nguyên thủy. (auto-boxing là một tính năng hoàn toàn biên dịch-thời gian, do đó, nó không giúp đỡ)

Lỗi xảy ra khi cast()checks isInstance() để xác minh rằng diễn viên có hiệu lực.

Các tài liệu cho isInstance() say:

Cụ thể, nếu đối tượng Class này đại diện cho một lớp học tuyên bố, phương pháp này trả về true nếu đối số đối tượng quy định là một thể hiện của lớp đại diện (hoặc của bất kỳ lớp con của nó) ; nó trả về false nếu không. Nếu đối tượng Class này đại diện cho một lớp mảng, phương thức này trả về true nếu đối số Object đã chỉ định có thể được chuyển đổi thành đối tượng của lớp mảng bằng một chuyển đổi nhận dạng hoặc bằng một phép chuyển đổi tham chiếu mở rộng; nó trả về false nếu không. Nếu đối tượng Class này đại diện cho một giao diện, phương thức này trả về true nếu lớp hoặc bất kỳ superclass nào của đối số Object đã chỉ định thực hiện giao diện này; nó trả về false nếu không. Nếu đối tượng Class này đại diện cho một kiểu nguyên thủy, phương thức này trả về false.

(nhấn mạnh thêm)


chỉnh sửa của bạn làm việc vì bạn không còn sử dụng một loại nguyên thủy.
Trong cả hai trường hợp, trình biên dịch tự động hóa 42 để nó có thể được truyền dưới dạng đối tượng.

Cuộc gọi đầu tiên, như trước đây, không có hiệu lực.
Cuộc gọi thứ hai xác minh rằng số nguyên đã đóng trong thực tế là một phiên bản của lớp Integer, sau đó trả về nó.

+0

Tôi đã viết ở đó rằng mã hoạt động cho mọi lớp nhất định ngoại trừ các nguyên thủy; vì vậy việc đúc một đối tượng cho một loại chung là có thể. Thứ hai, bạn có thể đúc các đối tượng để nguyên thủy. – m3th0dman

+0

@ m3th0dman: Tôi không nói điều đó là không thể. Tôi nói nó không có hiệu lực trong thời gian chạy. – SLaks

+0

Tôi hiểu ngay bây giờ; nhưng không phải loại phá vỡ hợp đồng của phương pháp đúc? Về mặt kỹ thuật diễn viên là có thể. – m3th0dman

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