2013-05-30 22 views
20

Nếu khóa của một HashMap là một mảng chuỗi:một mảng java có thể được sử dụng như một HashMap chính

HashMap<String[], String> pathMap; 

Bạn có thể truy cập vào bản đồ bằng cách sử dụng một mảng chuỗi mới được tạo ra hay nó phải cùng Chuỗi [] vật?

pathMap = new HashMap<>(new String[] { "korey", "docs" }, "/home/korey/docs"); 
String path = pathMap.get(new String[] { "korey", "docs" }); 
+2

Không; mảng không ghi đè 'hashCode()'. – SLaks

+0

Liên quan chặt chẽ đến [câu hỏi tương tự về 'Set's] (http://stackoverflow.com/questions/9841934/how-to-make-a-set-of-array-in-java). – Raedwald

Trả lời

28

Nó sẽ phải là cùng một đối tượng. A HashMap so sánh các phím bằng cách sử dụng equals() và hai mảng trong Java chỉ bằng nhau nếu chúng là cùng một đối tượng.

Nếu bạn muốn bình đẳng giá trị, hãy viết lớp chứa của riêng bạn bao bọc một String[] và cung cấp ngữ nghĩa thích hợp cho equals()hashCode(). Trong trường hợp này, cách tốt nhất là làm cho vùng chứa không thay đổi được, vì việc thay đổi mã băm cho một đối tượng chạy tàn phá với các lớp chứa dựa trên hàm băm.

EDIT

Như những người khác đã chỉ ra, List<String> có ngữ nghĩa bạn dường như muốn cho một đối tượng chứa. Vì vậy, bạn có thể làm một cái gì đó như thế này:

HashMap<List<String>, String> pathMap; 

pathMap.put(
    // unmodifiable so key cannot change hash code 
    Collections.unmodifiableList(Arrays.asList("korey", "docs")), 
    "/home/korey/docs" 
); 

// later: 
String dir = pathMap.get(Arrays.asList("korey", "docs")); 
+2

Tôi nghĩ rằng nó cũng sử dụng 'hashCode()' để xác định giá trị băm của một đối tượng. – pvorb

+1

@pvorb - Thật vậy. Và hai mảng không có cùng mã băm. Tuy nhiên, đây không phải là yêu cầu đối với bất kỳ triển khai Java nào. Trong mọi trường hợp, hai tham chiếu với cùng một 'hashCode()' sau đó được so sánh bằng cách sử dụng 'equals()' để xác định xem chúng có cùng khóa hay không. –

+0

+1 để biết thêm thông tin. – pvorb

1

Mảng trong Java sử dụng Object 's hashCode() và không ghi đè lên nó (điều tương tự với equals()toString()). Vì vậy, không, bạn không thể không được sử dụng mảng dưới dạng khóa băm.

+1

Bạn _can_ sử dụng chúng như là một chìa khóa, nó sẽ chỉ sử dụng bất kỳ đối tượng nào cho hashCode của nó ... Không phải những gì anh ta muốn, nhưng không có gì ngăn cản bạn làm điều đó. – Lucas

1

Ted Hopp là đúng nó sẽ phải cùng một đối tượng

để biết thông tin xem ví dụ này

public static void main(String[] args) { 
     HashMap<String[], String> pathMap; 
     pathMap = new HashMap<String[], String>(); 
     String[] data = new String[] { "korey", "docs" }; 
     pathMap.put(data, "/home/korey/docs"); 
     String path = pathMap.get(data); 
     System.out.println(path); 
    } 
} 

Khi bạn chạy trên nó sẽ in "tài liệu".

+0

Nó sẽ in "/ home/korey/docs" như mong đợi –

6

Không, nhưng bạn có thể sử dụng List<String> sẽ hoạt động như bạn mong đợi!

+7

Điều này làm việc với báo trước. Nếu bạn định sử dụng 'List ' làm khóa trong bộ sưu tập dựa trên băm, danh sách sẽ không thể sửa đổi được. Nếu mã băm cho một đối tượng thay đổi trong khi đối tượng đang được sử dụng làm khóa trong bộ sưu tập dựa trên băm, thì bộ sưu tập thường bị hỏng. –

+0

'Danh sách' là một giao diện và không đảm bảo rằng việc triển khai đúng cách ghi đè bằng và hashCode –

+1

@SteveKuo - Có. Tài liệu cho 'List' yêu cầu bất kỳ sự triển khai nào để sử dụng một ngữ nghĩa cụ thể cho' equals() 'và' hashCode() '. Các ngữ nghĩa bắt buộc phù hợp với những gì OP có vẻ muốn. –

1

Bạn không thể sử dụng đồng bằng Java Array làm khóa trong HashMap. (Vâng bạn có thể, nhưng nó sẽ không hoạt động như mong đợi.)

Nhưng bạn có thể viết một lớp bao bọc có tham chiếu đến mảng và cũng ghi đè hashCode()equals().

+0

Không cần viết một lớp trình bao bọc mảng mới, một lớp đã tồn tại - 'ArrayList' –

+0

@SteveKuo Đúng vậy. Nhưng có lẽ bạn muốn viết của riêng bạn, vì 'ArrayList' là mutable và mảng bên dưới có thể được thay thế nội bộ mà không cần bạn nhận thấy nó. – pvorb

+1

@pvorb - Người ta luôn có thể sử dụng 'Collections.unmodifiableList (someList)' để biến 'List' thành một đối tượng bất biến. –

0

Trong hầu hết các trường hợp, trong đó các chuỗi bên trong mảng của bạn không phải là bệnh lý và không bao gồm dấu phẩy theo sau dấu cách, bạn có thể sử dụng Arrays.toString() làm khóa duy nhất. tức là Map của bạn sẽ là Map<String, T>. Và get/put cho một mảng myKeys[] sẽ là

T t = myMap.get(Arrays.toString(myKeys)); 

myMap.put(Arrays.toString(myKeys), myT); 

Rõ ràng bạn có thể đặt một số mã bao bọc nếu muốn.

Một hiệu ứng phụ tốt đẹp là chìa khóa của bạn hiện không thể thay đổi. Tất nhiên, bạn thay đổi mảng myKeys và sau đó thử một số get(), bạn sẽ không tìm thấy nó.

Hashing of Strings được tối ưu hóa cao.Vì vậy, của tôi đoán là giải pháp này, mặc dù nó cảm thấy hơi chậm và kludgy, sẽ nhanh hơn và hiệu quả hơn bộ nhớ (phân bổ ít đối tượng hơn) so với giải pháp @Ted Hopp sử dụng Danh sách bất biến. Chỉ cần suy nghĩ về việc liệu Arrays.toString() là duy nhất cho các phím của bạn. Nếu không, hoặc nếu có bất kỳ nghi ngờ nào, (ví dụ: String [] xuất phát từ đầu vào của người dùng), hãy sử dụng Danh sách.

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