JavaRush /Blog Java /Random-MS /Analisis soalan dan jawapan daripada temu bual untuk pemb...

Analisis soalan dan jawapan daripada temu bual untuk pembangun Java. Bahagian 15

Diterbitkan dalam kumpulan
Hi hi! Berapa banyak yang perlu diketahui oleh pembangun Java? Anda boleh berhujah untuk masa yang lama mengenai isu ini, tetapi sebenarnya pada temuduga anda akan didorong sepenuhnya oleh teori. Walaupun dalam bidang pengetahuan yang anda tidak akan mempunyai peluang untuk digunakan dalam kerja anda. Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 1Nah, jika anda seorang pemula, pengetahuan teori anda akan dipandang serius. Memandangkan belum ada pengalaman dan pencapaian hebat, yang tinggal hanyalah untuk menyemak kekuatan pangkalan pengetahuan. Hari ini kami akan terus mengukuhkan asas ini dengan meneliti soalan temu bual yang paling popular untuk pembangun Java. Jom terbang!

Teras Java

9. Apakah perbezaan antara pengikatan statik dan dinamik di Jawa?

Saya telah menjawab soalan ini dalam artikel ini dalam soalan 18 tentang polimorfisme statik dan dinamik, saya menasihati anda untuk membacanya.

10. Adakah mungkin untuk menggunakan pembolehubah peribadi atau dilindungi dalam antara muka?

Tidak, awak tak boleh. Kerana apabila anda mengisytiharkan antara muka, pengkompil Java secara automatik menambah kata kunci awam dan abstrak sebelum kaedah antara muka dan kata kunci awam , statik dan akhir sebelum ahli data. Sebenarnya, jika anda menambah private atau protected , konflik akan timbul dan pengkompil akan mengadu tentang pengubah suai akses dengan mesej: "Pengubah suai '<pengubah suai terpilih>' tidak dibenarkan di sini." Mengapa pengkompil menambah public , statik dan muktamad pembolehubah dalam antara muka? Mari kita fikirkan:
  • awam - antara muka membolehkan klien berinteraksi dengan objek. Jika pembolehubah tidak terbuka, pelanggan tidak akan mempunyai akses kepada pembolehubah itu.
  • statik - antara muka tidak boleh dibuat (atau lebih tepat, objek mereka), jadi pembolehubah adalah statik.
  • muktamad - memandangkan antara muka digunakan untuk mencapai 100% abstraksi, pembolehubah mempunyai bentuk terakhirnya (dan tidak akan diubah).

11. Apakah Pemuat Kelas dan untuk apa ia digunakan?

Pemuat Kelas - atau Pemuat Kelas - menyediakan pemuatan kelas Java. Lebih tepat lagi, pemuatan dipastikan oleh keturunannya - pemuat kelas tertentu, kerana ClassLoader itu sendiri adalah abstrak. Setiap kali fail .class dimuatkan, contohnya, selepas memanggil pembina atau kaedah statik kelas yang sepadan, tindakan ini dilakukan oleh salah satu keturunan kelas ClassLoader . Terdapat tiga jenis ahli waris:
  1. Bootstrap ClassLoader ialah pemuat asas, dilaksanakan pada peringkat JVM dan tidak mempunyai maklum balas daripada persekitaran masa jalan, kerana ia adalah sebahagian daripada kernel JVM dan ditulis dalam kod asli. Pemuat ini berfungsi sebagai induk kepada semua kejadian ClassLoader yang lain.

    Terutamanya bertanggungjawab untuk memuatkan kelas dalaman JDK, biasanya rt.jar dan perpustakaan teras lain yang terletak dalam direktori $JAVA_HOME/jre/lib . Platform yang berbeza mungkin mempunyai pelaksanaan yang berbeza bagi pemuat kelas ini.

  2. Pemuat Kelas Sambungan ialah pemuat sambungan, keturunan kelas pemuat asas. Menjaga memuatkan lanjutan kelas asas Java standard. Dimuatkan daripada direktori sambungan JDK, biasanya $JAVA_HOME/lib/ext atau mana-mana direktori lain yang disebut dalam sifat sistem java.ext.dirs (pilihan ini boleh digunakan untuk mengawal pemuatan sambungan).

  3. System ClassLoader ialah pemuat sistem yang dilaksanakan pada peringkat JRE yang menjaga pemuatan semua kelas peringkat aplikasi ke dalam JVM. Ia memuatkan fail yang terdapat dalam pembolehubah persekitaran kelas -classpath atau -cp pilihan baris arahan.

Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 2Pemuat kelas adalah sebahagian daripada masa jalan Java. Apabila JVM meminta kelas, pemuat kelas cuba mencari kelas dan memuatkan definisi kelas ke dalam masa jalan menggunakan nama kelas yang layak sepenuhnya. Kaedah java.lang.ClassLoader.loadClass() bertanggungjawab untuk memuatkan definisi kelas pada masa jalan. Ia cuba memuatkan kelas berdasarkan nama penuhnya. Jika kelas belum dimuatkan, ia mewakilkan permintaan kepada pemuat kelas induk. Proses ini berlaku secara rekursif dan kelihatan seperti ini:
  1. Pemuat Kelas Sistem cuba mencari kelas dalam cachenya.

    • 1.1. Jika kelas ditemui, pemuatan berjaya diselesaikan.

    • 1.2. Jika kelas tidak ditemui, pemuatan diwakilkan kepada Pemuat Kelas Sambungan.

  2. Extension Classloader cuba mencari kelas dalam cachenya sendiri.

    • 2.1. Jika kelas ditemui, ia berjaya diselesaikan.

    • 2.2. Jika kelas tidak ditemui, pemuatan diwakilkan kepada Pemuat Kelas Bootstrap.

  3. Bootstrap Classloader cuba mencari kelas dalam cachenya sendiri.

    • 3.1. Jika kelas ditemui, pemuatan berjaya diselesaikan.

    • 3.2. Jika kelas tidak ditemui, Bootstrap Classloader yang mendasari akan cuba memuatkannya.

  4. Jika memuatkan:

    • 4.1. Berjaya - pemuatan kelas selesai.

    • 4.2. Jika gagal, kawalan dipindahkan ke Pemuat Kelas Sambungan.

  5. 5. Extension Classloader cuba memuatkan kelas dan jika memuatkan:

    • 5.1. Berjaya - pemuatan kelas selesai.

    • 5.2. Jika gagal, kawalan dipindahkan ke Pemuat Kelas Sistem.

  6. 6. Pemuat Kelas Sistem cuba memuatkan kelas, dan jika memuatkan:

    • 6.1. Berjaya - pemuatan kelas selesai.

    • 6.2. Tidak berjaya lulus - pengecualian dijana - ClassNotFoundException.

Topik pemuat kelas adalah topik yang luas dan tidak boleh diabaikan. Untuk mengenalinya dengan lebih terperinci, saya menasihati anda untuk membaca artikel ini , dan kami tidak akan berlama-lama dan teruskan.

12. Apakah itu Kawasan Data Masa Jalan?

Ares Data Masa Jalan - kawasan data masa jalan JVM. JVM mentakrifkan beberapa kawasan data masa jalan yang diperlukan semasa pelaksanaan program. Sebahagian daripada mereka dicipta apabila JVM bermula. Yang lain adalah setempat-benang dan dicipta hanya apabila benang itu dibuat (dan dimusnahkan apabila benang dimusnahkan). Kawasan data masa jalan JVM kelihatan seperti ini: Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 3
  • Daftar PC adalah setempat untuk setiap utas dan mengandungi alamat arahan JVM yang sedang dijalankan oleh utas itu.

  • JVM Stack ialah kawasan memori yang digunakan sebagai storan untuk pembolehubah tempatan dan hasil sementara. Setiap benang mempunyai tindanan tersendiri: sebaik sahaja benang ditamatkan, tindanan ini juga dimusnahkan. Perlu diingat bahawa kelebihan timbunan atas timbunan adalah prestasi, manakala timbunan sememangnya mempunyai kelebihan dalam skala storan.

  • Tindanan Kaedah Asli - Kawasan data per-benang yang menyimpan elemen data, serupa dengan tindanan JVM, untuk melaksanakan kaedah asli (bukan Java).

  • Heap - digunakan oleh semua utas sebagai storan yang mengandungi objek, metadata kelas, tatasusunan, dsb., yang dibuat semasa masa jalan. Kawasan ini dicipta apabila JVM bermula dan dimusnahkan apabila ia ditutup.

  • Kawasan kaedah - Kawasan masa jalan ini adalah biasa kepada semua utas dan dicipta apabila JVM bermula. Ia menyimpan struktur untuk setiap kelas, seperti Runtime Constant Pool, kod untuk pembina dan kaedah, data kaedah, dsb.

13. Apakah objek tidak berubah?

Dalam bahagian artikel ini, dalam soalan 14 dan 15, sudah ada jawapan untuk soalan ini, jadi lihatlah tanpa membuang masa anda.

14. Apakah yang istimewa tentang kelas String?

Terdahulu dalam analisis, kami berulang kali bercakap tentang ciri-ciri tertentu String (terdapat bahagian berasingan untuk ini). Sekarang mari kita ringkaskan ciri String :
  1. Ia adalah objek paling popular di Jawa dan digunakan untuk pelbagai tujuan. Dari segi kekerapan penggunaan, ia tidak kalah dengan jenis primitif.

  2. Objek kelas ini boleh dibuat tanpa menggunakan kata kunci baharu - terus melalui petikan String str = “rentetan”; .

  3. String ialah kelas yang tidak boleh diubah : apabila mencipta objek kelas ini, datanya tidak boleh diubah (apabila anda menambah + "rentetan lain" pada rentetan tertentu, akibatnya anda akan mendapat rentetan ketiga yang baharu). Ketidakbolehubahan kelas String menjadikannya selamat.

  4. Kelas String dimuktamadkan (mempunyai pengubah suai akhir ), jadi ia tidak boleh diwarisi.

  5. String mempunyai kolam rentetan sendiri, kawasan ingatan dalam timbunan yang menyimpan nilai rentetan yang dihasilkannya. Dalam bahagian siri ini , dalam soalan 62, saya menerangkan kumpulan rentetan.

  6. Java mempunyai analog String , juga direka bentuk untuk berfungsi dengan rentetan - StringBuilder dan StringBuffer , tetapi dengan perbezaannya ia boleh berubah. Anda boleh membaca lebih lanjut tentang mereka dalam artikel ini .

Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 4

15. Apakah kovarians jenis?

Untuk memahami kovarians, kita akan melihat contoh. Katakan kita mempunyai kelas haiwan:
public class Animal {
 void voice() {
   System.out.println("*тишина*");
 }
}
Dan beberapa kelas Anjing memanjangkannya :
public class Dog extends Animal {

 @Override
 public void voice() {
   System.out.println("Гав, гав, гав!!!");
 }
}
Seperti yang kita ingat, kita boleh dengan mudah menetapkan objek jenis pewaris kepada jenis induk:
Animal animal = new Dog();
Ini tidak lebih daripada polimorfisme. Mudah, fleksibel bukan? Nah, bagaimana dengan senarai haiwan? Bolehkah kita memberikan senarai dengan Haiwan generik senarai dengan objek Anjing ?
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs;
Dalam kes ini, garisan untuk menetapkan senarai anjing kepada senarai haiwan akan digariskan dengan warna merah, i.e. pengkompil tidak akan lulus kod ini. Walaupun tugasan ini nampaknya agak logik (lagipun, kita boleh menetapkan objek Anjing kepada pembolehubah jenis Animal ), ia tidak boleh dilakukan. Ini kerana jika ia dibenarkan, kami akan dapat meletakkan objek Haiwan ke dalam senarai yang pada asalnya bertujuan untuk menjadi Anjing , sambil berfikir bahawa kami hanya mempunyai Anjing dalam senarai . Dan kemudian, sebagai contoh, kita akan menggunakan kaedah get() untuk mengambil objek daripada senarai anjing itu , memikirkan bahawa ia adalah anjing, dan memanggil beberapa kaedah objek Anjing padanya, yang tidak ada pada Haiwan . Dan seperti yang anda faham, ini adalah mustahil - ralat akan berlaku. Tetapi, mujurlah, pengkompil tidak terlepas ralat logik ini dengan memberikan senarai keturunan kepada senarai ibu bapa (dan sebaliknya). Di Java, anda hanya boleh menetapkan objek senarai untuk menyenaraikan pembolehubah dengan generik yang sepadan. Ini dipanggil invariasi. Jika mereka boleh melakukan ini, ia akan dipanggil dan dipanggil kovarians. Iaitu, kovarians ialah jika kita boleh menetapkan objek jenis ArrayList<Dog> kepada pembolehubah jenis List<Animal> . Ternyata kovarians tidak disokong di Jawa? Tidak kira bagaimana keadaannya! Tetapi ini dilakukan dengan cara tersendiri. Reka bentuk digunakan untuk apa ? memanjangkan Haiwan . Ia diletakkan dengan generik pembolehubah yang kita ingin tetapkan objek senarai, dengan generik keturunan. Pembinaan generik ini bermakna bahawa mana-mana jenis yang merupakan keturunan jenis Haiwan akan lakukan (dan jenis Haiwan juga termasuk di bawah generalisasi ini). Sebaliknya, Haiwan boleh menjadi bukan sahaja kelas, tetapi juga antara muka (jangan tertipu dengan kata kunci lanjutan ). Kita boleh melakukan tugasan terdahulu seperti ini: Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 5
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
Akibatnya, anda akan melihat dalam IDE bahawa pengkompil tidak akan mengadu tentang pembinaan ini. Mari kita semak fungsi reka bentuk ini. Katakan kita mempunyai kaedah yang menyebabkan semua haiwan yang dihantar kepadanya mengeluarkan bunyi:
public static void animalsVoice(List<? extends Animal> animals) {
 for (Animal animal : animals) {
   animal.voice();
 }
}
Mari beri dia senarai anjing:
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
animalsVoice(dogs);
Dalam konsol kita akan melihat output berikut:
Woof woof woof!!! Woof woof woof!!! Woof woof woof!!!
Ini bermakna pendekatan kovarians ini berjaya. Biar saya ambil perhatian bahawa generik ini termasuk dalam senarai ? extends Animal kita tidak boleh memasukkan data baharu dalam apa jua jenis: sama ada jenis Dog , mahupun jenis Animal :
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
animals.add(new Dog());
dogs.add(new Animal());
Sebenarnya, dalam dua baris terakhir pengkompil akan menyerlahkan sisipan objek dalam warna merah. Ini disebabkan oleh fakta bahawa kita tidak boleh seratus peratus pasti senarai objek jenis apa yang akan diberikan kepada senarai dengan data oleh generik <? memanjangkan Animal> . Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 6Saya juga ingin bercakap tentang kontravarians , kerana biasanya konsep ini sentiasa bersama-sama dengan kovarians, dan sebagai peraturan mereka ditanya tentangnya bersama-sama. Konsep ini agak bertentangan dengan kovarians, kerana konstruk ini menggunakan jenis pewaris. Katakan kita mahukan senarai yang boleh diberikan senarai objek jenis yang bukan nenek moyang objek Dog . Walau bagaimanapun, kami tidak mengetahui terlebih dahulu jenis khusus ini. Dalam kes ini, pembinaan borang ? super Dog , yang mana semua jenis sesuai - nenek moyang kelas Anjing :
List<Animal> animals = new ArrayList<>();
List<? super Dog> dogs = animals;
dogs.add(new Dog());
dogs.add(new Dog());
Kami dengan selamat boleh menambah objek jenis Dog ke senarai dengan generik seperti itu , kerana dalam apa jua keadaan ia mempunyai semua kaedah yang dilaksanakan oleh mana-mana nenek moyangnya. Tetapi kami tidak akan dapat menambah objek jenis Animal , kerana tidak ada kepastian bahawa akan ada objek jenis ini di dalam, dan bukan, sebagai contoh, Dog . Lagipun, kita boleh meminta daripada elemen senarai ini kaedah kelas Anjing , yang Haiwan tidak akan mempunyai . Dalam kes ini, ralat penyusunan akan berlaku. Juga, jika kita ingin melaksanakan kaedah sebelumnya, tetapi dengan generik ini:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Dog dog : dogs) {
   dog.voice();
 }
}
kami akan mendapat ralat kompilasi dalam for loop , kerana kami tidak dapat memastikan bahawa senarai yang dikembalikan mengandungi objek jenis Dog dan bebas menggunakan kaedahnya. Jika kita memanggil kaedah dogs.get(0) pada senarai ini . - kita akan mendapat objek jenis Object . Iaitu, untuk kaedah animalsVoice() berfungsi , kita sekurang-kurangnya perlu menambah manipulasi kecil dengan menyempitkan data jenis:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Object obj : dogs) {
   if (obj instanceof Dog) {
     Dog dog = (Dog) obj;
     dog.voice();
   }
 }
}
Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 7

16. Bagaimanakah terdapat kaedah dalam kelas Objek?

Dalam bahagian siri ini, dalam perenggan 11, saya telah pun menjawab soalan ini, jadi saya amat menasihati anda untuk membacanya jika anda belum melakukannya lagi. Di situlah kita akan berakhir untuk hari ini. Jumpa anda di bahagian seterusnya! Analisis soalan dan jawapan daripada temu bual untuk pembangun Java.  Bahagian 15 - 8
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION