2017-09-27 15 views
5

Tôi đang điều tra cách thư viện tạo đối tượng proxy hoạt động đặc biệt là tôi muốn hiểu cách chúng tìm nạp loại từ phương thức được khai báo. Ví dụ: thư viện phổ biến cho Android - Trang bị thêm:Cách xóa công trình xóa

interface MyService { 

    @GET("path") 
    Call<MyData> getData(); 
} 

Tôi đã nhầm lẫn - làm thế nào để có thể nhận được từ giao diện này chính xác Lớp MyData không phải là đối tượng thô? Nguyên nhân từ việc xóa loại hiểu biết của tôi sẽ xóa bất kỳ thông tin nào được đặt bên trong dấu ngoặc nhọn chung.

tôi đã viết một số mã thử nghiệm và đáng ngạc nhiên đối với tôi nó là rất dễ dàng để có được loại từ mã ví dụ:

@org.junit.Test 
public void run() { 
    Method[] methods = Test.class.getDeclaredMethods(); 
    Method testMethod = methods[0]; 
    System.out.println(testMethod.getReturnType()); 
    ParameterizedType genericType = ((ParameterizedType) testMethod.getGenericReturnType()); 
    Class<Integer> clazz = (Class<Integer>) genericType.getActualTypeArguments()[0]; 
    System.out.println(clazz); 
} 

interface Test { 
    List<Integer> test(); 
} 

Nó trông hơi bẩn nhưng nó hoạt động và in Integer. Nó có nghĩa là chúng ta có các loại trong thời gian chạy. Ngoài ra tôi đã đọc về một trick bẩn với các lớp nặc danh:

System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass()); 

in thô AbstractList<E> trong khi mã này

System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass()); 

in ArrayList<Integer>.

Và đó không phải là điều cuối cùng làm tôi bối rối. Trong Kotlin có được reified Generics từ đó trông giống như một số hack trong thời gian biên dịch nhưng chúng ta có thể dễ dàng có được lớp từ chung chung:

inline fun <reified T> test() { 
    print(T::class) 
} 

Và bây giờ tôi hoàn toàn nhầm lẫn với cơ chế loại tẩy xoá.

  1. Ai đó có thể giải thích, tại sao đôi khi nó chứa thông tin và đôi khi không?
  2. Tại sao generics không được triển khai theo cách thông thường trong Java? Có, tôi đọc rằng nó có thể phá vỡ sự hợp tác với các phiên bản trước, nhưng tôi muốn hiểu làm thế nào. Tại sao loại trả về chung không phá vỡ bất kỳ thứ gì trừ new ArrayList<Integer>?
  3. Tại sao các lớp ẩn danh giữ kiểu chung và không bị xóa?

Cập nhật: 4. Làm thế nào để generics reified làm việc trong Kotlin và tại sao điều thú vị như vậy không thể được thực hiện trong Java?

Here giải thích rõ ràng về cách hoạt động của các generics được đổi mới. @Mibac

Bạn chỉ có thể sử dụng được kết hợp lại với hàm nội tuyến. Như vậy một hàm làm cho trình biên dịch sao chép bytecode của hàm đến mọi địa chỉ nơi chức năng đang được sử dụng (chức năng đang được "nội tuyến"). Khi bạn gọi hàm inline với kiểu được sửa đổi, trình biên dịch biết loại thực tế được sử dụng làm đối số kiểu và sửa đổi bytecode được tạo để sử dụng trực tiếp lớp tương ứng. Do đó các cuộc gọi như myVar là T trở thành myVar là String, nếu đối số loại là String, trong bytecode và tại thời gian chạy.

+3

[Cách 'reified' hoạt động] (https://stackoverflow.com/a/45952201/3533380) – Mibac

Trả lời

3

Ai đó có thể giải thích, tại sao đôi khi nó chứa thông tin và đôi khi không?

On mức JVM có một Signature attribute rằng:

ghi một chữ ký (§4.7.9.1) cho một lớp, giao diện, xây dựng, phương pháp, hoặc lĩnh vực có khai trong việc sử dụng ngôn ngữ lập trình Java loại biến hoặc loại tham số.

Một trong những lý do tại sao bạn có thể muốn có nó là, ví dụ, trình biên dịch cần phải biết loại thực tế của đối số của một some_method đến từ precompiled some.class (mà đến từ bên thứ ba some.jar). Trong trường hợp này giả định rằng phương pháp mất Object có thể vi phạm các giả định mà some.class được biên dịch và bạn không thể gọi some_method theo cách an toàn.

Tại sao các lớp ẩn danh giữ loại chung và không bị xóa?

Khi bạn gọi:

System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass()); 

... không có gì được xác định theo lớp JVM, trong khi điều này:

System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass()); 

... thực sự xác định lớp trên jvm level, albiet ẩn danh trên mức laguage java.

Đây là lý do tại sao phản ánh mang lại kết quả khác nhau cho những trường hợp này.

Tại sao Generics không được triển khai theo cách thông thường trong Java? Có, tôi đọc rằng nó có thể phá vỡ sự hợp tác với các phiên bản trước, nhưng tôi muốn hiểu làm thế nào. Tại sao kiểu trả về chung không phá vỡ bất cứ thứ gì trừ ArrayListdoes mới?

Generics Làm thế nào để làm việc trong reified Kotlin và tại sao điều thú vị như vậy không thể được thực hiện trong Java?

Tôi không nghĩ bạn có thể đưa ra câu trả lời khách quan không dựa trên ý kiến. Hơn nữa, tôi muốn đề nghị chia nhỏ hoặc thu hẹp phạm vi câu hỏi của bạn.

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