HashMap dan int sebagai kuncinya


104

Saya mencoba membangun HashMap yang akan memiliki integer sebagai kunci dan objek sebagai nilai.

Sintaks saya adalah:

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

Namun, kesalahan yang dikembalikan adalah - Kesalahan sintaks pada token "int", Dimensi yang diharapkan setelah token ini - Saya tidak mengerti mengapa saya harus menambahkan dimensi (yaitu: membuat int menjadi array) karena saya hanya perlu menyimpan satu digit sebagai kunci.

Apa yang dapat saya lakukan?

Terima kasih sebelumnya! :)


14
HashMaptidak menangani primitif, hanya benda.
Menno

Terkait pertanyaan SO , tetapi dengan intmenjadi nilai, bukan kuncinya.
cyroxx

5
Gunakan Integersebagai gantinya.
Hot Licks

Apakah lebih baik menggunakan autobox ke Integer atau hanya menyimpan data sebagai String, mana yang lebih nyaman?
Marcin Erbel

Jawaban:


25

Anda tidak dapat menggunakan primitif karena HashMap menggunakan objek secara internal untuk kuncinya. Jadi Anda hanya dapat menggunakan objek yang mewarisi dari Objek (yaitu objek apa pun).

Itu adalah fungsi put () di HashMap dan seperti yang Anda lihat, ini menggunakan Object untuk 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;
}

Ekspresi "k = e.key" harus membuatnya jelas.

Saya menyarankan untuk menggunakan pembungkus seperti Integer dan autoboxing.


137

Gunakan Integersebagai gantinya.

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

Java akan secara otomatis mengoksidasi intnilai primitif Anda ke Integerobjek.

Baca lebih lanjut tentang autoboxing dari dokumentasi Oracle Java.


10
Dia juga seharusnya tidak menyebutkan sebuah kelasmyObject
Adam Gent

@Adament Benar. Semua nama kelas harus dimulai dengan huruf besar, saya mengoreksi kode yang disarankan.
gaborsch

3
Saya tahu Anda tahu :) Saya hanya ingin memastikan OP tahu / belajar. Yang saya tahu dia bisa saja meletakkan nama variabel di parameter tipe.
Adam Gent

1
Sedikit catatan singkat, lebih baik menggunakan ArrayMapatau SimpleArrayMapdi Android untuk menghemat memori dan meningkatkan kinerja ( Informasi lebih lanjut )
Noah Huppert

42

Untuk semua orang yang membuat kode Java untuk perangkat Android dan berakhir di sini: gunakan SparseArrayuntuk kinerja yang lebih baik;

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

dengan ini Anda dapat menggunakan int daripada Integer seperti;

int newPos = 3;

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

7
Ingatlah bahwa SparseArray lebih lambat daripada hashmap, tetapi lebih hemat memori. Jadi, jangan gunakan pada kumpulan data yang besar.
TpoM6oH

Bagaimana SparseArray digunakan untuk performa yang lebih baik saat lebih lambat? Yang mana yang akan digunakan dalam game android saya
Snake

@Snake SparseArrayJika Anda mengalokasikan sekumpulan memori boxing dan unboxing int seperti yang Anda lakukan dengan a HashMap, vm perlu menjeda eksekusi untuk pengumpulan sampah lebih cepat. Ini penting jika Anda mencoba melakukan sesuatu dengan sering dan cepat.
Jon

1
Ingat bahwa kompleksitas penyisipan ke dalam SparseArrayadalah O (n) ( HashMapmemiliki O (1) ). Ini penting ketika jumlah elemen banyak. Penyisipan ke awal larik semacam itu jauh lebih lambat.
Vladimir Petrakovich

1
@ M.kazemAkhgary Tidak persis. put()mengambil O(n)(bukan n log n) untuk penyisipan di awal karena ia menemukan posisi dan kemudian menggeser semua elemen berikut. delete()itu sendiri memang membutuhkan O(log n), tetapi penyisipan berikutnya atau iterasi melalui elemen setelah penghapusan akan membutuhkan pengumpulan sampah yang mengambil O(n).
Vladimir Petrakovich


4

Alasan utama dengan HashMap tidak mengizinkan primitif sebagai kunci adalah bahwa HashMap dirancang sedemikian rupa sehingga untuk membandingkan kunci, ia menggunakan metode equals () , dan metode hanya dapat dipanggil pada objek bukan pada primitif.

Jadi ketika int di-autobox ke Integer, Hashmap dapat memanggil metode equals () pada objek Integer.

Itulah mengapa, Anda harus menggunakan Integer daripada int. Maksud saya, hashmap melempar kesalahan saat meletakkan int sebagai kunci (Tidak tahu arti kesalahan yang dilemparkan)

Dan jika Anda berpikir demikian, Anda dapat membuat kinerja Map lebih cepat dengan menjadikan primitif sebagai kunci, ada pustaka bernama FastUtil yang berisi implementasi Map dengan tipe int sebagai kuncinya.

Karena itu, ini jauh lebih cepat daripada Hashmap


1
Tidak, alasan utama untuk tidak mengizinkan tipe primitif adalah penghapusan tipe di Java, yang secara efektif berubah Map<Integer, String>menjadi Map<Object, Object>selama kompilasi. BTW, ada IdentityHashMap yang menggunakan ==operator untuk pemeriksa persamaan, yang masih tidak mengizinkan tipe primitif.
Yoory N.

3

HashMap tidak mengizinkan tipe data primitif sebagai argumen. Ia hanya bisa menerima benda begitu

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

tidak akan berfungsi.

Anda harus mengubah deklarasi menjadi

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

begitu pun saat Anda melakukan hal berikut

myMap.put(2,myObject);

Tipe data primitif di-autobox ke objek Integer.

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

Anda dapat membaca lebih lanjut tentang autoboxing di sini http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html



1

gunakan int sebagai Object bukan sebagai tipe primitif

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

Saya telah menulis HashMap <Integer, MyObject> myMap = new HashMap <Integer, MyObject> (); tetapi menampilkan buat masalah saya dengan> dan <untuk menampilkan jawaban yang bagus
franki3xe

Saya tahu itu menyakitkan untuk mengetik tetapi saya berusaha menyelamatkan Anda dari segera -1. Saya tidak seperti komentar orang lain sebelum menghukum (saya tidak memberi Anda -1).
Adam Gent

0

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


0

Saya tidak mengerti mengapa saya harus menambahkan dimensi (yaitu: membuat int menjadi array) karena saya hanya perlu menyimpan digit sebagai kunci.

Array juga merupakan Objek, begitu HashMap<int[], MyObject>juga konstruksi valid yang menggunakan larik int sebagai kunci.

Compiler tidak mengetahui apa yang Anda inginkan atau butuhkan, ia hanya melihat konstruksi bahasa yang hampir benar, dan memperingatkan apa yang hilang agar benar sepenuhnya.


1
Hati-hati dengan ini, nilai hash dari sebuah array tidak terkait dengan isinya, jadi dua array dengan konten yang sama dapat di-hash ke nilai yang berbeda sehingga menjadikannya kunci yang sangat buruk.
john16384

0

Untuk seseorang yang tertarik dengan peta seperti itu karena Anda ingin mengurangi jejak autoboxing di Java dari pembungkus daripada tipe primitif, saya akan merekomendasikan untuk menggunakan koleksi Eclipse . Trove tidak lagi didukung , dan saya yakin ini adalah pustaka yang cukup tidak dapat diandalkan (meskipun ini cukup populer) dan tidak dapat dibandingkan dengan koleksi 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));
    }
}

Dalam contoh ini di atas IntObjectHashMap .

Karena Anda memerlukan int-> pemetaan objek , pertimbangkan juga penggunaan YourObjectType[]array atau List<YourObjectType>dan nilai akses berdasarkan indeks, karena map pada dasarnya adalah array asosiatif dengan tipe int sebagai indeks.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.