2014-11-02 12 views
14

Dưới đây là Java Generics đầu tiên mà tôi từng viết:Không ClassCastException được ném trong Java Generics

public class MyClass { 

    public static <T> T castToAnotherType(Object param) { 
     T ret = null; 
     try { 
      ret = (T) param; 
     } catch (ClassCastException e) { 
      System.out.print("Exception inside castToAnotherType()"); 
     } 
     return ret; 
    } 

    public static void main(String[] args) { 
     try { 
      String obj = MyClass.castToAnotherType(new Object()); 
     } catch (ClassCastException e) { 
      System.out.print("Exception outside castToAnotherType()"); 
     } 
    } 

} 

Kết quả là "ngoại lệ bên ngoài castToAnotherType()". Tại sao ngoại lệ không xảy ra bên trong phương pháp chung?

Trả lời

15

T được hiệu quả xóa trong biên dịch. Xem here:

Generics được đưa vào ngôn ngữ Java để cung cấp loại chặt chẽ hơn kiểm tra lúc biên dịch và hỗ trợ lập trình chung. Để thực hiện Generics, trình biên dịch Java áp dụng loại tẩy xoá để:

  • Thay thế tất cả các thông số loại trong các loại generic với giới hạn của họ hoặc Object nếu các thông số loại là vô biên. Bytecode được sản xuất, do đó, chỉ chứa các lớp, giao diện và phương thức thông thường.
  • Chèn phôi loại nếu cần thiết để bảo vệ an toàn loại. Tạo ra các phương pháp cầu để bảo tồn đa hình trong các loại generic mở rộng.
  • Loại tẩy xóa đảm bảo rằng không có lớp mới nào được tạo cho tham số loại; do đó, generics không phải chịu chi phí thời gian chạy.

Vì vậy castToAnotherType của bạn bị xóa T vào ca. như sau:

public static Object castToAnotherType(Object param) { 
    Object ret = null; 
    try { 
     ret = (Object) param; 
    } catch (ClassCastException e) { 
     System.out.print("Exception inside castToAnotherType()"); 
    } 
    return ret; 
} 

Rõ ràng là không sản xuất bất kỳ ClassCastException.

main(...) là một câu chuyện khác nhau, nó kết quả như sau:

public static void main(String[] args) { 
    try { 
     String obj = (String) MyClass.castToAnotherType(new Object()); 
    } catch (ClassCastException e) { 
     System.out.print("Exception outside castToAnotherType()"); 
    } 
} 

nào tạo ra ClassCastException khi cố gắng đúc Object-String.

Vui lòng xem phần Type Erasure của Generics tutorial.

+0

Đó là phức tạp hơn nhiều hơn tôi nghĩ. Tôi cần phải dành nhiều thời gian học để hiểu đầy đủ về điều này khi tôi có thời gian. Bây giờ, bạn có bất cứ gợi ý nào để khắc phục nó không? Ví dụ: trả về 'null' khi' param' không thể được cast thành kiểu 'T'? – Livy

+1

@Livy Đây là một câu hỏi khác, hãy hỏi riêng nó. Tóm lại, một trong những phương pháp sẽ là truyền tham số 'Class targetClass' làm tham số bổ sung. Nhưng tôi rất muốn thấy những câu trả lời khác. :) – lexicore

4

Vâng, kể từ khi biên dịch xóa các thông số kiểu generic, đúc bên trong phương pháp này là về cơ bản tương đương với:

Object ret = null; 
    try { 
     ret = (Object) param; 
    } 
    ... 

mà không phải là một vấn đề, bất kể những gì bạn vượt qua phương pháp của bạn (vì bất kỳ đối tượng có thể được truyền tới Object).

Tuy nhiên, khi bạn cố gắng gán đối tượng đó cho một chuỗi, trong phương pháp chính của bạn, ClassCastException xảy ra, vì Object không thể truyền tới số String.

3

Tất cả các loại chung được xóa trong mã được biên dịch. Theo như mã được biên dịch có liên quan, castToAnotherType chỉ trả về một Object. Tuy nhiên, phương pháp main của bạn cố gắng gán nó cho một số String và không phải là String, do đó tạo ra một ClassCastException.

http://en.wikipedia.org/wiki/Type_erasure

3

Đây là vì chung loại tẩy xoá,

 T ret = null; 
     try { 
      ret = (T) param; 
... 

được dịch bởi trình biên dịch vào

 Object ret = null; 
     try { 
      ret = (T) param; 
... 
+1

Thực ra 'ret = (Object) param;'. – immibis