it-swarm-vi.com

Điều gì là sai với khái quát của Java?

Tôi đã thấy nhiều lần trên trang này đăng các bài viết về việc triển khai các khái niệm chung của Java. Bây giờ, tôi có thể thành thật nói rằng tôi không có vấn đề gì với việc sử dụng chúng. Tuy nhiên, tôi đã không cố gắng tự tạo một lớp chung chung. Vậy, vấn đề của bạn với hỗ trợ chung của Java là gì?

50
Michael K

Việc triển khai chung của Java sử dụng loại xóa . Điều này có nghĩa là các bộ sưu tập chung được gõ mạnh của bạn thực sự thuộc loại Object khi chạy. Điều này có một số cân nhắc về hiệu suất vì nó có nghĩa là các kiểu nguyên thủy phải được đóng hộp khi thêm vào bộ sưu tập chung. Tất nhiên những lợi ích của tính chính xác của kiểu thời gian biên dịch lớn hơn mức độ thông thường của việc xóa kiểu và tập trung ám ảnh vào khả năng tương thích ngược.

56
ChaosPandion

Quan sát rằng các câu trả lời đã được cung cấp tập trung vào sự kết hợp của ngôn ngữ Java, JVM và Java.

Không có gì sai với các khái quát của Java khi có liên quan đến ngôn ngữ Java. Như được mô tả trong C # vs Java generic , các tổng quát của Java khá tốt ở cấp độ ngôn ngữ1.

Điều tối ưu là JVM không hỗ trợ trực tiếp chung chung, điều này gây ra một số hậu quả lớn:

  • các phần liên quan đến phản chiếu của Thư viện lớp không thể hiển thị thông tin loại đầy đủ có sẵn bằng ngôn ngữ Java
  • một số hình phạt hiệu suất có liên quan

Tôi cho rằng sự khác biệt mà tôi đang tạo ra là một ngôn ngữ mô phạm vì ngôn ngữ Java được biên dịch phổ biến với JVM làm mục tiêu và Java làm thư viện lõi.

1 Với ngoại lệ có thể có của các ký tự đại diện, được cho là làm cho kiểu suy luận không thể giải quyết được trong trường hợp chung. Đây là một sự khác biệt lớn giữa C # và Java chung chung không được đề cập rất thường xuyên. Cảm ơn, Antimon.

26
Roman Starkov

Những lời chỉ trích thông thường là thiếu sự thống nhất. Điều đó có nghĩa là các đối tượng trong thời gian chạy không chứa thông tin về các đối số chung của chúng (mặc dù thông tin vẫn còn hiện diện trên các trường, phương thức, hàm tạo và lớp và giao diện mở rộng). Điều này có nghĩa là bạn có thể chuyển, ArrayList<String> Thành List<File>. Trình biên dịch sẽ đưa ra các cảnh báo cho bạn, nhưng nó cũng sẽ cảnh báo bạn nếu bạn lấy ArrayList<String> Gán nó cho một tham chiếu Object và sau đó chuyển nó thành List<String>. Nhược điểm là với các khái quát có lẽ bạn không nên thực hiện, việc thực hiện sẽ tốt hơn nếu không có dữ liệu không cần thiết và tất nhiên là khả năng tương thích ngược.

Một số người phàn nàn rằng bạn không thể quá tải trên cơ sở các đối số chung (void fn(Set<String>)void fn(Set<File>)). Bạn cần sử dụng tên phương thức tốt hơn để thay thế. Lưu ý rằng quá tải này sẽ không yêu cầu thống nhất, vì quá tải là một vấn đề thời gian tĩnh, biên dịch.

Các kiểu nguyên thủy không hoạt động với thuốc generic.

Ký tự đại diện và giới hạn khá phức tạp. Chúng rất hữu ích. Nếu Java giao diện không thay đổi ưa thích và giao diện không hỏi, thì bên khai báo thay vì tổng quát bên sử dụng sẽ phù hợp hơn.

13
Tom Hawtin - tackline

Generics Java hút vì bạn không thể làm như sau:

public class AsyncAdapter<Parser,Adapter> extends AsyncTask<String,Integer,Adapter> {
    proptected Adapter doInBackground(String... keywords) {
      Parser p = new Parser(keywords[0]); // this is an error
      /* some more stuff I was hoping for but couldn't do because
         the compiler wouldn't let me
      */
    }
}

Bạn sẽ không cần phải bán thịt mọi lớp trong đoạn mã trên để làm cho nó hoạt động như bình thường nếu các tổng quát thực sự là các tham số của lớp chung.

10
davidk01
  • cảnh báo trình biên dịch cho các tham số chung bị thiếu không phục vụ mục đích làm cho ngôn ngữ trở nên dài dòng vô nghĩa, ví dụ: public String getName(Class<?> klazz){ return klazz.getName();}

  • Generics không chơi Nice với mảng

  • Thông tin loại bị mất làm cho sự phản chiếu một mớ hỗn độn của băng đúc và ống dẫn.

5
Steve B.

Tôi nghĩ rằng những câu trả lời khác đã nói điều này ở một mức độ nào đó, nhưng không rõ ràng lắm. Một trong những vấn đề với thuốc generic là mất các loại chung trong quá trình phản ánh. Ví dụ:

List<String> arr = new ArrayList<String>();
assertTrue( ArrayList.class, arr.getClass() );
TypeVarible[] types = arr.getClass().getTypedVariables();

Thật không may, các kiểu trả về không thể cho bạn biết rằng các kiểu chung của mảng là Chuỗi. Đó là một sự khác biệt tinh tế, nhưng nó quan trọng. Bởi vì mảng được tạo trong thời gian chạy, các kiểu chung bị xóa trong thời gian chạy, do đó bạn không thể tìm ra. Như một số đã nêu ArrayList<Integer> trông giống như ArrayList<String> từ quan điểm phản ánh.

Điều này có thể không quan trọng đối với người dùng Generics, nhưng giả sử chúng tôi muốn tạo một số khung ưa thích sử dụng sự phản chiếu để tìm ra những điều lạ mắt về cách người dùng khai báo các loại chung chung cụ thể.

Factory<MySpecialObject> factory = new Factory<MySpecialObject>();
MySpecialObject obj = factory.create();

Giả sử chúng tôi muốn một nhà máy chung tạo ra một thể hiện của MySpecialObject bởi vì đó là loại chung chung cụ thể mà chúng tôi đã khai báo cho trường hợp này. Lớp Factory cũng không thể tự hỏi mình để tìm ra loại cụ thể được khai báo cho trường hợp này vì Java đã xóa chúng.

Trong các tổng quát của .Net, bạn có thể thực hiện việc này vì trong thời gian chạy, đối tượng biết các kiểu chung vì trình biên dịch tuân thủ nhị phân. Với các lần xóa Java không thể làm điều này.

5
chubbsondubs

Tôi có thể nói một vài điều tốt về khái quát, nhưng đó không phải là câu hỏi. Tôi có thể phàn nàn rằng chúng không có sẵn trong thời gian chạy và không hoạt động với mảng, nhưng điều đó đã được đề cập.

Một phiền toái tâm lý lớn: Thỉnh thoảng tôi gặp tình huống không thể tạo ra thuốc generic để làm việc. (Mảng là ví dụ đơn giản nhất.) Và tôi không thể biết liệu thuốc generic không thể thực hiện công việc hay liệu tôi chỉ ngu ngốc. Tôi ghét điều đó. Một cái gì đó giống như thuốc generic nên hoạt động luôn. Mỗi lần tôi không thể làm những gì tôi muốn bằng cách sử dụng ngôn ngữ Java, tôi biết vấn đề là tôi và tôi biết nếu tôi chỉ giữ đẩy, cuối cùng tôi sẽ đến đó. Với thuốc generic, nếu tôi trở nên quá cố chấp, tôi có thể lãng phí rất nhiều thời gian.

Nhưng vấn đề thực sự là thuốc generic tạo ra quá nhiều phức tạp cho quá ít lợi ích. Trong những trường hợp đơn giản nhất, nó có thể ngăn tôi thêm Apple vào danh sách có chứa ô tô. Tốt. Nhưng nếu không có chung chung, lỗi này sẽ khiến ClassCastException thực sự nhanh chóng trong thời gian chạy với ít thời gian lãng phí. Nếu tôi Thêm một chiếc xe có ghế trẻ em với một đứa trẻ trong đó, tôi có cần cảnh báo thời gian biên dịch rằng danh sách này chỉ dành cho những chiếc xe có ghế trẻ em chứa tinh tinh con không? Một danh sách các trường hợp Object đơn giản bắt đầu giống như một ý tưởng hay.

Mã chung có thể có rất nhiều từ và ký tự và chiếm nhiều không gian thừa và mất nhiều thời gian hơn để đọc. Tôi có thể dành nhiều thời gian để có được tất cả các mã bổ sung đó để hoạt động đúng. Khi nó làm, tôi cảm thấy điên rồ thông minh. Tôi cũng đã lãng phí vài giờ hoặc hơn thời gian của riêng mình và tôi phải tự hỏi liệu có ai khác sẽ có thể tìm ra mã không. Tôi muốn có thể giao nó để bảo trì cho những người kém thông minh hơn tôi hoặc những người có ít thời gian để lãng phí.

Mặt khác (Tôi có một chút vết thương ở đó và cảm thấy cần phải cung cấp một số dư), thật tuyệt khi sử dụng các bộ sưu tập và bản đồ đơn giản để có thêm, đặt và được kiểm tra khi viết và nó thường không thêm nhiều phức tạp vào mã ( if ai đó khác viết bộ sưu tập hoặc bản đồ) . Và Java tốt hơn C #. Có vẻ như không có bộ sưu tập C # nào tôi muốn sử dụng bao giờ xử lý chung chung. (Tôi thừa nhận tôi có sở thích kỳ lạ trong các bộ sưu tập.)

1
RalphChapin