2012-11-15 38 views
5

Tôi có một lớp học bất biến, TokenList, trong đó bao gồm một danh sách các đối tượng Token, mà cũng là không thay đổi:Sử dụng UUIDs cho equals rẻ() và hashCode()

@Immutable 
public final class TokenList { 

    private final List<Token> tokens; 

    public TokenList(List<Token> tokens) { 
     this.tokens = Collections.unmodifiableList(new ArrayList(tokens)); 
    } 

    public List<Token> getTokens() { 
     return tokens; 
    } 
} 

tôi làm một vài hoạt động bằng các TokenLists lấy nhiều TokenLists làm đầu vào và trả về một TokenList là đầu ra. Có thể có nhiều TokenLists tùy ý đi vào, và mỗi người có thể có nhiều Tokens tùy ý.

Các hoạt động này rất tốn kém và có khả năng hoạt động tương tự (tức là các đầu vào tương tự) sẽ được thực hiện nhiều lần, vì vậy tôi muốn lưu các kết quả đầu ra. Tuy nhiên, hiệu suất là rất quan trọng và tôi lo lắng về chi phí thực hiện hashCode() và equals() trên các đối tượng này có thể chứa nhiều phần tử tùy ý (vì chúng không thay đổi, hashCode có thể được lưu trữ, nhưng bằng vẫn sẽ đắt).

này dẫn tôi đến tự hỏi liệu tôi có thể sử dụng một UUID để cung cấp equals() và hashCode() đơn giản và rẻ tiền bằng cách làm cho các bản cập nhật sau để TokenList:

@Immutable 
public final class TokenList { 

    private final List<Token> tokens; 
    private final UUID uuid; 

    public TokenList(List<Token> tokens) { 
     this.tokens = Collections.unmodifiableList(new ArrayList(tokens)); 
     this.uuid = UUID.randomUUID(); 
    } 

    public List<Token> getTokens() { 
     return tokens; 
    } 

    public UUID getUuid() { 
     return uuid; 
    } 
} 

Và một cái gì đó như thế này để hoạt động như một khóa bộ nhớ cache:

@Immutable 
public final class TopicListCacheKey { 

    private final UUID[] uuids; 

    public TopicListCacheKey(TopicList... topicLists) { 
     uuids = new UUID[topicLists.length]; 
     for (int i = 0; i < uuids.length; i++) { 
      uuids[i] = topicLists[i].getUuid(); 
     } 
    } 

    @Override 
    public int hashCode() { 
     return Arrays.hashCode(uuids); 
    } 

    @Override 
    public boolean equals(Object other) { 
     if (other == this) return true; 
     if (other instanceof TopicListCacheKey) 
      return Arrays.equals(uuids, ((TopicListCacheKey) other).uuids); 
     return false; 
    } 
} 

Tôi cho rằng có 2^UUID khác nhau và tôi có thể có tối đa 1.000.000 đối tượng TokenList hoạt động trong ứng dụng bất kỳ lúc nào. Với điều này, và thực tế là các UUID được sử dụng kết hợp trong các khóa bộ nhớ cache, có vẻ như là cơ hội của việc tạo ra kết quả sai này biến mất nhỏ. Tuy nhiên, tôi cảm thấy khó chịu về việc tiếp tục với nó vì nó chỉ cảm thấy 'bẩn thỉu'. Có bất kỳ lý do gì mà tôi không nên sử dụng hệ thống này không? Chi phí hiệu năng của SecureRandom được sử dụng bởi UUID.randomUUID() có lớn hơn mức tăng (đặc biệt là vì tôi mong đợi nhiều luồng sẽ làm điều này cùng một lúc)? Các vụ va chạm có nhiều khả năng hơn tôi nghĩ không? Về cơ bản, có điều gì sai trái khi làm theo cách này không ??

Cảm ơn.

+0

Tại sao bạn thực hiện bằng ở vị trí đầu tiên? Nếu bạn không cần nó (và cố gắng thay thế nó bằng UUID thì bạn không nên), đừng ghi đè bằng/hashcode. Nếu bạn muốn nó, bạn cần phải chắc chắn rằng cùng một danh sách mã thông báo bản đồ để cùng một uuid mỗi lần. –

+1

Thực hiện việc này có thể phá vỡ hợp đồng chung trên ['List.equals()'] (http://docs.oracle.com/javase/7/docs/api/java/util/List.html#equals (java.lang) .Object)), đó là những gì bạn muốn? Ngoài ra nếu bằng là đắt tiền, sử dụng 'hashCode' đầu tiên trong bằng, và sau đó chuyển sang bằng thực tế nếu chúng giống nhau. –

Trả lời

0

SecureRandom sẽ không cung cấp cho bạn bất kỳ sự thăng tiến nào, nó chỉ "ngẫu nhiên" hơn bình thường Random. Khả năng va chạm là thứ gì đó theo thứ tự của số bình phương chia cho tổng số UUID có thể, vì vậy một số rất nhỏ. Tuy nhiên, tôi sẽ không dựa vào số lượng luôn là duy nhất. Bạn có thể thử điều này, nhưng tốt nhất là kiểm tra và đảm bảo rằng số đó chưa được bao gồm ở một nơi khác trong danh sách hashcode. Nếu không, bạn có thể gặp phải một số vấn đề rất lạ ...

3

Điều bạn đang cố gắng hết sức phức tạp và cần phân tích chi tiết. Vì vậy, bạn cần phải kiểm tra các câu hỏi dưới đây trước khi quyết định về bất kỳ cách tiếp cận nào.

Các hoạt động này rất tốn kém, và có một cơ hội tốt mà các hoạt động tương tự (tức là đầu vào tương tự) sẽ được thực hiện nhiều lần

1) Khi bạn nói "Cùng đầu vào" ở trên dòng, bạn có ý nghĩa gì? Điều này có nghĩa là, chính xác cùng một đối tượng tức là một đối tượng được giới thiệu qua một số tham chiếu (cùng một vị trí bộ nhớ) hay nó có nghĩa là các đối tượng riêng biệt của bộ nhớ nhưng có cùng một dữ liệu giống nhau?

Ở đây nếu đối tượng giống nhau, tức là cùng một vị trí bộ nhớ, thì việc so sánh == sẽ hoạt động tốt. Đối với điều này, bạn phải giữ đối tượng tham chiếu như là chìa khóa trong bộ nhớ cache.

Nhưng nếu đó là trường hợp thứ hai, tức làcác đối tượng riêng biệt về trí nhớ nhưng lại giống nhau, thì tôi không nghĩ UUID sẽ giúp bạn. Bởi vì bạn phải đảm bảo rằng 2 đối tượng riêng biệt đó sẽ nhận được cùng một UUID. Điều này sẽ không dễ dàng như mọi khi bạn phải trải qua toàn bộ dữ liệu TokenList để đảm bảo rằng

2) Sử dụng mã băm trong bộ nhớ cache, có an toàn không? Tôi khuyên bạn không nên sử dụng hashcode làm khóa vì mặc dù 2 đối tượng khác nhau, chúng có thể có cùng mã băm. Vì vậy, logic của bạn có thể đi sai lầm khủng khiếp.

Vì vậy, hãy nhận câu trả lời cho những câu hỏi này chỉ rõ ràng trước tiên & chỉ sau đó nghĩ về cách tiếp cận.

+0

Bất kỳ TokenLists 'thế hệ đầu tiên' nào bằng nhau về mặt logic sẽ bằng nhau theo '=='. 'TokenLists' thế hệ thứ hai - kết quả đầu ra từ các hoạt động sử dụng thế hệ thứ nhất - sẽ là các đối tượng khác nhau mặc dù hợp lý giống nhau, trừ khi tôi sử dụng bộ nhớ đệm để trả về cùng một đối tượng. Vì vậy, tôi có thể cache hashCode và dựa vào == để so sánh - tất cả đều rất nhanh. Cảm ơn! –

Các vấn đề liên quan