2009-07-27 31 views
11

Tôi muốn lưu trữ một số đối tượng nhất định trong HashMap. Vấn đề là, thông thường bạn chỉ cần sử dụng một đối tượng duy nhất làm khóa. (Bạn có thể, ví dụ, sử dụng một String.) Những gì tôi muốn làm điều đó để sử dụng nhiều đối tượng. Ví dụ, một Class và một String. Có một cách đơn giản và sạch sẽ để thực hiện điều đó?Sử dụng hai (hoặc nhiều hơn) đối tượng dưới dạng khóa HashMap

Trả lời

14

Bạn chính phải thực hiện hashCode và equals. Nếu nó là một SortedMap, nó cũng phải thực hiện các giao diện Comparable

public class MyKey implements Comparable<MyKey> 
{ 
private Integer i; 
private String s; 
public MyKey(Integer i,String s) 
{ 
this.i=i; 
this.s=s; 
} 

public Integer getI() { return i;} 
public String getS() { return s;} 

@Override 
public int hashcode() 
{ 
return i.hashcode()+31*s.hashcode(); 
} 

@Override 
public boolean equals(Object o) 
{ 
if(o==this) return true; 
if(o==null || !(o instanceof MyKey)) return false; 
MyKey cp= MyKey.class.cast(o); 
return i.equals(cp.i) && s.equals(cp.s); 
    } 

    public int compareTo(MyKey cp) 
    { 
    if(cp==this) return 0; 
    int i= i.compareTo(cp.i); 
    if(i!=0) return i; 
    return s.compareTo(cp.s); 
    } 


@Override 
    public String toString() 
     { 
     return "("+i+";"+s+")"; 
     } 

    } 

public Map<MyKey,String> map= new HashMap<MyKey,String>(); 
map.put(new MyKey(1,"Hello"),"world"); 
8

tôi có xu hướng sử dụng một danh sách

map.put(Arrays.asList(keyClass, keyString), value) 
+1

Không phải là hashcode của Array.asList cụ thể cho danh sách đó? –

+1

Không, mã băm của bất kỳ 'List' (hoặc ít nhất là bất kỳ' AbstractList', mà 'Arrays.asList' là) được xác định bởi các hashcodes của các phần tử của nó. Tôi chỉ nhìn nó vì tôi có cùng suy nghĩ. –

+2

Dễ làm, nhưng nó có nhược điểm là không ghi lại những gì thuộc danh sách. Đó là lớp học, chuỗi; hoặc chuỗi đầu tiên? hoặc tên lớp và chuỗi? –

1

Bạn có thể tạo ra một lớp người giữ có chứa các lớp và chuỗi mà bạn muốn như các phím.

public class Key { 

    public MyClass key_class; 
    public String key_string; 

    public Key(){ 
     key_class = new MyClass(); 
     key_string = ""; 
    } 

} 

Có lẽ không phải là giải pháp tốt nhất, nhưng khả năng.

+3

Bất kỳ lớp nào được sử dụng làm khóa cần ghi đè bằng() và hashCode() đúng cách. – notnoop

+2

Tôi thích cách tiếp cận, nhưng việc thêm phương thức hashcode và equals là bắt buộc đối với trường hợp sử dụng. Tôi cũng sẽ làm cho nó trở nên bất biến. –

+0

@msaeed và @Jens Schauder, cảm ơn các con trỏ. –

4

Cách dễ nhất mà tôi biết là tạo lớp bao bọc và ghi đè lên băm và bằng. Ví dụ:

public class KeyClass { 

    private String element1; 
    private String element2; 

    //boilerplate code here 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof KeyClass) { 
      return element1.equals(((KeyClass)obj).element1) && 
       element2.equals(((KeyClass)obj).element2); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return (element1 + element2).hashcode(); 
    } 
} 

HÀNH Tất nhiên, tôi sẽ khuyên bạn nên sử dụng một StringBuilder và bất cứ điều gì khác, nhưng cách này bạn đã ghi đè equals và hashCode, do đó cho phép một hash và bình đẳng kiểm tra trên nhiều phím của bạn.

Ngoài ra, tôi khuyên bạn nên làm cho các đối tượng không thay đổi (không thể chỉnh sửa) vì mục đích an toàn, nhưng đó hoàn toàn là ưu tiên.

2

Bạn có nghĩa là đối tượng sẽ được khóa bằng hai khóa hoặc đúng hơn là khóa bao gồm hai thứ.

Nếu bạn muốn trường hợp đầu tiên. Đó là, một đối tượng được keyed bởi hai phím, nói một lớp hoặc một đối tượng, bạn cần phải sử dụng hai bản đồ.

Map<Key1, value> 

Map<Key2, value> 

Trong trường hợp thứ hai bạn cần một bản đồ của bản đồ, vì vậy:

Map<Key1, Map<Key2, value>> 
0

Có một vài nơi mà mọi người đề xuất tạo lớp "Khóa" chứa những người khác, tôi hoàn toàn đồng ý. Chỉ cần nghĩ rằng tôi muốn thêm một gợi ý hữu ích.

Nếu bạn sử dụng nhật thực hoặc netbeans, chúng có một tùy chọn tốt - bạn có thể yêu cầu Eclipse tạo phương thức equals và hashcode dựa trên một hoặc nhiều thành viên. Vì vậy, bạn chỉ cần chọn các thành viên (hoặc các thành viên) bạn muốn lấy và NB tạo ra hầu hết các mã bạn cần phải viết cho bạn.

Tất nhiên khi tôi chỉ muốn truy xuất một đối tượng, tôi thường chỉ ủy quyền hàm băm và bằng phương thức cho đối tượng đó (ủy nhiệm bằng có thể có vấn đề vì nó có nghĩa là một trong các lớp "Trình giữ khóa" của bạn sẽ bằng nhau đến đối tượng đó là nó là chìa khóa, nhưng đó là khá dễ dàng cố định (và sẽ không thường ảnh hưởng đến bất cứ điều gì anyway)

nên ra khỏi đỉnh đầu của tôi:

class KeyHolder { 
    public final String key; 
    public final Object storeMe; 

    public KeyHolder(String key, Object storeMe) { 
     this.key=key; 
     this.storeMe=storeMe; 
    } 

    public equals(Object o) { 
     return (o instanceof KeyHolder && ((KeyHolder)o).key.equals(key)); 
    } 

    public hashcode() { 
     return key.hashCode(); 
    } 
} 

đó là tất cả để có nó, và nhật thực sẽ làm hai điều cuối cùng cho bạn nếu bạn yêu cầu.

Nhân tiện, tôi biết rằng tôi có các thành viên công cộng, một thành viên cuối cùng của cộng đồng chính xác giống như có một người bắt đầu - không thực sự là một ý tưởng khủng khiếp. Tôi bắt đầu sử dụng mô hình này trên các lớp tiện ích nhỏ như thế này nhiều hơn gần đây. Nếu các thành viên không phải là cuối cùng, nó sẽ tồi tệ hơn bởi vì nó sẽ giống như có một setter (Cái gì tôi cố gắng tránh những ngày này).

0

Người ta có thể giải quyết vấn đề này bằng cách sử dụng bộ sưu tập commons's commons lib's MultiKey class. Dưới đây là ví dụ đơn giản:

import org.apache.commons.collections.keyvalue.MultiKey; 

HashMap map = new HashMap(); 
MultiKey multiKey = new MultiKey(key1, key2); 

map.put(multikey,value); 

//to get 
map.get(new MultiKey(key1,key2)); 
+1

Lưu ý rằng điều này trùng lặp [Câu trả lời của Clay] (http://stackoverflow.com/a/1190244/157247), mặc dù bạn đã cung cấp một ví dụ. –

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