HashMap và int làm khóa


104

Tôi đang cố gắng xây dựng một HashMap sẽ có số nguyên là khóa và đối tượng là giá trị.

Cú pháp của tôi là:

HashMap<int, myObject> myMap = new HashMap<int, myObject>();

Tuy nhiên, lỗi được trả về là - Lỗi cú pháp trên mã thông báo "int", Thứ nguyên được mong đợi sau mã thông báo này - Tôi không hiểu tại sao tôi nên thêm một thứ nguyên (tức là: tạo int vào một mảng) vì tôi chỉ cần lưu trữ một chữ số làm chìa khóa.

Tôi có thể làm gì?

Cảm ơn trước! :)


14
HashMapkhông xử lý nguyên thủy, chỉ đối tượng.
Menno

Câu hỏi SO có liên quan , nhưng intlà giá trị, không phải là chìa khóa.
cyroxx

5
Sử dụng Integerthay thế.
Hot Licks

Sẽ tốt hơn nếu autobox int thành Integer hay chỉ lưu trữ dữ liệu dưới dạng Chuỗi, điều này thoải mái hơn?
Marcin Erbel

Câu trả lời:


25

Bạn không thể sử dụng nguyên thủy vì HashMap sử dụng đối tượng bên trong cho khóa. Vì vậy, bạn chỉ có thể sử dụng một đối tượng kế thừa từ Object (đó là bất kỳ đối tượng nào).

Đó là hàm put () trong HashMap và như bạn có thể thấy, nó sử dụng Object cho K:

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key);
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

Biểu thức "k = e.key" nên làm cho nó rõ ràng.

Tôi khuyên bạn nên sử dụng một trình bao bọc như Số nguyên và hộp tự động.


137

Sử dụng Integerthay thế.

HashMap<Integer, MyObject> myMap = new HashMap<Integer, MyObject>();

Java sẽ tự động đóng hộp intcác giá trị nguyên thủy của bạn vào Integercác đối tượng.

Đọc thêm về tính năng tự động đóng hộp từ các tài liệu Java của Oracle.


10
Ông cũng không nên đặt tên cho một lớp họcmyObject
Adam Gent

@AdamGent Đúng. Tất cả các tên lớp phải bắt đầu bằng viết hoa, tôi đã sửa mã đề xuất.
gaborsch

3
Tôi biết bạn biết :) Tôi chỉ muốn đảm bảo rằng OP biết / học. Đối với tất cả những gì tôi biết, anh ta có thể đã đặt một tên biến trong tham số kiểu.
Adam Gent

1
Chỉ cần một lưu ý nhỏ, tốt hơn là sử dụng ArrayMaphoặc SimpleArrayMaptrên Android để tiết kiệm bộ nhớ và tăng hiệu suất ( Thông tin thêm )
Noah Huppert

42

Đối với tất cả những ai viết mã Java cho thiết bị Android và kết thúc ở đây: sử dụng SparseArrayđể có hiệu suất tốt hơn;

private final SparseArray<myObject> myMap = new SparseArray<myObject>();

với điều này, bạn có thể sử dụng int thay vì Integer như;

int newPos = 3;

myMap.put(newPos, newObject);
myMap.get(newPos);

7
Hãy nhớ rằng SparseArray chậm hơn so với hashmap, nhưng bộ nhớ hiệu quả hơn. Vì vậy, không sử dụng nó trên các tập dữ liệu lớn.
TpoM6oH

SparseArray được sử dụng như thế nào để có hiệu suất tốt hơn trong khi nó chậm hơn? Mà một trong những sử dụng trong trò chơi Android của tôi
Rắn

@Snake SparseArrayNếu bạn phân bổ một loạt các int bộ nhớ và mở hộp như bạn làm với a HashMap, vm sẽ cần tạm dừng thực thi để thu gom rác sớm hơn. Điều này rất quan trọng nếu bạn đang cố gắng làm việc gì đó thường xuyên và nhanh chóng.
Jon

1
Hãy nhớ rằng độ phức tạp của việc chèn vào SparseArrayO (n) ( HashMapO (1) ). Điều quan trọng là khi số lượng phần tử lớn. Việc chèn vào đầu mảng như vậy chậm hơn nhiều.
Vladimir Petrakovich

1
@ M.kazemAkhgary Không chính xác. put()lấy O(n)(không n log n) để chèn khi bắt đầu vì nó tìm vị trí và sau đó dịch chuyển tất cả các phần tử sau. delete()bản thân nó thực sự mất O(log n), nhưng lần chèn tiếp theo hoặc lặp lại qua các phần tử sau khi xóa sẽ yêu cầu một bộ sưu tập rác O(n).
Vladimir Petrakovich


4

Lý do chính khiến HashMap không cho phép các khóa nguyên thủy là vì HashMap được thiết kế theo cách để so sánh các khóa, nó sử dụng dấu bằng () phương thức và một phương thức chỉ có thể được gọi trên một đối tượng không phải trên nguyên thủy.

Vì vậy, khi int được tự động đóng hộp thành Integer, Hashmap có thể gọi phương thức equals () trên đối tượng Integer.

Đó là lý do tại sao, bạn nên sử dụng Integer thay vì int. Ý tôi là hashmap ném một lỗi khi đặt int làm khóa (Không biết ý nghĩa của lỗi được ném ra)

Và nếu bạn nghĩ như vậy, bạn có thể làm cho hiệu suất của Bản đồ nhanh hơn bằng cách tạo một nguyên thủy làm khóa, có một thư viện tên là FastUtil chứa triển khai Bản đồ với kiểu int làm khóa.

Vì điều này, nó nhanh hơn nhiều so với Hashmap


1
Không, lý do chính của việc không cho phép các kiểu nguyên thủy là tính năng xóa kiểu trong Java, điều này biến Map<Integer, String>thành một cách hiệu quả Map<Object, Object>trong quá trình biên dịch. BTW, có IdentityHashMap sử dụng ==toán tử để kiểm tra bình đẳng, vẫn không cho phép các kiểu nguyên thủy.
Yoory N.

3

HashMap không cho phép các kiểu dữ liệu nguyên thủy làm đối số. Nó chỉ có thể chấp nhận các đối tượng

HashMap<int, myObject> myMap = new HashMap<int, myObject>();

sẽ không làm việc.

Bạn phải thay đổi khai báo thành

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

vì vậy ngay cả khi bạn làm những điều sau

myMap.put(2,myObject);

Kiểu dữ liệu nguyên thủy được tự động đóng hộp vào một đối tượng Integer.

8 (int) === boxing ===> 8 (Integer)

Bạn có thể đọc thêm về autoboxing tại đây http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html



1

sử dụng int làm Đối tượng không phải là kiểu nguyên thủy

HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();

Tôi đã viết HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); nhưng hiển thị làm cho vấn đề của tôi với> và <để hiển thị câu trả lời tốt
franki3xe

Tôi biết rất đau khi gõ nhưng tôi đã cố gắng cứu bạn ngay lập tức -1. Tôi không giống như những người khác bình luận trước khi phạt (Tôi không -1 bạn).
Adam Gent

0

Hãy sử dụng HashMap<Integer, myObject> myMap = new HashMap<Integer, myObject>();


0

Tôi không hiểu tại sao tôi nên thêm một thứ nguyên (tức là: tạo int vào một mảng) vì tôi chỉ cần lưu trữ một chữ số làm khóa.

Một mảng cũng là một Đối tượng, vì vậy HashMap<int[], MyObject> một cấu trúc hợp lệ sử dụng mảng int làm khóa.

Trình biên dịch không biết bạn muốn gì hoặc bạn cần gì, nó chỉ thấy cấu trúc ngôn ngữ gần như chính xác và cảnh báo những gì còn thiếu để nó hoàn toàn chính xác.


1
Hãy cẩn thận với điều này, giá trị băm của một mảng không liên quan đến nội dung của nó, vì vậy hai mảng có cùng nội dung có thể băm thành một giá trị khác nhau khiến nó trở thành một khóa rất kém.
john16384

0

Đối với một số người quan tâm đến một bản đồ như vậy vì bạn muốn giảm dấu vết của tự động đóng hộp trong Java của trình bao bọc hơn các kiểu nguyên thủy, tôi khuyên bạn nên sử dụng các bộ sưu tập Eclipse . Trove không được hỗ trợ nữa và tôi tin rằng nó là một thư viện khá không đáng tin cậy (mặc dù nó khá phổ biến) và không thể so sánh với các bộ sưu tập Eclipse .

import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap;

public class Check {
    public static void main(String[] args) {
        IntObjectHashMap map = new IntObjectHashMap();

        map.put(5,"It works");
        map.put(6,"without");
        map.put(7,"boxing!");

        System.out.println(map.get(5));
        System.out.println(map.get(6));
        System.out.println(map.get(7));
    }
}

Trong ví dụ này ở trên IntObjectHashMap .

Khi bạn cần ánh xạ đối tượng int-> , hãy xem xét việc sử dụng YourObjectType[]mảng hoặc List<YourObjectType>và truy cập các giá trị theo chỉ mục, vì bản chất, bản đồ là một mảng kết hợp với kiểu int làm chỉ mục.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.