2013-08-03 37 views
15

Tôi đã đọc rất nhiều bài đăng trong một giờ qua, nhưng tôi vẫn chưa rõ ràng về khái niệm sử dụng các đối tượng bất biến như các khóa trong Hashmap. Tôi có một hashmap có khóa của nó như là một String. Giá trị trong hashmap là MyStore, nơi MyStore đại diện cho thông tin về các cửa hàng mà tôi sở hữu. Chuỗi đại diện cho địa chỉ. Trong mã của tôi, logic tôi có là, đầu tiên tôi nhìn vào bản đồ cho khóa đó, nếu hiện tại -> nhận được giá trị của nó, nếu nó không có mặt, đặt nó trong hashmap. Quản lý của tôi chỉ nói với tôi chìa khóa sẽ thay đổi trong tương lai, đó là địa chỉ của các cửa hàng của tôi sẽ thay đổi trong tương lai. Ông nói trong trường hợp đó, logic của tôi kiểm tra đầu tiên nếu chìa khóa tồn tại sẽ không hoạt động. Tôi không hiểu ý anh ấy ở đây. Tôi muốn hiểu các điểm dưới đây rất rõ ràng -Chuỗi là khóa trong hashmap

  1. Sự khác biệt giữa các khóa có thể thay đổi và không thay đổi được cho một băm.
  2. Điều gì xảy ra nếu bạn sử dụng khóa không thay đổi có thể thay đổi? - Tôi biết điều này không có ý nghĩa, nhưng tôi muốn hiểu rõ những gì người quản lý của tôi đang nói ở đây.
  3. Một số bài viết nói về chuỗi nếu được sử dụng làm khóa trong bộ nhớ cache băm hashcode của chúng -Điều này có nghĩa là gì?
  4. Nếu cho phép nói rằng tôi đã sử dụng các đối tượng có thể thay đổi làm khóa trong hashmap của tôi đã triển khai hashcode và bằng, thì nó có hoạt động không? Tôi giả định nó sẽ bởi vì nếu thay đổi quan trọng, phương pháp chứa sẽ xem xét nếu khóa là hiện tại. Nếu không có mặt, nó sẽ đặt mục nhập để bạn có thể nhận được trong tương lai.

Tôi không có ý định tạo một bài đăng trùng lặp nếu điều này đã được thảo luận trước đây. Nếu tôi bỏ lỡ đọc bài đăng có câu trả lời cho tất cả các câu hỏi của tôi, hãy chỉ cho tôi câu hỏi đó. Nếu không, vui lòng giải thích các thuật ngữ của giáo dân về các câu hỏi trên tôi có để nó có ích trong tương lai cho những người đọc khác :). Vui lòng chỉnh sửa chủ đề của bài đăng của tôi để trong tương lai nếu có ai có câu hỏi tương tự, họ truy cập trực tiếp tại đây :)

+1

này nên trả lời câu hỏi của bạn http://stackoverflow.com/questions/214714/mutable-vs-immutable-objects – Spencer

+0

Bao giờ thay đổi băm mã ngắt hợp đồng HashMap của. Trong trường hợp này, bạn có thể muốn [ánh xạ theo tham chiếu đối tượng] (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/IdentityHashMap.html). Hoặc chuyển đổi bản đồ thành quan hệ đối tượng-thuộc tính. –

Trả lời

23

Đầu tiên: HashMap hoạt động như thế nào?

Về cơ bản nó có một mảng và khi bạn đặt cặp khóa-giá trị trong bản đồ, nó được lưu trữ tại một trong các vị trí trong mảng. Vị trí trong mảng được chọn dựa trên kết quả của khóa hashCode() của khóa được chuyển đến phương thức băm. Tại sao vậy? Vâng, nếu bạn yêu cầu giá trị cho một khóa nhất định, chỉ mục trong mảng để tìm khóa và giá trị liên quan của nó chỉ có thể được tính toán lại để tìm chỉ mục trong mảng một lần nữa. (Một số logic hơn là cần thiết để đối phó với các phím mà bản đồ để chỉ số tương tự, nhưng Tôi chỉ cố gắng để giúp bạn hiểu được cơ chế cơ bản) Sau đó equals() được sử dụng để kiểm tra xem phím ở chỉ số tính toán thực sự là chìa khóa yêu cầu .

  1. Từ điều này, nên rõ ràng hơn một chút tại sao khóa không thể thay đổi tốt hơn khóa có thể thay đổi. Khóa không thay đổi sẽ luôn giữ nguyên giá trị hashCode() và hàm băm sẽ tìm lại nhóm chính xác (= chỉ mục trong mảng của mảng băm) một lần nữa.

    Điều đó không có nghĩa là các khóa có thể thay đổi không thể hoạt động. Một khóa có thể thay đổi sẽ hoạt động nếu các đột biến trên khóa không ảnh hưởng đến mã băm hoặc nếu các phím đơn giản không bị đột biến miễn là hashMap được sử dụng.

  2. Làm cách nào để thay đổi khóa không thay đổi?Vâng, chính bản thân nó có thể không thay đổi được, nhưng ánh xạ khóa-giá trị có thể thay đổi trong logic nghiệp vụ. Nếu bạn tạo bản đồ, sử dụng địa chỉ làm khóa, bạn dựa vào thực tế là địa chỉ của cửa hàng sẽ không thay đổi. Nếu địa chỉ của cửa hàng thay đổi, bạn sẽ không tìm thấy địa chỉ đó trong Bản đồ bằng địa chỉ mới của cửa hàng làm khóa. Người quản lý của bạn có điểm hợp lệ.

  3. tốc độ tìm khóa trong Bản đồ phụ thuộc rất nhiều vào tốc độ tính mã băm. Đối với chuỗi, phép tính này lặp lại trên tất cả các ký tự trong chuỗi. Nếu bạn sử dụng các chuỗi dài làm khóa và có nhiều quyền truy cập Bản đồ, điều này có thể dẫn đến cổ chai hiệu suất. Việc thực thi chuỗi Java do đó lưu trữ giá trị băm, vì vậy nó sẽ chỉ được tính một lần. Tuy nhiên, bạn sẽ chỉ tránh tính toán mã băm nếu bạn sử dụng cùng một trường hợp String một lần nữa (các phiên bản mới sẽ không có giá trị được lưu trong bộ nhớ cache). Bạn có thể intern() các phím bạn sử dụng, nhưng hãy xem xét điều này chỉ khi nó có thể được hiển thị rằng có thực sự là một cổ chai hiệu suất, như String thực hiện đi kèm với chi phí riêng của mình.

  4. như được giải thích trong 1: các khóa có thể thay đổi có thể hoạt động nếu mã băm của chúng không bị ảnh hưởng bởi đột biến. ví dụ. sử dụng một Khách hàng làm khóa, trong đó hashCode() chỉ dựa trên tên của khách hàng, sau đó thực hiện Khách hàng chỉ không cho phép thay đổi tên, nhưng cho phép các giá trị khác thay đổi, là một khóa đáng tin cậy.

+0

Tuyệt vời. Cảm ơn bowmore. – rickygrimes

+0

Mã băm của chuỗi đã được lưu trong bộ nhớ cache ... – assylias

+0

@assylias đã chỉnh sửa câu trả lời của tôi – bowmore

0

Nói chung, các khóa trong hashmaps sẽ không thay đổi.

Xem this

Lưu ý: cẩn thận phải được thực hiện nếu đối tượng có thể thay đổi được sử dụng như bản đồ phím. Hành vi của bản đồ không được xác định nếu giá trị của một đối tượng được thay đổi theo cách ảnh hưởng đến bằng so sánh trong khi đối tượng là một chìa khóa trong bản đồ.

Hàm băm của khóa của bạn được tính một lần trong khi chèn, hashmap sẽ lưu nó và nó sẽ không tự động cập nhật khi khóa của bạn được sửa đổi. Đó là lý do tại sao có một giả định rằng các phím sẽ không thay đổi được.

Tùy chọn của bạn là: 1. Không sử dụng các đối tượng có thể thay đổi làm khóa. Cố gắng tìm một phím khác hoặc sử dụng một phần bất biến của cựu của bạn đối tượng chủ chốt 2. Không thay đổi đối tượng có thể thay đổi của bạn trong khi chúng được sử dụng như phím

+0

Bạn có thể trả lời từng câu hỏi tôi đã hỏi ở trên không? Điều đó sẽ thực sự hữu ích. – rickygrimes

1
  1. Có thể có một vấn đề nếu bạn sửa đổi bạn có thể thay đổi đối tượng được sử dụng làm chìa khóa. map.containsKey(modifiedKey) có thể trả về false ngay cả khi khóa ở đó, bạn sẽ phải lặp qua các phím để tìm nó. Vì vậy, hãy thử sử dụng bất biến hoặc không sửa đổi trong khi đó là chìa khóa.

  2. Đối tượng không thay đổi không bao giờ thay đổi.Có những phương pháp giống như họ đang thay đổi đối tượng nhưng thay vào đó một bản sao mới được tạo ra. Ví dụ:

    Chuỗi a = "A";

    Chuỗi b = a.substring (0); // chuỗi con tạo ra một bản sao của "A" với một không được sửa đổi ở tất cả.

    a = a + b; // a + b tạo một chuỗi mới "AA" mà không sửa đổi các chuỗi trước đó.

  3. này có thể giúp caching-hashes-in-java-collections cũng này là rất tốt why-are-immutable-objects-in-hashmaps-so-effective

  4. String có đã thực hiện equalshashcode, không cần phải phát minh ra lớp khác để sử dụng thay vì nó trừ khi bạn hoàn toàn chắc chắn bạn cần đến nó.

    Như đã đề cập ở điểm 1. bạn có thể làm điều đó nhưng bạn sẽ phải cẩn thận và không sửa đổi các đối tượng có thể thay đổi của bạn. Đó không phải là một thực hành rất tốt mặc dù.

+0

Cảm ơn bạn rất nhiều vì đã liên kết - http://stackoverflow.com/questions/10342859/why-are-immutable-objects-in-hashmaps-so-effective. Nó trả lời tất cả những câu hỏi tôi có. – rickygrimes

+0

Chắc chắn tôi có thể. Nhưng tôi thành thật vẫn chưa rõ ràng với điểm số 2. Ngoài ra, vui lòng sửa đổi câu trả lời của bạn cho điểm số 4 của tôi. Tôi đang đề cập đến những vật không thay đổi được. – rickygrimes

1
  1. phím bất di bất dịch không thể thay đổi. Do đó, mã băm được tính tại thời điểm chèn không thể thay đổi. Vì vậy, khi bạn cố gắng để có được một yếu tố từ bản đồ, hashcode của đối tượng để có được được tính chống lại hashcodes biết. Nếu khóa của bạn đã thay đổi từ bên ngoài (nó có thể thay đổi được), mã băm của khóa mới sẽ khác với mã băm mà bạn đã chèn vào.

  2. Hãy xem ví dụ. for (24)

    public class RandomPair { 
        int p; 
        int q; 
    
        public RandomPair(int p, int q) { 
         this.p = p; 
         this.q = q; 
        } 
        @Override 
        public int hashCode() { 
         return 31 * p + q; 
        } 
    
        @Override 
        public boolean equals(Object obj) { 
         if (!(obj instanceof RandomPair)) { 
          return false; 
         } 
         if (obj == this) { 
          return true; 
         } 
    
         RandomPair other = (RandomPair) obj; 
         if (p != other.p) 
          return false; 
         if (q != other.q) 
          return false; 
         return true; 
        } 
    
        public static void main(String[] args) { 
         RandomPair pair = new RandomPair(10, 10); 
         Map<RandomPair, Integer> map = new HashMap<RandomPair, Integer>(); 
    
         map.put(pair, 1); 
         System.out.println(map.get(pair)); //returns 1 
    
         //someone somewhere just changed the value of pair 
         pair.p = 20; 
         //the object was the same, someone somewhere just changed value of pair and now you can't 
         //find it in the map 
         System.out.println(map.get(pair)); 
    
         //had you made p and q final, this sort of modification wouldn't be possible 
         //Strings are immutable and thus prevent this modification 
        } 
    } 
    
  3. Kể từ chuỗi là không thay đổi, giá trị hashcode một lần tính toán có thể được tái sử dụng lại. Mã băm được tính toán một cách lười biếng. tức là trên cuộc gọi đầu tiên đến hashcode và sau đó giá trị của hashcode được lưu trữ.

+0

Cảm ơn bsd. Bạn cũng có thể thêm một vài dòng về những gì người quản lý của tôi đang nói đến không? Chúng tôi đang nhận dữ liệu từ khách hàng dưới dạng chuỗi JSON. Vì vậy, họ sẽ thay đổi địa chỉ cho chắc chắn. Tôi muốn hiểu làm thế nào mà có thể ảnh hưởng đến logic tôi có? – rickygrimes

+0

Không giữ địa chỉ một phần của tính toán 'hashcode' và' equals'.Các trường là hằng số, có thể là số nhận dạng 10 chữ số duy nhất của chúng (có thể là SSN) phải là một phần của 'hashcode'. Tên có thể thay đổi, địa chỉ có thể thay đổi. Nếu bạn có thể tìm hiểu những gì đã thay đổi trong đối tượng 'Person', bạn có thể xóa mục đó khỏi bản đồ và chèn lại với các giá trị mới. – bsd

0
  1. Một khóa có thể thay đổi hoặc đối tượng có nghĩa là bạn có thể sửa đổi các đối tượng [bởi thay đổi tôi có nghĩa là bạn có thể thay đổi giá trị đại diện bởi đối tượng]. Điều này sẽ ảnh hưởng đến dung lượng lưu trữ của nó trong HashMap nếu logic được viết bằng bằng và hashcode sử dụng các giá trị có thể sửa đổi này.

  2. Tính bất biến lý tưởng có nghĩa là đối tượng khi khởi tạo không thể thay đổi sau đó. Nhưng nếu chúng ta nói cụ thể theo điều khoản của HashMap thì tất cả các biến được sử dụng bên trong bằng và phương thức hashcode, nếu chúng có thể được sửa đổi thì đối tượng đó không nên được sử dụng làm khóa khác nó có thể được sử dụng làm khóa [nhưng vẫn không được khuyến nghị].

  3. Không chỉ khoảng String, bất kỳ cách nào cũng sẽ lưu lại mã băm của nó. Hashcode được tạo ra một lần nữa và một lần nữa cho hầu như tất cả các đối tượng [Có một lý do tại sao tôi nói gần như là trong một số trường hợp nó có thể thay đổi]. Hashcode được lưu trữ trong tiêu đề Object.

  4. Nếu bạn muốn sử dụng đối tượng có thể thay đổi làm khóa thì bạn nên truy cập IdentityHashMap. Chỉ cần đọc về chúng, chúng có thể hữu ích trong những trường hợp như vậy.

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