2013-07-03 50 views
12

Tôi đã nghĩ rằng java xóa sạch loại bỏ chung loại trong thời gian biên dịch tuy nhiên khi tôi kiểm tra nó bằng bản thân mình tôi nhận ra có một số thông tin về các loại chung trong Bytecode.hiện loại Java xóa xóa loại chung của tôi?

đây là thử nghiệm của tôi:

tôi đã viết 2 lớp:

import java.util.*; 
public class Test { 
    List integerList; 
} 

import java.util.*; 
public class Test { 
    List<Integer> integerList; 
} 

tôi biên soạn cả hai lớp và ở đâu đó trong lớp chung tôi thấy dòng này

integerList{blah blah}Ljava/util/List;{blah blah} 
Signature{blah blah}%Ljava/util/List<Ljava/lang/Integer;>;{blah blah}<init> 

không n generic class:

integerList{blah blah}Ljava/util/List;{blah blah}<init> 

vì vậy rõ ràng là tôi có thông tin chung bên trong bytecode vì vậy điều tẩy xoá này là gì?

Trả lời

5

Một số thông tin loại chung được lưu trữ trong thuộc tính Signature. Tham khảo JLS 4.84.6JVM spec 4.3.4. Đọc here:

lẽ khiếu nại phổ biến nhất về Generics trong Java là họ không reified - không có một cách nào để biết khi chạy một List<String> là bất kỳ khác nhau từ một List<Long>. Tôi đã quen với điều này đến nỗi tôi khá ngạc nhiên khi chạy ngang qua công việc của Neil Gafter trên Super Type Tokens. Nó chỉ ra rằng trong khi JVM sẽ không theo dõi các đối số kiểu thực tế cho các cá thể của một lớp chung, nó theo dõi các đối số kiểu thực tế cho các lớp con của các lớp chung. Nói cách khác, trong khi ArrayList<String>() mới thực sự chỉ là ArrayList() mới khi chạy, nếu một lớp mở rộng ArrayList<String>, thì JVM biết rằng String là đối số kiểu thực cho tham số loại List.

Neal Gafter's blog.

+2

Điều này gây hiểu lầm. Siêu dữ liệu vẫn chỉ để phản ánh. Nó không được thống nhất. – Antimony

0

Xóa nghĩa là nhập chung không được kết hợp trong mã byte (khi danh sách được tạo hoặc sử dụng).

Chữ ký bạn nhìn thấy được sử dụng chỉ để cho biết rằng trường là chung chung.

1

Loại thông tin sẽ bị xóa khỏi đây

integerList = new ArrayList<Integer>(); 

trong bytecode nó sẽ tương đương với

integerList = new ArrayList(); 

và không có cơ hội để biết trong thời gian chạy từ integerList thời gian biên dịch của nó đối tượng là những gì kiểu.

+0

Chắc chắn! nhưng từ định nghĩa của "integerList" đó là Danh sách JVM có thể tìm ra loại –

+1

Có, với phản ánh từ Field, nhưng nếu bạn nhận được một thể hiện của ArrayList sẽ không có cách nào tìm ra kiểu generic của nó –

6

điều tẩy xóa này là gì ??

Erasure là ánh xạ từ loại thô đến loại thô. Cụm từ phổ biến "vì tẩy xoá" về cơ bản là vô nghĩa.Điều quan trọng là các chi tiết kỹ thuật sử dụng ánh xạ.

Có hai cách sử dụng thú vị.

  • Được sử dụng để ánh xạ chữ ký phương thức từ việc sử dụng Generics cho các loại thô. Đó là chữ ký thô được sử dụng cho quá tải. Điều này gây ra phần lớn các vấn đề với "tẩy xoá". Ví dụ: bạn không thể có hai phương thức add(List<String>)add(List<Integer>) cùng loại. Quá tải có lẽ không phải là một ý tưởng tuyệt vời, và không có sẵn sàng để thêm tính năng này.

  • Loại có sẵn cho một thể hiện của một đối tượng trong thời gian chạy là loại được tạo với xóa. Vì vậy, nếu bạn truyền đến, giả sử, (String) sẽ được kiểm tra trong thời gian chạy, nhưng nếu bạn truyền tới List<String> chỉ việc xóa loại đó (List) sẽ được kiểm tra. Bạn có thể có các biến loại List<String>List<Integer> trỏ đến chính xác cùng một phiên bản. Trong thực tế, bạn không nên sử dụng phôi (loại tham chiếu) trong 1,5 và sau đó.

Trường hợp thực tế, thông tin chung được lưu giữ trong tệp lớp và được cung cấp thông qua phản ánh. Vì vậy, bạn sẽ tìm thấy nó trên các định nghĩa lớp, siêu kiểu, trường, phương thức, hàm tạo, v.v.

+0

Cảm ơn, câu trả lời của bạn trợ giúp tôi rất nhiều. –

3

Đây là trường hợp sử dụng thuật ngữ chính xác thực sự quan trọng: Bytecode là bộ hướng dẫn của Máy ảo Java. Một tập tin lớp học chứa bytecode, mà còn thông tin được sử dụng để liên kết (ký hiệu trường, chữ ký phương thức, ...), đối với trình xác minh bytecode, cho trình gỡ lỗi, ...

Loại tẩy xoá có nghĩa là thông tin loại chung là không dịch sang mã byte; cụ thể hơn, tất cả các trường hợp của một kiểu generic đều có cùng biểu diễn trong mã byte. Tương tự như vậy, kiểu động của một đối tượng mà thời gian chạy theo dõi (được sử dụng bởi các toán tử cast và instanceof, và có sẵn thông qua getClass()) là giống nhau cho tất cả các cá thể của một lớp chung, không phân biệt bất kỳ tham số kiểu nào được cung cấp trong nguồn mã.

Thử nghiệm của bạn chứng minh rằng thông tin loại chung được giữ lại trong tệp lớp, cụ thể hơn, trong các loại phương thức và chữ ký trường. Đó là điều không ngạc nhiên, bởi vì các chữ ký thực sự được sử dụng trong thời gian biên dịch. Cũng có thể được sử dụng tại thời gian liên kết và thậm chí có thể truy cập thông qua api phản chiếu. Điểm khác biệt quan trọng là chúng là các loại trường hoặc phương thức được khai báo, không phải là loại đối tượng thực tế thời gian chạy.

Tức là, vì Java 1.5, chúng ta phải phân biệt giữa loại được khai báo của một biến và kiểu thời gian chạy của đối tượng mà nó đề cập đến. Các cựu hỗ trợ generics, sau này không. Và có, điều này có nghĩa là không có sự tương ứng một-một giữa thời gian biên dịch và các kiểu thời gian chạy.