Mengenai pertanyaan-pertanyaan dalam seri ini, setiap orang yang mempelajari Java harus memahaminya. Tentu saja tidak masalah jika Anda hanya belajar Java untuk bersenang-senang. Jika Anda merasa telah melampaui level pemula tetapi tidak memahami masalah ini dengan baik, silakan tambahkan diri Anda ke tim pemula.
Pertanyaan 1: Apa yang saya nyatakan?
String s = "Halo dunia!";
Banyak orang telah melakukan hal ini, tapi apa sebenarnya yang kita nyatakan? Jawabannya biasanya: sebuah String dengan konten "Halo dunia!". Jawaban yang tidak jelas seperti itu sering kali menjadi sumber ketidakjelasan konsep. Jika Anda memberikan jawaban yang akurat, mungkin separuh orang akan menjawab salah.
Pernyataan ini mendeklarasikan referensi ke suatu objek, bernama "s", yang dapat menunjuk ke objek apa pun bertipe String. Saat ini, pernyataan ini menunjuk ke objek bertipe String "Halo dunia!". Inilah yang sebenarnya terjadi. Kita tidak mendeklarasikan objek String, kita hanya mendeklarasikan variabel referensi yang hanya bisa menunjuk ke objek String. Jadi, jika setelah pernyataan tadi, jika Anda menjalankan kalimat lain:
Tali tali = s;
Kami telah mendeklarasikan referensi lain yang hanya dapat menunjuk ke objek String, bernama string. Tidak ada objek kedua yang dihasilkan. String masih menunjuk ke objek asli, yaitu menunjuk ke objek yang sama dengan s.
Pertanyaan 2: Apa perbedaan antara metode "==" dan sama dengan?
Operator == khusus digunakan untuk membandingkan nilai variabel untuk kesetaraan. Hal yang lebih mudah untuk dipahami adalah:
Copy kode kodenya sebagai berikut:
ke dalam a=10;
ke dalam b=10;
Maka a==b akan benar.
Namun yang sulit dipahami adalah:
Copy kode kodenya sebagai berikut:
String a=String baru("foo");
String b=String baru("foo");
Maka a==b akan mengembalikan false.
Menurut postingan sebelumnya, variabel objek sebenarnya adalah referensi, dan nilainya menunjuk ke alamat memori tempat objek tersebut berada, bukan objek itu sendiri. Baik a maupun b menggunakan operator baru, yang berarti dua string dengan konten "foo" akan dihasilkan di memori. Karena ada "dua", keduanya secara alami terletak di alamat memori yang berbeda. Nilai a dan b sebenarnya adalah nilai dari dua alamat memori yang berbeda, jadi dengan menggunakan operator "==" maka hasilnya akan salah. Memang benar objek yang ditunjuk oleh a dan b memiliki konten "foo" dan harus "sama", tetapi operator == tidak melibatkan perbandingan konten objek.
Perbandingan isi objek persis seperti yang dilakukan metode sama dengan.
Lihatlah bagaimana metode yang sama dengan objek Object diimplementasikan:
Copy kode kodenya sebagai berikut:
boolean sama dengan(Objek o){
kembalikan ini==o;
}
Objek objek menggunakan operator == secara default. Jadi jika kelas yang Anda buat sendiri tidak mengganti metode sama dengan, maka kelas Anda akan mendapatkan hasil yang sama dengan menggunakan sama dengan dan menggunakan ==. Dapat juga dilihat bahwa metode Object yang sama tidak mencapai tujuan yang seharusnya dicapai oleh metode yang sama: untuk membandingkan apakah isi dari dua objek adalah sama. Karena jawabannya harus ditentukan oleh pencipta kelas, Object menyerahkan tugas ini kepada pencipta kelas.
Lihatlah kelas ekstrim:
Copy kode kodenya sebagai berikut:
Monster Kelas{
konten String pribadi;
...
boolean sama dengan(Objek lain){ return true;}
}
Saya mengganti metode yang sama. Implementasi ini menyebabkan perbandingan antar instance Monster selalu menghasilkan nilai true apa pun kontennya.
Jadi ketika Anda menggunakan metode sama dengan untuk menentukan apakah isi suatu objek sama, mohon jangan anggap remeh. Karena mungkin Anda berpikir mereka setara, tetapi penulis kelas ini tidak berpikir demikian, dan implementasi metode yang setara di kelas tersebut dikendalikan olehnya. Jika Anda perlu menggunakan metode sama dengan, atau menggunakan koleksi berbasis kode hash (HashSet, HashMap, HashTable), silakan periksa dokumen java untuk mengonfirmasi bagaimana logika sama dengan kelas ini diterapkan.
Pertanyaan 3: Apakah String telah berubah?
TIDAK. Karena String dirancang untuk menjadi kelas yang tidak dapat diubah, semua objeknya adalah objek yang tidak dapat diubah. Silakan lihat kode berikut:
Copy kode kodenya sebagai berikut:
String s = "Halo";
s = s + "dunia!";
Apakah target yang ditunjukkan oleh s telah berubah? Kesimpulan ini dapat dengan mudah diambil dari kesimpulan artikel pertama seri ini. Mari kita lihat apa yang terjadi. Dalam kode ini, s awalnya menunjuk ke objek String dengan konten "Halo", dan kemudian kami melakukan operasi + pada s. Apakah objek yang ditunjuk oleh s berubah? Jawabannya adalah tidak. Saat ini, s tidak lagi menunjuk ke objek asli, tetapi ke objek String lain dengan konten "Halo dunia!". Objek asli masih ada di memori, tetapi variabel referensi s tidak lagi menunjuk ke sana.
Melalui penjelasan di atas, kita dapat dengan mudah mengambil kesimpulan lain. Jika string sering dimodifikasi dengan berbagai cara, atau dimodifikasi secara tidak terduga, maka penggunaan String untuk merepresentasikan string akan menyebabkan banyak overhead memori. Karena objek String tidak dapat diubah setelah dibuat, objek String diperlukan untuk mewakili setiap string yang berbeda. Saat ini, Anda harus mempertimbangkan untuk menggunakan kelas StringBuffer, yang memungkinkan modifikasi, daripada membuat objek baru untuk setiap string yang berbeda. Apalagi perubahan kebijakan antara kedua jenis ini sangat sederhana.
Pada saat yang sama, kita juga dapat mengetahui bahwa jika Anda ingin menggunakan string dengan konten yang sama, Anda tidak perlu membuat String baru setiap saat. Misalnya, jika kita ingin menginisialisasi variabel referensi String bernama s di konstruktor dan menyetelnya ke nilai awal, kita harus melakukan ini:
Copy kode kodenya sebagai berikut:
Demo kelas publik {
String pribadi;
…
Demo publik {
s = "Nilai Awal";
}
…
}
Daripada s = new String("Nilai Awal");
Yang terakhir akan memanggil konstruktor setiap kali untuk menghasilkan objek baru, yang memiliki kinerja rendah dan konsumsi memori yang besar, dan tidak ada artinya. Karena objek String tidak dapat diubah, hanya satu objek String yang dapat digunakan untuk mewakili string dengan konten yang sama . Dengan kata lain, jika Anda memanggil konstruktor di atas beberapa kali untuk membuat beberapa target, atribut tipe String-nya akan mengarah ke target yang sama.
Kesimpulan di atas juga didasarkan pada fakta bahwa untuk konstanta string, jika isinya sama, Guangzhou Java Training percaya bahwa konstanta tersebut mewakili objek String yang sama. Memanggil konstruktor dengan kata kunci baru akan selalu membuat target baru, terlepas dari apakah kontennya sama atau tidak.
Adapun mengapa kelas String harus digambarkan sebagai kelas yang tidak dapat diubah, itu ditentukan oleh tujuannya. Faktanya, tidak hanya String, tetapi juga banyak kelas di perpustakaan kelas standar Java yang tidak dapat diubah. Saat mengembangkan suatu sistem, terkadang kita perlu mendeskripsikan kelas yang tidak dapat diubah untuk melewati serangkaian nilai terkait, yang juga merupakan perwujudan dari pemikiran yang berorientasi pada tujuan. Kelas yang tidak dapat diubah memiliki beberapa keuntungan. Misalnya, karena tujuannya hanya untuk dibaca, tidak akan ada masalah dengan akses bersamaan oleh banyak thread. Tentu saja ada juga beberapa kekurangannya, misalnya setiap situasi yang berbeda memerlukan objek untuk mewakilinya, yang dapat menimbulkan masalah fungsional. Oleh karena itu, perpustakaan kelas standar Java juga menyediakan versi variabel yaitu StringBuffer.