2012-04-17 17 views
13

Tôi không chắc chắn những gì tôi muốn làm là có thể, nhưng nếu có, tôi muốn tìm hiểu làm thế nào. Về cơ bản, tôi muốn tạo một Bản đồ trong đó khóa là một lớp (java.lang.Class) và giá trị cho mục nhập đó là một thể hiện của lớp đó. Hiện tại tôi cóBản đồ Java, khóa = class, giá trị = instance của lớp đó

private Map<Class<?>, Object> myMap = new HashMap<Class<?>, Object>(); 

Tuy nhiên, điều này có nghĩa là mọi đối tượng đều có thể được đặt trong Bản đồ. Nếu có thể, tôi muốn làm cho nó, vì vậy chỉ có thể đặt một thể hiện của lớp trong khóa vào bản đồ. Có cách nào để sử dụng không? parametrization trên lớp để đảm bảo điều này?

Ngoài ra, tôi thấy có thể là possible memory leak khi thực hiện một việc như thế này. Tôi không chắc tôi hoàn toàn hiểu được điều này xảy ra như thế nào. Tôi sẽ chỉ dán các vật thể đơn vào bản đồ, vậy vẫn còn lo ngại về rò rỉ bộ nhớ? Nếu vậy, làm thế nào để ngăn chặn nó?

+0

Với những gì tôi đang làm, điều không quan trọng là tôi đảm bảo điều này.Tôi chỉ muốn biết nếu nó có thể. Thật tốt khi biết tất cả điều này để tham khảo trong tương lai. – dnc253

Trả lời

10

Hệ thống kiểu Java đơn giản không đủ mạnh để thực thi ràng buộc kiểu bạn đang mô tả trực tiếp và bạn cần thực hiện một số phôi không an toàn để thực hiện công việc này - hoặc bọc Map trong một số API khác. loại an toàn. Guava'sClassToInstanceMap thực hiện chính xác trường hợp sử dụng này, cung cấp API an toàn bên ngoài áp đặt các hạn chế bổ sung trên giao diện Map để làm cho nó hoạt động. (Tiết lộ: Tôi đóng góp cho Guava.)

Thời gian duy nhất điều này có thể gây ra rò rỉ bộ nhớ là có một số lớp bạn đang sử dụng ở đây sẽ không được giữ lại trong suốt thời gian của ứng dụng. Đây không phải là một mối quan tâm đối với nhiều người dùng, đặc biệt nếu bạn đang viết một ứng dụng "phía máy chủ" không quan tâm đến việc dỡ bỏ các lớp không sử dụng.

+0

Với điều này, có thể một giải pháp đơn giản là mở rộng HashMap và ghi đè lên phương thức đặt để thực thi rằng giá trị là từ cùng một lớp với khóa. – elevine

+1

Tôi phải thừa nhận rằng tôi hầu như không thích giải pháp đó bởi vì bạn vẫn phải làm phôi và mọi thứ, và bạn không nhận được những lợi ích về an toàn kiểu tại thời gian biên dịch. –

+0

+1 cho "hoặc bọc Bản đồ trong một số API khác thực thi an toàn loại" (và để đóng góp cho ổi :) Nhưng bạn không thể làm điều này với một Class.cast đơn giản() (xem câu trả lời của tôi bên dưới)? – DaveFar

0

Điều này là không thể do loại xóa.

Tuy nhiên, bạn có thể phân lớp HashMap và viết một số logic vào phương pháp put mà sẽ làm việc này cho bạn:

public void put(K key, V value) { 

    if (// value is an instance of key using .getClass()) { 
     super.put(key, value) 
    } 
    throw new Exception(); 
} 

(Mã chỉ mang tính chất minh họa)

6

Bạn có thể ẩn các bộ sưu tập và chỉ cho phép nó được truy cập thông qua các phương thức accessor.

private final Map<Class, Object> myMap = new HashMap<Class, Object>(); 

public <T> void putMap(Class<T> tClass, T t) { 
    myMap.put(tClass, t); 
} 

@SuppressWarnings("unchecked") 
public <T> T getMap(Class<T> tClass) { 
    return (T) myMap.get(tClass); 
} 

Cảnh báo có thể bị bỏ qua vì bạn biết rằng phương pháp cuối cùng là an toàn ngay cả khi trình biên dịch không.

5

Những gì bạn đang sử dụng là heterogeneous container. Các có thể được tạo an toàn bằng cách sử dụng mã thông báo loại (như bạn đã làm) và Class.cast() với logic ứng dụng chính xác: Vì vậy, có một phím tắt không được kiểm soátCảnh báo trong phạm vi Class.cast(), nhưng logic ứng dụng đảm bảo tính chính xác.

Tôi khuyên bạn nên đọc Mục Java hiệu quả của Josh Bloch 29: Xem xét các thùng chứa không đồng nhất an toàn. Ví dụ của mình là:

// Typesafe heterogeneous container pattern - implementation 
public class Favorites { 
    private Map<Class<?>, Object> favorites = 
    new HashMap<Class<?>, Object>(); 

    public <T> void putFavorite(Class<T> type, T instance) { 
    if (type == null) 
     throw new NullPointerException("Type is null"); 
    favorites.put(type, instance); 
    } 

    public <T> T getFavorite(Class<T> type) { 
    return type.cast(favorites.get(type)); 
    } 
} 

tôi chỉ nhìn thấy một khả năng cho bộ nhớ rò rỉ nếu bạn giữ tùy tiện nhiều loại khác nhau bạn thực sự không còn cần nữa.