JavaRush /Blog Java /Random-MS /Kisah satu wawancara: soalan yang menarik
GuitarFactor
Tahap
Санкт-Петербург

Kisah satu wawancara: soalan yang menarik

Diterbitkan dalam kumpulan
Baru-baru ini saya berpeluang menghadiri temuduga untuk jawatan intern di salah sebuah syarikat IT yang besar. Kisah satu wawancara: soalan menarik - 1Ini adalah wawancara IT pertama saya dan, pada pendapat saya, ia ternyata menarik. Secara keseluruhan, saya telah "disoal siasat" selama lebih daripada 3 jam (ini didahului dengan kerja rumah dan ujian di pejabat pada komputer). Saya ingin memberi penghormatan kepada penemuduga, yang tidak berputus asa apabila saya menjawab soalan dengan salah, tetapi dengan bantuan soalan-soalan utamanya memaksa saya untuk memikirkannya dan datang kepada jawapan yang betul. Di bawah ini saya akan membentangkan beberapa "lakaran" - pada pendapat saya, soalan yang agak menarik, beberapa daripadanya memberi saya pemahaman yang lebih mendalam tentang aspek tertentu di Jawa. Mungkin perkara-perkara ini kelihatan jelas kepada sesetengah orang, tetapi saya fikir akan ada mereka yang akan berguna untuknya. Di bawah frasa diserlahkan dalam fon berikut: Penemubual - dalam penjelasan Suara dan pemikiran saya yang tebal - dalam huruf condong Jawapan saya - dalam fon biasa Kita sudah selesai dengan latar belakang, mari mulakan perniagaan)

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 kertas
int 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
Dalam kes ini, dividekaedah 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 intyang 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 tengah ArrayListatau tengah LinkedList? *Di sini saya melompat, saya teringat bahawa di mana-mana sahaja saya membaca sesuatu seperti "gunakan LinkedListuntuk 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
  1. 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.
  2. Untuk LinkedList.. Kami mula-mula sampai ke tengah dalam masa linear dan kemudian memasukkan elemen dalam masa malar, menukar pautan untuk elemen jiran.
Jadi ternyata, yang mana lebih cepat? Hm... Sama juga rupanya. Tetapi bilakah ia LinkedListlebih cepat? Ternyata apabila kita memasukkannya ke dalam separuh pertama senarai. Sebagai contoh, jika anda memasukkannya pada awal-awal lagi, anda ArrayListperlu mengira semula semua indeks sehingga bahagian paling belakang, tetapi anda LinkedListhanya 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 dalam Object, 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 equalsdan 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!*
  1. Buat dua contoh kelas A

  2. Kami mencipta peta kosong, yang secara lalai mempunyai 16 bakul. Kuncinya ialah objek kelas A, di mana kaedah equalsdan tidak ditindih hashcode.

  3. Letakkannya a1dalam peta. Untuk melakukan ini, kami mula-mula mengira cincang a1.

    Apakah cincangan akan sama dengan?

    Alamat sel dalam ingatan ialah pelaksanaan kaedah daripada kelasObject

  4. 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);
    }
  5. Kami menyemak bahawa tiada perlanggaran dan masukkan a1.

  6. Mari kita beralih kepada kaedah get. Contoh a1 dan a2 dijamin mempunyai berbeza hash(alamat berbeza dalam ingatan), jadi kami tidak akan menemui apa-apa untuk kunci ini

    Bagaimana jika kita mentakrifkannya semula hanya hashcodedalam 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 objek Entrydalam LinkedList yang dilampirkan pada troli dan bandingkan kekunci dengan equals. Kerana equalstidak ditindih, maka pelaksanaan asas diambil dari kelas Object- 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 HashMapobjek dengan bukan ditindih equalshashcode?

    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 Stacktentang Heapmemori 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 Stackingatan untuk panggilan kaedah seterusnya, dan OutOfMemoryruang untuk objek telah kehabisan dalam Heapingatan*
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!
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION