2010-07-24 26 views
8

Làm cách nào để viết một số InternPool<T> chung trong Java? Có cần một giao diện Internable không?Generic InternPool <T> bằng Java?

String trong Java có khả năng thực hiện; Tôi muốn các lớp thực tập như BigDecimalAccount.

Trả lời

2

Điều này nghe có vẻ giống như bạn đang tìm kiếm flyweight pattern.

Bánh xe là mẫu thiết kế phần mềm. Trọng tải là một đối tượng giảm thiểu việc sử dụng bộ nhớ bằng cách chia sẻ càng nhiều dữ liệu càng tốt với các đối tượng tương tự khác

Nhấp vào liên kết, nó chứa một ví dụ Java.

+0

+1. Tôi nghĩ rằng đây là cả hai mô hình tương tự (hoặc có thể là một Flyweight chỉ là một ứng dụng của một Interner) nhưng tôi thích "Flyweight" bởi vì nó dễ dàng hơn để google – finnw

5

Something như thế này:

public class InternPool<T> { 

    private WeakHashMap<T, WeakReference<T>> pool = 
     new WeakHashMap<T, WeakReference<T>>(); 

    public synchronized T intern(T object) { 
     T res = null; 
     // (The loop is needed to deal with race 
     // conditions where the GC runs while we are 
     // accessing the 'pool' map or the 'ref' object.) 
     do { 
      WeakReference<T> ref = pool.get(object); 
      if (ref == null) { 
       ref = new WeakReference<T>(object); 
       pool.put(object, ref); 
       res = object; 
      } else { 
       res = ref.get(); 
      } 
     } while (res == null); 
     return res; 
    } 
} 

này phụ thuộc vào lớp yếu tố hồ bơi thực hiện equalshashCode để cung cấp "sự bình đẳng theo giá trị" và tuân theo để hợp đồng API cho các phương pháp đó. Nhưng chắc chắn là BigDecimal.


CẬP NHẬT - cho một lời giải thích lý do tại sao chúng ta cần một WeakHashMap<T, WeakReference<T>> chứ không phải là một WeakHashMap<T, T>, xem . Phiên bản ngắn gọn là các liên kết yếu yếu trong phần sau sẽ không bị GC phá vỡ vì các tham chiếu nhập tương ứng đang làm cho các giá trị có thể truy cập một cách mạnh mẽ.

+0

Tôi giả sử bạn không cần phải kiểm tra xem ref.get() là vô giá trị. –

+0

Tôi nghĩ không, nhưng tôi đã nhận ra rằng có một điều kiện chủng tộc với GC. Nếu GC chạy ngay lập tức sau khi cuộc gọi đến 'get',' ref' được trả lại có thể bị hỏng khi chúng ta nhìn vào nó. Toàn bộ lô cần phải được lặp lại. Đã cập nhật. –

+0

Tại sao bạn cần một WeakReference cho giá trị bản đồ? Không phải bạn đã sử dụng WeakhashMap vì vậy nếu không có tham chiếu mạnh mẽ đến đối tượng, mục nhập sẽ bị xóa? – as3rdaccount

4

Ví dụ, hãy xem Interner từ Guava. Nó không yêu cầu một giao diện Internable, nó chỉ dựa trên equalshashCode.

3

tôi sẽ tách các giải pháp thành hai lớp có mã sạch hơn và cũng theo cách này được thoát khỏi vòng lặp:

public class WeakPool<T> { 
    private final WeakHashMap<T, WeakReference<T>> pool = new WeakHashMap<T, WeakReference<T>>(); 
    public T get(T object) { 
     final T res; 
     WeakReference<T> ref = pool.get(object); 
     if (ref != null) { 
      res = ref.get(); 
     } else { 
      res = null; 
     } 
     return res; 
    } 
    public void put(T object) { 
     pool.put(object, new WeakReference<T>(object)); 
    } 
} 

và lớp interning sử dụng hồ bơi yếu là rất đơn giản:

public class InternPool<T> { 

    private final WeakPool<T> pool = new WeakPool<T>(); 

    public synchronized T intern(T object) { 
     T res = pool.get(object); 
     if (res == null) { 
      pool.put(object); 
      res = object; 
     } 
     return res; 
    } 
} 
1

Chỉ cần báo trước nhanh chóng:

Nó chưa được đề cập một cách rõ ràng ở trên, nhưng phải rõ ràng rằng các đối tượng đang được tập trung phải là một số không thay đổi loại.

Lưu ý thứ hai: Bạn không cần phải sử dụng một tham chiếu yếu khác cho đối tượng làm giá trị trong bản đồ, tham chiếu đến tĩnh sẽ đủ nếu bạn chỉ dựa vào keyset của bản đồ cho dữ liệu. Ví dụ, tuyên bố:

WeakHashMap<T,Boolean> 

Và chèn cặp như:

pool.put (object, Boolean.TRUE); 

Đó là một tiết kiệm nhỏ của một trường hợp WeakReference (nếu bạn không thể tái sử dụng một sử dụng cho các phím).

... hoặc tạo lớp WeakSet, vì @PeterVerhas đã thực hiện với WeakPool của mình.

+0

vì vậy với phương pháp của bạn làm thế nào có thể được lấy đại diện thực của một đối tượng? lặp đi lặp lại bởi tất cả các phím và kiểm tra bình đẳng ??? – Sergio

0

Không phải

"WeakReference ref = pool.get (object);"

thay vì là

WeakReference ref = pool.intern (object);

??

+0

Xin lỗi hiểu lầm, nó cho bình luận của tôi – FrederikH