Sketsa 1. “Metode yang tampaknya sederhana”
Tuliskan bagaimana Anda akan menerapkan metode yang mengembalikan hasil pembagian angka a dengan angka b. Pewawancara menulis di selembar kertasint divide(int a, int b) {
}
*Saya melirik dengan tidak percaya pada selembar kertas dengan tanda tangan metode. Apa menariknya?* Saya menulis:
int divide(int a, int b) {
return a/b;
}
Apakah ada masalah dengan metode ini? *Saya menangkap orang bodoh yang sangat bodoh* Tampaknya tidak.. Berikutnya adalah pertanyaan yang wajar: Bagaimana jika b=0? *Wah, aku bisa dikeluarkan dari kantor ini jika terus seperti ini!* Oh iya, tentu saja. Di sini kita memiliki argumen bertipe int, sehingga Pengecualian Aritmatika akan dilempar. Jika argumennya bertipe float atau double, hasilnya adalah Infinity. Apa yang akan kita lakukan mengenai hal ini? Saya mulai menulis coba/tangkap
int divide(int a, int b) {
try {
return a/b;
} catch (Exception e) {
e.printStackTrace();
return ... // ??? what the hack?
}
}
*Saya dapat kembali dan membekukan: sesuatu perlu dikembalikan jika terjadi kesalahan. Namun bagaimana “sesuatu” ini bisa dibedakan dari hasil perhitungannya?* Apa yang akan kita kembalikan? Hm... Saya akan mengubah jenis variabel pengembalian menjadi Integer dan jika ada pengecualian saya akan mengembalikan nol. Bayangkan kita tidak bisa mengubah tipenya. Bisakah kita keluar? Mungkin kita bisa melakukan hal lain dengan pengecualian? *Ini dia* Kita juga bisa meneruskannya ke metode panggilan! Benar. Seperti apa tampilannya?
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();
}
}
Apakah pengecualian itu perlu ditangani? Ya, karena kami meneruskannya secara eksplisit dari metode pembagian. (*Saya salah di sini! Berikut ini adalah pertanyaan-pertanyaan yang mengarahkan pewawancara untuk sampai pada jawaban yang benar*) Dan Pengecualian Aritmatika - jenis pengecualian apa - dicentang atau tidak? Ini adalah pengecualian Runtime, yang berarti tidak dicentang. *Inilah pertanyaan mematikannya* Jadi ternyata, menurut kata-kata Anda, jika kita menentukan throw Arithmetic Exception di tanda tangan metode, maka itu menjadi pengecualian yang dicentang? *Ugh!* Mungkin... tidak. Ya, sudah hilang. Jika kami menunjukkan lemparan /pengecualian yang tidak dicentang/ di tanda tangan, kami hanya memperingatkan bahwa metode tersebut dapat memunculkan pengecualian, tetapi tidak perlu menanganinya dalam metode pemanggilan. Itu sudah beres. Adakah hal lain yang bisa kita lakukan untuk menghindari kesalahan? *Setelah berpikir beberapa lama* Ya, kita juga dapat memeriksa apakah (b==0). Dan lakukan beberapa logika. Benar. Jadi kita bisa melakukan 3 cara:
- coba tangkap
- throws – meneruskan ke metode pemanggilan
- pemeriksaan argumen
divide
menurut Anda metode mana yang lebih disukai? Saya akan memilih untuk meneruskan pengecualian ke metode panggilan, karena... dalam metode pembagian tidak jelas bagaimana memproses pengecualian ini dan jenis hasil apa int
yang akan dikembalikan jika terjadi kesalahan. Dan dalam metode pemanggilan, saya akan menggunakan argumen b untuk memeriksa apakah sama dengan nol. Tampaknya jawaban ini memuaskan orang yang diwawancarai, tetapi sejujurnya, saya tidak yakin jawaban ini jelas))
Sketsa 2. “Siapa yang lebih cepat?”
Setelah pertanyaan standar, apa perbedaan ArrayList dari LinkedList, muncul ini: Apa yang akan terjadi lebih cepat - memasukkan elemen ke tengahArrayList
atau ke tengah LinkedList
? *Di sini saya melompat, saya ingat bahwa di mana pun saya membaca sesuatu seperti “gunakan LinkedList
untuk menyisipkan atau menghapus elemen di tengah daftar.” Di rumah saya bahkan mengecek ulang kuliah JavaRush, ada ungkapan: “jika Anda akan menyisipkan (atau menghapus) banyak elemen di tengah-tengah koleksi, lebih baik Anda menggunakan LinkedList
. Dalam semua kasus lainnya - ArrayList
.” Dijawab otomatis* Akan lebih cepat dengan LinkedList
. Tolong jelaskan
- Untuk menyisipkan elemen di tengah
ArrayList
, kita mencari elemen dalam daftar dalam waktu konstan, lalu menghitung ulang indeks elemen di sebelah kanan elemen yang disisipkan, dalam waktu linier. - Untuk
LinkedList
.. Pertama-tama kita mencapai bagian tengah dalam waktu linier dan kemudian memasukkan elemen dalam waktu konstan, mengubah tautan untuk elemen tetangga.
LinkedList
lebih cepat? Ternyata saat kita memasukkannya ke paruh pertama daftar. Misalnya, jika Anda memasukkannya di awal, Anda ArrayList
harus menghitung ulang semua indeks hingga bagian paling ekor, tetapi Anda LinkedList
hanya perlu mengubah referensi elemen pertama. Moral: jangan percaya secara harfiah semua yang tertulis, bahkan di JavaRush!)
Sketsa 3. “Di manakah kita tanpa persamaan dan kode hash!”
Percakapan tentang sama dengan dan kode hash sangat panjang - bagaimana cara menimpanya, apa implementasinyaObject
, apa yang terjadi di balik terpal, kapan sebuah elemen dimasukkan ke dalam HashMap
, dll. Saya hanya akan mengutip beberapa poin yang menurut saya menarik* Bayangkan kita telah membuat sebuah kelas
public class A {
int id;
public A(int id) {
this.id = id;
}
}
Dan mereka tidak menimpa equals
dan hashcode
. Jelaskan apa yang akan terjadi ketika kode dijalankan
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*Ada baiknya sebelum wawancara saya secara khusus menghabiskan beberapa hari untuk memahami algoritme dasar, kompleksitasnya, dan struktur datanya - ini sangat membantu, terima kasih CS50!*
-
Buat dua instance kelas A
-
Kami membuat peta kosong, yang secara default memiliki 16 keranjang. Kuncinya adalah objek kelas A, di mana metode
equals
dan tidak ditimpahashcode
. -
Taruh
a1
di peta. Untuk melakukan ini, pertama-tama kita menghitung hashnyaa1
.Hashnya akan sama dengan apa?
Alamat sel di memori merupakan implementasi metode dari suatu kelas
Object
-
Berdasarkan hash, kami menghitung indeks keranjang.
Bagaimana cara menghitungnya?
*Sayangnya, saya tidak memberikan jawaban yang jelas di sini. Anda memiliki nomor yang panjang - sebuah hash, dan ada 16 keranjang - bagaimana cara menentukan indeks sehingga objek dengan hash berbeda didistribusikan secara merata ke seluruh keranjang? Saya dapat membayangkan indeks dihitung seperti ini:
int index = hash % buckets.length
Sudah di rumah saya melihat bahwa implementasi asli dalam kode sumber sedikit berbeda:
static int indexFor(int h, int length) { return h & (length - 1); }
-
Kami memeriksa bahwa tidak ada tabrakan dan memasukkan a1.
-
Mari beralih ke metodenya
get
. Instance a1 dan a2 dijamin memiliki perbedaanhash
(alamat berbeda di memori), jadi kami tidak akan menemukan apa pun untuk kunci iniBagaimana jika kita mendefinisikan ulang hanya
hashcode
di kelas A dan mencoba memasukkan ke dalam peta hash terlebih dahulu sepasang dengan kunci a1, dan kemudian dengan a2?Kemudian pertama-tama kita akan menemukan keranjang yang diinginkan
hashcode
- operasi ini akan dilakukan dengan benar. Selanjutnya, mari kita mulai menelusuri objek-objekEntry
di LinkedList yang dilampirkan ke keranjang dan membandingkan kuncinya denganequals
. Karenaequals
tidak ditimpa, maka implementasi dasar diambil dari kelasObject
- perbandingan dengan referensi. a1 dan a2 dijamin memiliki link yang berbeda, jadi kita akan “kehilangan” elemen a1 yang disisipkan, dan a2 akan ditempatkan di LinkedList sebagai node baru.Apa kesimpulannya? Apakah mungkin untuk menggunakannya sebagai kunci dalam
HashMap
suatu objek dengan non-overrideequalshashcode
?Tidak Anda tidak bisa.
Sketsa 4. “Ayo kita hancurkan dengan sengaja!”
Setelah pertanyaan tentang Kesalahan dan Pengecualian, pertanyaan berikut diikuti: Tulis contoh sederhana di mana suatu fungsi akan menampilkan StackOverflow. *Kemudian saya ingat bagaimana kesalahan ini mengganggu saya ketika saya mencoba menulis beberapa fungsi rekursif* Ini mungkin akan terjadi dalam kasus panggilan rekursif, jika kondisi untuk keluar dari rekursi tidak ditentukan dengan benar. *Lalu saya mulai sedikit pandai, akhirnya pewawancara membantu, semuanya menjadi sederhana*void sof() {
sof();
}
Apa bedanya kesalahan ini dengan OutOfMemory
? *Saya tidak menjawab di sini, baru kemudian saya menyadari bahwa ini adalah pertanyaan tentang pengetahuan Stack
memori Heap
Java (panggilan dan referensi ke objek disimpan di Stack, dan objek itu sendiri disimpan di memori Heap). Oleh karena itu, StackOverflow dibuang ketika tidak ada lagi ruang di Stack
memori untuk pemanggilan metode berikutnya, dan OutOfMemory
ruang untuk objek telah habis di Heap
memori*
Inilah momen-momen wawancara yang saya ingat. Pada akhirnya, saya diterima untuk magang, jadi saya memiliki 2,5 bulan pelatihan di depan saya dan, jika semuanya berjalan dengan baik, pekerjaan di perusahaan) Jika ada minat, saya bisa menulis artikel lain, kali ini lebih kecil, dengan analisis masalah sederhana namun ilustratif yang diberikan kepada saya saat diwawancarai di perusahaan lain. Sekian dari saya, semoga artikel ini dapat membantu seseorang memperdalam atau mengorganisasikan ilmunya. Selamat belajar semuanya!
GO TO FULL VERSION