Pertanyaan indexOf () Perilaku Strange Java.util.List dengan String duplikat


Saya baru saja menemukan beberapa perilaku aneh yang tidak saya harapkan dari ArrayList<String> di Jawa. Ini datang, pasti, dari pemahaman saya yang buruk tentang referensi di Jawa.

Biarkan saya tunjukkan sepotong kode ini:

List<String> myList = new ArrayList<>();

myList.add("One");
myList.add("Two");
myList.add("Two");
myList.add("Three");

for (String s : myList){
  System.out.println(myList.indexOf(s));
}

Potongan kode ini menyediakan output berikut:

0  
1  
1  
3

Bagaimana bisa? Saya telah menambahkan pada tujuan dua Strings yang mengandung karakter yang sama ("Dua"), tetapi objek itu sendiri seharusnya tidak sama. Apa yang saya salah paham di sini? Saya mengharapkan keluaran lain ini:

0
1
2
3

6
2017-08-18 13:48


asal


Jawaban:


ArrayList.indexOf () tidak menggunakan referensi persamaan untuk menemukan objek. Ini menggunakan equals() metode. Perhatikan apa yang dikatakan dokumentasi (penekanan saya):

mengembalikan indeks terendah seperti itu (o == null? get (i) == null: o.equals (dapatkan (i))), atau -1 jika tidak ada indeks semacam itu.

Dengan demikian, itu akan cocok pada string pertama yang secara logis sama.

EDIT:

AndremoniyKomentarnya benar sekali. Dalam kasus string literal, karena mereka diinternir, mereka juga akan kebetulan memiliki referensi yang sama. Jadi, 2 senar Anda "Two" sebenarnya referensi yang sama dalam kasus ini.

System.out.println("Two" == "Two"); // will return true because they are the same reference.

12
2017-08-18 13:49



Itu hanya karena indexOf mengembalikan pertama terjadinya item dalam daftar yang ada sama ke string yang diberikan. Lihat dokumentasi:

Mengembalikan indeks kemunculan pertama dari elemen yang ditentukan dalam daftar ini, atau -1 jika daftar ini tidak mengandung elemen. Lebih formal, mengembalikan indeks terendah i seperti yang (o==null ? get(i)==null : o.equals(get(i))), atau -1 jika tidak ada indeks semacam itu.


2
2017-08-18 13:50



Anda harus mencatat dua poin:

  1. kemungkinan besar Anda menggunakan String-instance yang sama, karena konstanta "Two" diinternir, itu semua kejadian literal ini akan mengacu pada contoh yang sama.
  2. List.indexOf() tidak membandingkan item dengan == (yaitu identitas-objek) tetapi menggunakan equals() - itu adalah beberapa cara yang ditentukan oleh kelas untuk membandingkan dua objek untuk kesetaraan (yang masuk akal karena jika tidak Anda tidak akan dapat menemukan sesuatu dalam daftar kecuali Anda sudah memiliki referensi untuk itu). Jadi, bahkan dua yang berbeda String-objects (misalnya dibuat oleh new String("Two")) masih akan menghasilkan output yang sama.

Untuk kelengkapan kutipan dari javadoc dari indexOf(sebagaimana telah disebutkan dalam jawaban lainnya:

mengembalikan indeks terendah seperti itu (o == null? get (i) == null:   o.equals (get (i))), atau -1 jika tidak ada indeks seperti itu.


1
2017-08-18 13:54



Java tidak memungkinkan Anda untuk membuat perbedaan antara keduanya, tetapi Anda telah menemukan perbedaan antara (dan perbedaan antara) metode dan a fungsi.

Sederhananya suatu metode dapat mengubah keadaan suatu objek. Suatu fungsi tidak akan. Jadi memanggil metode Anda add(String) akan mengubah keadaan List. Secara khusus, ia menambahkan String ke daftar. indexOf(String) Namun bukan suatu metode, itu adalah fungsi. Sekarang tentu, Java memanggil mereka metode karena ... itulah yang mereka sebut. Dan dapat dibayangkan bahwa implementasi - dapat mengubah keadaan. Tetapi kita tahu bahwa itu tidak, dengan kontrak.

Suatu fungsi, mengingat input yang sama (di mana status saat ini dari objek yang mendasari adalah bagian dari input tersebut) akan selalu mengembalikan hasil yang sama. Selalu. Itulah yang hebat tentang suatu fungsi. Anda dapat memanggil fungsi (fungsi yang benar) sebanyak yang Anda inginkan dan selalu mendapatkan hasil yang sama selama masukan Anda dan data yang mendasarinya tidak berubah.

Beberapa orang di MIT melakukannya penelitian ke dalam analisis fungsi di Java (yang untuk menghindari kebingungan, mereka memanggil "metode murni"). Akan lebih baik jika ada kerangka kerja yang memungkinkan Anda untuk menentukan bahwa metode tertentu memang fungsi (atau sebagaimana mereka menyebutnya, adalah murni) dan kemudian memiliki penganalisis memastikan Anda tidak secara tidak sengaja memperkenalkan mutasi ke kode yang dilindungi oleh anotasi itu.


0
2017-08-18 15:13