Lakaran 1. "Kaedah yang kelihatan mudah"
Tulis bagaimana anda akan melaksanakan kaedah yang mengembalikan hasil pembahagian nombor a dengan nombor b. Penemuduga menulis pada sehelai kertasint divide(int a, int b) {
}
*Saya mengerling tidak percaya pada sekeping kertas dengan tandatangan kaedah. Apa tangkapannya?* Saya menulis:
int divide(int a, int b) {
return a/b;
}
Adakah terdapat sebarang masalah dengan kaedah ini? *Saya menangkap orang bodoh yang benar-benar bodoh* Nampaknya tidak.. Seterusnya datang soalan yang sah: Bagaimana jika b=0? *Wah, saya akan dihalau dari pejabat ini jika saya terus begini!* Oh ya, sudah tentu. Di sini kita mempunyai hujah jenis int, jadi Pengecualian Aritmetik akan dilemparkan. Jika argumen adalah jenis apungan atau berganda, hasilnya ialah Infinity. Apa yang akan kita lakukan mengenai perkara ini? Saya mula menulis cuba/tangkap
int divide(int a, int b) {
try {
return a/b;
} catch (Exception e) {
e.printStackTrace();
return ... // ??? what the hack?
}
}
*Saya boleh kembali dan membekukan: sesuatu perlu dikembalikan sekiranya berlaku ralat. Tetapi bagaimanakah “sesuatu” ini boleh dibezakan daripada hasil pengiraan?* Apakah yang akan kita kembalikan? Hm... Saya akan menukar jenis pembolehubah pulangan kepada Integer dan sekiranya berlaku pengecualian, saya akan mengembalikan null. Mari kita bayangkan bahawa kita tidak boleh menukar jenis. Bolehkah kita keluar? Mungkin kita boleh melakukan sesuatu yang lain dengan pengecualian? *Ini dia datang* Kami juga boleh memajukannya kepada kaedah panggilan! Betul. Apakah rupanya?
int divide(int a, int b) throws ArithmeticException{
return a/b;
}
void callDivide(int a, int b) {
try {
divide(a, b);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
Adakah perlu untuk mengendalikan pengecualian? Ya, kerana kami memajukannya secara eksplisit daripada kaedah bahagi. (*Saya tersilap di sini! Apa yang berikut ialah soalan utama daripada penemuduga untuk mendapatkan jawapan yang betul*) Dan Pengecualian Aritmetik - apakah jenis pengecualian itu - ditandakan atau dinyahtanda? Ini adalah pengecualian Runtime, yang bermaksud tidak ditanda. *Ini adalah soalan pembunuh* Jadi ternyata, dalam kata-kata anda, jika kami menyatakan lontaran Pengecualian Aritmetik dalam tandatangan kaedah, maka ia menjadi pengecualian yang diperiksa? *Ugh!* Mungkin... tidak. Ya, tidak. Jika kami menunjukkan lontaran /pengecualian tidak ditanda/ dalam tandatangan, kami hanya memberi amaran bahawa kaedah itu boleh membuang pengecualian, tetapi tidak perlu mengendalikannya dalam kaedah panggilan. Itu sudah diselesaikan. Adakah terdapat apa-apa lagi yang boleh kita lakukan untuk mengelakkan kesilapan? *Setelah berfikir* Ya, kami juga boleh menyemak sama ada (b==0). Dan lakukan beberapa logik. Betul. Jadi kita boleh pergi 3 cara:
- cuba tangkap
- lontaran – memajukan kepada kaedah panggilan
- penyemakan hujah
divide
kaedah manakah yang anda fikir lebih baik? Saya akan memilih untuk memajukan pengecualian kepada kaedah panggilan, kerana... dalam kaedah bahagi tidak jelas cara memproses pengecualian ini dan jenis hasil int
yang akan dikembalikan sekiranya berlaku ralat. Dan dalam kaedah panggilan, saya akan menggunakan hujah b untuk menyemak sama ada ia sama dengan sifar. Nampaknya jawapan ini memuaskan hati orang yang ditemu duga, tetapi sejujurnya, saya tidak pasti bahawa jawapan ini tidak jelas))
Lakaran 2. “Siapa yang lebih pantas?”
Selepas soalan standard, bagaimana ArrayList berbeza daripada LinkedList, datang ini: Apa yang akan berlaku lebih cepat - memasukkan elemen ke tengahArrayList
atau tengah LinkedList
? *Di sini saya melompat, saya teringat bahawa di mana-mana sahaja saya membaca sesuatu seperti "gunakan LinkedList
untuk memasukkan atau mengalih keluar elemen di tengah senarai." Di rumah saya juga menyemak semula kuliah JavaRush, terdapat frasa: "jika anda akan memasukkan (atau memadam) banyak elemen ke tengah-tengah koleksi, maka lebih baik anda menggunakan LinkedList
. Dalam semua kes lain - ArrayList
.” Dijawab secara automatik* Ia akan menjadi lebih pantas dengan LinkedList
. Tolong jelaskan
- Untuk memasukkan elemen di tengah
ArrayList
, kami mencari elemen dalam senarai dalam masa malar, dan kemudian mengira semula indeks elemen di sebelah kanan yang disisipkan, dalam masa linear. - Untuk
LinkedList
.. Kami mula-mula sampai ke tengah dalam masa linear dan kemudian memasukkan elemen dalam masa malar, menukar pautan untuk elemen jiran.
LinkedList
lebih cepat? Ternyata apabila kita memasukkannya ke dalam separuh pertama senarai. Sebagai contoh, jika anda memasukkannya pada awal-awal lagi, anda ArrayList
perlu mengira semula semua indeks sehingga bahagian paling belakang, tetapi anda LinkedList
hanya perlu menukar rujukan elemen pertama. Moral: jangan percaya secara literal semua yang ditulis, walaupun dalam JavaRush!)
Lakaran 3. "Di mana kita akan berada tanpa persamaan dan kod cincang!"
Perbualan tentang equals dan kod cincang adalah sangat panjang - cara mengatasinya, pelaksanaan dalamObject
, perkara yang berlaku di bawah hud, apabila elemen dimasukkan ke dalam HashMap
, dsb. Saya hanya akan memberikan beberapa mata yang menarik pada pendapat saya* Bayangkan bahawa kita telah mencipta kelas
public class A {
int id;
public A(int id) {
this.id = id;
}
}
Dan mereka tidak mengatasi equals
dan hashcode
. Terangkan apa yang akan berlaku apabila kod tersebut dilaksanakan
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*Adalah bagus bahawa sebelum temu duga saya secara khusus meluangkan masa beberapa hari untuk memahami algoritma asas, kerumitan dan struktur datanya - ia banyak membantu, terima kasih CS50!*
-
Buat dua contoh kelas A
-
Kami mencipta peta kosong, yang secara lalai mempunyai 16 bakul. Kuncinya ialah objek kelas A, di mana kaedah
equals
dan tidak ditindihhashcode
. -
Letakkannya
a1
dalam peta. Untuk melakukan ini, kami mula-mula mengira cincanga1
.Apakah cincangan akan sama dengan?
Alamat sel dalam ingatan ialah pelaksanaan kaedah daripada kelas
Object
-
Berdasarkan cincangan, kami mengira indeks bakul.
Bagaimana kita boleh mengiranya?
*Malangnya, saya tidak memberikan jawapan yang jelas di sini. Anda mempunyai nombor yang panjang - cincangan, dan terdapat 16 baldi - bagaimana untuk menentukan indeks supaya objek dengan cincang yang berbeza diedarkan secara sama rata merentas baldi? Saya boleh membayangkan bahawa indeks dikira seperti ini:
int index = hash % buckets.length
Sudah di rumah saya melihat bahawa pelaksanaan asal dalam kod sumber sedikit berbeza:
static int indexFor(int h, int length) { return h & (length - 1); }
-
Kami menyemak bahawa tiada perlanggaran dan masukkan a1.
-
Mari kita beralih kepada kaedah
get
. Contoh a1 dan a2 dijamin mempunyai berbezahash
(alamat berbeza dalam ingatan), jadi kami tidak akan menemui apa-apa untuk kunci iniBagaimana jika kita mentakrifkannya semula hanya
hashcode
dalam kelas A dan cuba memasukkan ke dalam peta cincang dahulu pasangan dengan kunci a1, dan kemudian dengan a2?Kemudian pertama kita akan mencari bakul yang dikehendaki oleh
hashcode
- operasi ini akan dilakukan dengan betul. Seterusnya, mari kita mulakan melalui objekEntry
dalam LinkedList yang dilampirkan pada troli dan bandingkan kekunci denganequals
. Keranaequals
tidak ditindih, maka pelaksanaan asas diambil dari kelasObject
- perbandingan dengan rujukan. a1 dan a2 dijamin mempunyai pautan yang berbeza, jadi kami akan "terlepas" elemen yang dimasukkan a1, dan a2 akan diletakkan dalam LinkedList sebagai nod baharu.Apakah kesimpulannya? Adakah mungkin untuk digunakan sebagai kunci dalam
HashMap
objek dengan bukan ditindihequalshashcode
?Tidak, awak tak boleh.
Lakaran 4. "Mari kita patahkan dengan sengaja!"
Selepas soalan tentang Ralat dan Pengecualian, soalan berikut diikuti: Tulis contoh mudah di mana fungsi akan membuang StackOverflow. *Kemudian saya teringat bagaimana ralat ini melanda saya semasa saya cuba menulis beberapa fungsi rekursif* Ini mungkin akan berlaku dalam kes panggilan rekursif, jika syarat untuk keluar dari rekursi tidak dinyatakan dengan betul. *Kemudian saya mula mencuba sesuatu yang bijak, akhirnya penemuduga membantu, semuanya menjadi mudah*void sof() {
sof();
}
Bagaimanakah ralat ini berbeza daripada OutOfMemory
? *Saya tidak menjawab di sini, hanya kemudian saya menyedari bahawa ini adalah soalan tentang pengetahuan Stack
tentang Heap
memori Java (panggilan dan rujukan kepada objek disimpan dalam Stack, dan objek itu sendiri disimpan dalam memori Heap). Sehubungan itu, StackOverflow dibuang apabila tiada lagi ruang dalam Stack
ingatan untuk panggilan kaedah seterusnya, dan OutOfMemory
ruang untuk objek telah kehabisan dalam Heap
ingatan*
Inilah detik-detik temuduga yang saya ingat. Pada akhirnya, saya diterima untuk latihan, jadi saya mempunyai 2.5 bulan latihan di hadapan saya dan, jika semuanya berjalan lancar, pekerjaan di syarikat) Jika ada minat, saya boleh menulis artikel lain, kali ini lebih kecil, dengan analisis masalah yang mudah tetapi menggambarkan bahawa saya telah diberikan temu duga di syarikat lain. Sekian sahaja untuk saya, semoga artikel ini dapat membantu seseorang untuk mendalami atau menyusun ilmu. Selamat belajar semua!
GO TO FULL VERSION