Tại sao Java Generics không hỗ trợ các kiểu nguyên thủy?


236

Tại sao các tướng trong Java làm việc với các lớp nhưng không phải với các kiểu nguyên thủy?

Ví dụ, điều này hoạt động tốt:

List<Integer> foo = new ArrayList<Integer>();

nhưng điều này không được phép:

List<int> bar = new ArrayList<int>();

1
int i = (int) đối tượng mới (); biên dịch tốt mặc dù.
Sachin Verma

Câu trả lời:


243

Generics trong Java là một cấu trúc thời gian biên dịch hoàn toàn - trình biên dịch biến tất cả các sử dụng chung thành phôi thành đúng loại. Điều này là để duy trì khả năng tương thích ngược với các thời gian chạy JVM trước đó.

Điều này:

List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);

bị biến thành (đại khái):

List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);

Vì vậy, bất cứ thứ gì được sử dụng làm tướng đều phải có thể chuyển đổi thành Object (trong ví dụ này get(0)trả về một Object) và các kiểu nguyên thủy thì không. Vì vậy, chúng không thể được sử dụng trong thuốc generic.


8
@DanyalAytekin - Trên thực tế, các tổng quát Java KHÔNG được xử lý như các mẫu C ++ ...
Stephen C

20
Tại sao trình biên dịch Java cũng không thể đóng hộp kiểu nguyên thủy trước khi nó được sử dụng? Điều này nên có thể phải không?
vrwim

13
@ DVRwim - Có thể là có thể. Nhưng nó sẽ chỉ là cú pháp đường. Vấn đề thực sự là các thế hệ Java với các nguyên hàm đóng hộp tương đối đắt về cả thời gian và không gian so với mô hình C ++ / C # ... trong đó loại nguyên thủy thực tế được sử dụng.
Stephen C

6
@MauganRa yeah Tôi biết tôi có thể :) Tôi đứng trước mặt tôi rằng đây là thiết kế khủng khiếp tho. Hy vọng rằng nó sẽ được sửa trong java 10 (hoặc tôi đã nghe) và các hàm bậc cao hơn. Đừng trích dẫn tôi về điều đó.
Ced

4
@Ced hoàn toàn đồng ý rằng đó là thiết kế tồi tệ, làm tổn thương vô tận những người mới bắt đầu và các chuyên gia cũng vậy
MauganRa

37

Trong Java, thuốc generic hoạt động theo cách mà họ làm ... ít nhất là một phần ... bởi vì chúng đã được thêm vào ngôn ngữ một số năm sau khi ngôn ngữ được thiết kế 1 . Các nhà thiết kế ngôn ngữ đã bị hạn chế trong các tùy chọn của họ về khái quát bằng cách phải đưa ra một thiết kế tương thích ngược với ngôn ngữ hiện có và thư viện lớp Java .

Các ngôn ngữ lập trình khác (ví dụ C ++, C #, Ada) cho phép các kiểu nguyên thủy được sử dụng làm kiểu tham số cho tổng quát. Nhưng mặt trái của việc này là việc triển khai các tổng quát (hoặc kiểu mẫu) của các ngôn ngữ như vậy thường đòi hỏi phải tạo ra một bản sao riêng biệt của loại chung cho từng tham số loại.


1 - Lý do chung không được đưa vào Java 1.0 là do áp lực thời gian. Họ cảm thấy rằng họ phải nhanh chóng phát hành ngôn ngữ Java để lấp đầy cơ hội thị trường mới được trình bày bởi các trình duyệt web. James Gosling đã tuyên bố rằng ông muốn đưa vào thuốc generic nếu họ có thời gian. Ngôn ngữ Java sẽ trông như thế nào nếu điều này xảy ra là phỏng đoán của bất kỳ ai.


11

Trong java generic được thực hiện bằng cách sử dụng "Loại xóa" để tương thích ngược. Tất cả các loại chung được chuyển đổi thành Object khi chạy. ví dụ,

public class Container<T> {

    private T data;

    public T getData() {
        return data;
    }
}

sẽ được nhìn thấy trong thời gian chạy như,

public class Container {

    private Object data;

    public Object getData() {
        return data;
    }
}

trình biên dịch có trách nhiệm cung cấp diễn viên phù hợp để đảm bảo an toàn loại.

Container<Integer> val = new Container<Integer>();
Integer data = val.getData()

sẽ trở thành

Container val = new Container();
Integer data = (Integer) val.getData()

Bây giờ câu hỏi là tại sao "Đối tượng" được chọn là loại trong thời gian chạy?

Câu trả lời là Object là siêu lớp của tất cả các đối tượng và có thể đại diện cho bất kỳ đối tượng nào do người dùng xác định.

Vì tất cả các nguyên thủy không kế thừa từ " Đối tượng " nên chúng tôi không thể sử dụng nó làm loại chung.

FYI: Dự án Valhalla đang cố gắng giải quyết vấn đề trên.


Cộng 1 cho danh pháp thích hợp.
Drazen Bjelovuk

7

Các bộ sưu tập được xác định để yêu cầu một loại xuất phát từ java.lang.Object. Các cơ sở đơn giản là không làm điều đó.


26
Tôi nghĩ câu hỏi ở đây là "tại sao". Tại sao thuốc generic yêu cầu Đối tượng? Sự đồng thuận dường như là ít lựa chọn thiết kế hơn và có nhiều khả năng tương thích ngược hơn. Trong mắt tôi, nếu thuốc generic không thể xử lý nguyên thủy, đó là sự thiếu hụt chức năng. Vì thế, mọi thứ liên quan đến nguyên thủy phải được viết cho từng nguyên thủy: thay vì So sánh <t, t>, chúng ta có Integer.compare (int a, int b), Byte.compare (byte a, byte b), v.v. Đó không phải là một giải pháp!
John P

1
Yeah genericics trên các loại nguyên thủy sẽ là một tính năng phải có. Đây là một liên kết đến một đề xuất cho nó openjdk.java.net/jeps/218
crow

4

Theo Tài liệu Java , các biến kiểu chung chỉ có thể được khởi tạo với các kiểu tham chiếu, không phải các kiểu nguyên thủy.

Điều này được cho là xuất hiện trong Java 10 trong Dự án Valhalla .

Trong bài viết của Brian Goetz về Nhà nước chuyên môn hóa

Có một lời giải thích tuyệt vời về lý do mà chung chung không được hỗ trợ cho nguyên thủy. Và, nó sẽ được triển khai như thế nào trong các bản phát hành Java trong tương lai.

Việc triển khai đã xóa hiện tại của Java, tạo ra một lớp cho tất cả các khởi tạo tham chiếu và không hỗ trợ cho các khởi tạo nguyên thủy. (Đây là một bản dịch đồng nhất và hạn chế rằng các tổng quát của Java chỉ có thể bao gồm các loại tham chiếu xuất phát từ các giới hạn của dịch đồng nhất đối với tập hợp mã byte của JVM, sử dụng các mã byte khác nhau cho các hoạt động trên các loại tham chiếu so với các kiểu nguyên thủy.) Tuy nhiên, các tổng quát bị xóa trong Java cung cấp cả tham số hành vi (phương thức chung) và tham số dữ liệu (tức thời nguyên và ký tự đại diện của các loại chung.)

...

một chiến lược dịch thuật đồng nhất đã được chọn, trong đó các biến loại chung được xóa theo giới hạn của chúng khi chúng được kết hợp vào mã byte. Điều này có nghĩa là cho dù một lớp có chung chung hay không, nó vẫn biên dịch thành một lớp duy nhất, có cùng tên và có chữ ký thành viên giống nhau. Loại an toàn được xác minh tại thời gian biên dịch và thời gian chạy không bị cản trở bởi hệ thống loại chung. Đổi lại, điều này áp đặt hạn chế rằng thuốc generic chỉ có thể hoạt động trên các loại tham chiếu, vì Object là loại chung nhất có sẵn và nó không mở rộng sang các loại nguyên thủy.


0

Khi tạo một đối tượng, bạn không thể thay thế một kiểu nguyên thủy cho tham số loại. Vì lý do hạn chế này, đó là vấn đề triển khai trình biên dịch. Các kiểu nguyên thủy có các hướng dẫn mã byte riêng để tải và lưu trữ vào ngăn xếp máy ảo. Vì vậy, không thể biên dịch các tổng quát nguyên thủy vào các đường dẫn mã byte riêng biệt này, nhưng nó sẽ làm cho trình biên dịch trở nên phức tạp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.