2016-03-25 17 views
5

Mã sau đây là từ thư viện Android có tên là ButterKnife. Tôi đang tìm ra cách nó hoạt động.Java Generics cast dựa trên kiểu trả về?

@SuppressWarnings("unchecked") // That's the point. 
    public <T> T castParam(Object value, String from, int fromPosition, String to, int toPosition) { 
    try { 
     return (T) value; 
    } catch (ClassCastException e) { 
     throw new IllegalStateException("Parameter #" 
      + (fromPosition + 1) 
      + " of method '" 
      + from 
      + "' was of the wrong type for parameter #" 
      + (toPosition + 1) 
      + " of method '" 
      + to 
      + "'. See cause for more info.", e); 
    } 
    } 

Tôi cố gắng để tái tạo lại hành vi của chức năng này:

@SuppressWarnings("unchecked") 
    public static <T> T cast(Object o){ 
     try { 
      return (T) o; 
     } catch (ClassCastException e){ 
      throw new AssertionError("Error"); 
     } 
    } 

Và sử dụng:

Object o = new String("test"); 
Double d = cast(o); 

Nhưng ngoại trừ không bao giờ bị bắt, nó được ném vào dòng khi phương thức được gọi. Tại sao vậy?

Ngoài ra, tính năng này hoạt động chính xác như thế nào? Làm thế nào để các phương pháp biết những gì để đúc?

Trả lời

2

Như SJuan67 giải thích, bạn có thể không thực sự sử dụng phôi với các kiểu generic như trình biên dịch Java

sẽ thay thế tất cả các thông số loại trong các loại generic với giới hạn hoặc đối tượng của họ 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.

Thông tin thêm về tất cả các hạn chế generics here.

đang Vậy ButterKnife sẽ trông như thế này:

public Object castParam(Object paramObject, String paramString1, int paramInt1, String paramString2, int paramInt2) 
    { 
    return paramObject; 
    } 

Vì vậy, câu hỏi của bạn:

Q: Nhưng ngoại trừ không bao giờ bị bắt, nó được ném vào dòng khi phương pháp này được gọi. Tại sao vậy?

A: Vâng, ngay cả trong mã bytecode.

Hỏi: Ngoài ra, cách thức hoạt động chính xác? Làm thế nào để các phương pháp biết những gì để đúc?

A: Không. Ít nhất không giống như bạn nghĩ rằng nó sẽ. Trong thực tế, nó sẽ ném ClassCastException không phải là IllegalStateException hoặc AssertionError như bạn đã quan sát. Bạn thậm chí có thể thử nó với ứng dụng mẫu ButterKnife và kết hợp một TextView biết đến CheckBox:

@Bind(R.id.title) CheckBox title; 

Q: Làm thế nào để công tác thư viện sau đó?

A: Vâng IllegalStateException không bao giờ được gọi và bạn có ClassCastException. Tại sao nó giống như tôi không thực sự chắc chắn. Tuy nhiên, khi ButterKnife tạo mã, điều này có thể nhằm ngăn ngừa các lỗi biên dịch.

ví dụ:

public interface Some { 
} 

public static void weWantSome(Some d) { 
} 

public static void test() { 
    String o = "test"; 
    weWantSome((Some)o); //<-- compile error 
    weWantSome(Main.<Some>cast(o)); //<-- runtime error 
} 

Đó là lý do tại sao trong các mã ví dụ trước biên dịch nhưng không chạy.

7

Loại Generics chỉ được chọn tại thời điểm biên dịch, do loại xóa. Điều này được thực hiện bởi vì không có cách nào để giới thiệu các generics trong thời gian chạy trong Java 5 mà không phá vỡ tính tương thích ngược và buộc phải biên dịch lại tất cả các thư viện đã tồn tại.

Lịch sử dài ngắn, khi bạn xác định lớp hoặc phương thức "chung", mã thực tế được biên dịch là Object thay vì loại bạn đang ràng buộc phương pháp. Tất cả các kiểm tra các loại được thực hiện tại thời gian biên dịch.

Vì vậy, mã phương thức của bạn không thực sự thực hiện truyền trong câu hỏi return vì nó đang gán một thứ gì đó (một String) cho giá trị trả về Object. ClassCastException thực tế được trả về bởi dòng gọi bởi vì nó là nơi mà biến tham chiếu thực sự được gõ.

+0

Ở đây người khác đã cố gắng thực hiện chính xác như cũ: http://stackoverflow.com/questions/14524751/cast-object-to-generic-type-for-returning – SJuan76

+0

Thư viện hoạt động như thế nào? – Greyshack

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