JavaRush /Java Blog /Random-ID /Analisis tanya jawab dari wawancara untuk pengembang Java...

Analisis tanya jawab dari wawancara untuk pengembang Java. Bagian 15

Dipublikasikan di grup Random-ID
Hai Hai! Berapa banyak yang perlu diketahui oleh pengembang Java? Anda dapat berdebat lama tentang masalah ini, tetapi kenyataannya adalah bahwa pada wawancara Anda akan didorong sepenuhnya oleh teori. Bahkan dalam bidang pengetahuan yang tidak dapat Anda gunakan dalam pekerjaan Anda. Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 1Nah, jika Anda seorang pemula, pengetahuan teoritis Anda akan ditanggapi dengan sangat serius. Karena belum ada pengalaman dan prestasi besar, yang tersisa hanyalah mengecek kekuatan basis pengetahuan. Hari ini kami akan terus memperkuat dasar ini dengan memeriksa pertanyaan wawancara paling populer untuk pengembang Java. Ayo terbang!

Inti Java

9. Apa perbedaan antara pengikatan statis dan dinamis di Java?

Saya sudah menjawab pertanyaan ini di artikel ini di pertanyaan 18 tentang polimorfisme statis dan dinamis, saya menyarankan Anda untuk membacanya.

10. Apakah mungkin untuk menggunakan variabel pribadi atau variabel yang dilindungi dalam sebuah antarmuka?

Tidak Anda tidak bisa. Karena ketika Anda mendeklarasikan sebuah antarmuka, kompiler Java secara otomatis menambahkan kata kunci public dan abstract sebelum metode antarmuka dan kata kunci public , static dan final sebelum anggota data. Sebenarnya, jika Anda menambahkan private atau protected , konflik akan muncul, dan kompiler akan mengeluh tentang pengubah akses dengan pesan: "Pengubah '<pengubah yang dipilih>' tidak diizinkan di sini." Mengapa kompiler menambahkan public , static dan final variabel di antarmuka? Mari kita cari tahu:
  • publik - antarmuka memungkinkan klien untuk berinteraksi dengan objek. Jika variabelnya tidak bersifat publik, klien tidak akan memiliki akses ke variabel tersebut.
  • statis - antarmuka tidak dapat dibuat (atau lebih tepatnya, objeknya), jadi variabelnya statis.
  • final - karena antarmuka digunakan untuk mencapai abstraksi 100%, variabel memiliki bentuk akhirnya (dan tidak akan diubah).

11. Apa itu Classloader dan kegunaannya?

Classloader - atau Class Loader - menyediakan pemuatan kelas Java. Lebih tepatnya, pemuatan disediakan oleh turunannya - pemuat kelas tertentu, karena ClassLoader sendiri bersifat abstrak. Setiap kali file .class dimuat, misalnya, setelah memanggil konstruktor atau metode statis dari kelas terkait, tindakan ini dilakukan oleh salah satu turunan kelas ClassLoader . Ada tiga jenis ahli waris:
  1. Bootstrap ClassLoader adalah pemuat dasar, diimplementasikan pada tingkat JVM dan tidak memiliki umpan balik dari lingkungan runtime, karena merupakan bagian dari kernel JVM dan ditulis dalam kode asli. Loader ini berfungsi sebagai induk dari semua instance ClassLoader lainnya.

    Bertanggung jawab terutama untuk memuat kelas internal JDK, biasanya rt.jar dan perpustakaan inti lainnya yang terletak di direktori $JAVA_HOME/jre/lib . Platform yang berbeda mungkin memiliki implementasi yang berbeda dari pemuat kelas ini.

  2. Extension Classloader adalah pemuat ekstensi, turunan dari kelas pemuat dasar. Menangani pemuatan ekstensi kelas dasar Java standar. Dimuat dari direktori ekstensi JDK, biasanya $JAVA_HOME/lib/ext atau direktori lain yang disebutkan dalam properti sistem java.ext.dirs (opsi ini dapat digunakan untuk mengontrol pemuatan ekstensi).

  3. System ClassLoader adalah pemuat sistem yang diimplementasikan pada tingkat JRE yang menangani pemuatan semua kelas tingkat aplikasi ke dalam JVM. Ini memuat file yang ditemukan di variabel lingkungan kelas -classpath atau opsi baris perintah -cp .

Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 2Pemuat kelas adalah bagian dari runtime Java. Saat JVM meminta sebuah kelas, pemuat kelas mencoba menemukan kelas tersebut dan memuat definisi kelas ke dalam runtime menggunakan nama kelas yang sepenuhnya memenuhi syarat. Metode java.lang.ClassLoader.loadClass() bertanggung jawab untuk memuat definisi kelas saat runtime. Ia mencoba memuat kelas berdasarkan nama lengkapnya. Jika kelas belum dimuat, permintaan tersebut akan didelegasikan ke pemuat kelas induk. Proses ini terjadi secara rekursif dan terlihat seperti ini:
  1. System Classloader mencoba menemukan kelas dalam cache-nya.

    • 1.1. Jika kelas ditemukan, pemuatan berhasil diselesaikan.

    • 1.2. Jika kelas tidak ditemukan, pemuatan didelegasikan ke Extension Classloader.

  2. Extension Classloader mencoba menemukan kelas dalam cache-nya sendiri.

    • 2.1. Jika kelas ditemukan, maka berhasil diselesaikan.

    • 2.2. Jika kelas tidak ditemukan, pemuatan didelegasikan ke Bootstrap Classloader.

  3. Bootstrap Classloader mencoba menemukan kelas di cache-nya sendiri.

    • 3.1. Jika kelas ditemukan, pemuatan berhasil diselesaikan.

    • 3.2. Jika kelas tidak ditemukan, Bootstrap Classloader yang mendasarinya akan mencoba memuatnya.

  4. Jika memuat:

    • 4.1. Berhasil - pemuatan kelas selesai.

    • 4.2. Jika gagal, kontrol ditransfer ke Extension Classloader.

  5. 5. Extension Classloader mencoba memuat kelas, dan jika memuat:

    • 5.1. Berhasil - pemuatan kelas selesai.

    • 5.2. Jika gagal, kontrol ditransfer ke System Classloader.

  6. 6. System Classloader mencoba memuat kelas, dan jika memuat:

    • 6.1. Berhasil - pemuatan kelas selesai.

    • 6.2. Tidak berhasil lolos - pengecualian dihasilkan - ClassNotFoundException.

Topik mengenai class loader merupakan topik yang luas dan tidak boleh diabaikan. Untuk mengenalnya lebih detail, saya menyarankan Anda untuk membaca artikel ini , dan kami tidak akan berlama-lama dan melanjutkan.

12. Apa yang dimaksud dengan Area Data Run-Time?

Ares Data Run-Time - Area data runtime JVM. JVM mendefinisikan beberapa area data runtime yang diperlukan selama eksekusi program. Beberapa di antaranya dibuat saat JVM dimulai. Lainnya bersifat thread-lokal dan dibuat hanya ketika thread dibuat (dan dimusnahkan ketika thread dimusnahkan). Area data runtime JVM terlihat seperti ini: Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 3
  • PC Register bersifat lokal untuk setiap thread dan berisi alamat instruksi JVM yang sedang dijalankan oleh thread tersebut.

  • JVM Stack adalah area memori yang digunakan sebagai penyimpanan variabel lokal dan hasil sementara. Setiap thread memiliki tumpukannya sendiri-sendiri: segera setelah thread dihentikan, tumpukan ini juga dimusnahkan. Perlu diperhatikan bahwa keunggulan stack dibandingkan heap adalah performanya, sedangkan heap tentunya memiliki keunggulan dalam skala penyimpanan.

  • Native Method Stack - Area data per-thread yang menyimpan elemen data, mirip dengan tumpukan JVM, untuk mengeksekusi metode asli (non-Java).

  • Heap - digunakan oleh semua thread sebagai penyimpanan yang berisi objek, metadata kelas, array, dll., yang dibuat saat runtime. Area ini dibuat saat JVM dimulai dan dimusnahkan saat dimatikan.

  • Area metode - Area runtime ini umum untuk semua thread dan dibuat saat JVM dimulai. Ini menyimpan struktur untuk setiap kelas, seperti Runtime Constant Pool, kode untuk konstruktor dan metode, data metode, dll.

13. Apa yang dimaksud dengan objek yang tidak dapat diubah?

Pada bagian artikel ini, pada soal 14 dan 15, sudah ada jawaban untuk pertanyaan tersebut, jadi silahkan simak tanpa membuang waktu Anda.

14. Apa yang spesial dari kelas String?

Sebelumnya dalam analisis, kami berulang kali membicarakan tentang fitur tertentu dari String (ada bagian terpisah untuk ini). Sekarang mari kita rangkum fitur-fitur String :
  1. Ini adalah objek paling populer di Java dan digunakan untuk berbagai tujuan. Dalam hal frekuensi penggunaan, tidak kalah dengan tipe primitif sekalipun.

  2. Objek kelas ini dapat dibuat tanpa menggunakan kata kunci new - langsung melalui tanda kutip String str = “string”; .

  3. String adalah kelas yang tidak dapat diubah : saat membuat objek dari kelas ini, datanya tidak dapat diubah (saat Anda menambahkan + "string lain" ke string tertentu, Anda akan mendapatkan string ketiga yang baru). Kekekalan kelas String membuatnya aman untuk thread.

  4. Kelas String sudah diselesaikan (memiliki pengubah akhir ), sehingga tidak dapat diwarisi.

  5. String memiliki kumpulan stringnya sendiri, area memori di heap yang menyimpan nilai string yang dibuatnya dalam cache. Di bagian seri ini , pada pertanyaan 62, saya menjelaskan kumpulan string.

  6. Java memiliki analogi String , juga dirancang untuk bekerja dengan string - StringBuilder dan StringBuffer , tetapi dengan perbedaan bahwa keduanya dapat berubah. Anda dapat membaca lebih lanjut tentang mereka di artikel ini .

Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 4

15. Apa yang dimaksud dengan kovarians tipe?

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

 @Override
 public void voice() {
   System.out.println("Гав, гав, гав!!!");
 }
}
Seperti yang kita ingat, kita dapat dengan mudah menetapkan objek bertipe pewaris ke tipe induk:
Animal animal = new Dog();
Ini tidak lebih dari polimorfisme. Nyaman, fleksibel bukan? Nah, bagaimana dengan daftar hewannya? Bisakah kita memberikan daftar dengan Animal generik daftar dengan objek Dog ?
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs;
Dalam hal ini, baris untuk menetapkan daftar anjing ke daftar hewan akan digarisbawahi dengan warna merah, mis. kompiler tidak akan meneruskan kode ini. Meskipun penugasan ini tampaknya cukup logis (bagaimanapun juga, kita dapat menetapkan objek Dog ke variabel bertipe Animal ), hal ini tidak dapat dilakukan. Hal ini karena jika diperbolehkan, kita akan dapat memasukkan objek Animal ke dalam daftar yang awalnya dimaksudkan sebagai Dog , sambil berpikir bahwa kita hanya memiliki Dogs dalam daftar tersebut . Dan kemudian, misalnya, kita akan menggunakan metode get() untuk mengambil objek dari daftar anjing tersebut , berpikir bahwa itu adalah seekor anjing, dan memanggil beberapa metode dari objek Anjing di atasnya, yang tidak dimiliki oleh Hewan . Dan seperti yang Anda pahami, ini tidak mungkin - kesalahan akan terjadi. Namun, untungnya, kompiler tidak melewatkan kesalahan logis ini dengan menugaskan daftar keturunan ke daftar orang tua (dan sebaliknya). Di Java, Anda hanya dapat menetapkan objek daftar ke variabel daftar dengan obat generik yang cocok. Ini disebut invariasi. Jika mereka bisa melakukan ini, itu akan disebut dan disebut kovarians. Artinya, kovarians adalah jika kita dapat menyetel objek bertipe ArrayList<Dog> ke variabel bertipe List<Animal> . Ternyata kovarians tidak didukung di Jawa? Tidak peduli bagaimana keadaannya! Tapi ini dilakukan dengan cara tersendiri. Untuk apa desain tersebut digunakan ? memperluas Hewan . Itu ditempatkan dengan variabel generik yang ingin kita atur objek daftarnya, dengan generik turunannya. Konstruksi umum ini berarti bahwa tipe apa pun yang merupakan keturunan dari tipe Hewan akan dapat melakukannya (dan tipe Hewan juga termasuk dalam generalisasi ini). Pada gilirannya, Animal tidak hanya bisa menjadi sebuah kelas, tetapi juga sebuah antarmuka (jangan tertipu dengan kata kunci extends ). Kita dapat mengerjakan tugas kita sebelumnya seperti ini: Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 5
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
Hasilnya, Anda akan melihat di IDE bahwa kompiler tidak akan mengeluh tentang konstruksi ini. Mari kita periksa fungsionalitas desain ini. Katakanlah kita mempunyai metode yang menyebabkan semua hewan yang melewatinya mengeluarkan suara:
public static void animalsVoice(List<? extends Animal> animals) {
 for (Animal animal : animals) {
   animal.voice();
 }
}
Mari kita beri dia daftar anjing:
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
animalsVoice(dogs);
Di konsol kita akan melihat output berikut:
Guk guk guk!!! Guk guk guk!!! Guk guk guk!!!
Artinya, pendekatan kovarians ini berhasil. Izinkan saya mencatat bahwa obat generik ini termasuk dalam daftar ? extends Animal kita tidak dapat memasukkan data baru jenis apa pun: baik jenis Dog maupun jenis Animal :
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
animals.add(new Dog());
dogs.add(new Animal());
Sebenarnya pada dua baris terakhir compiler akan menyorot penyisipan objek dengan warna merah. Hal ini disebabkan oleh fakta bahwa kita tidak dapat seratus persen yakin daftar objek jenis apa yang akan ditugaskan ke daftar dengan data dengan <? memperluas Hewan> . Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 6Saya juga ingin berbicara tentang kontravarian , karena biasanya konsep ini selalu sejalan dengan kovarians, dan biasanya mereka ditanyai secara bersamaan. Konsep ini agak kebalikan dari kovarians, karena konstruksi ini menggunakan tipe pewaris. Katakanlah kita menginginkan sebuah daftar yang dapat diberi daftar objek bertipe yang bukan merupakan nenek moyang dari objek Dog . Namun, kami belum mengetahui sebelumnya jenis spesifiknya. Dalam hal ini, konstruksi formulir ? Anjing super , yang cocok untuk semua jenis - nenek moyang dari kelas Anjing :
List<Animal> animals = new ArrayList<>();
List<? super Dog> dogs = animals;
dogs.add(new Dog());
dogs.add(new Dog());
Kita dapat dengan aman menambahkan objek bertipe Dog ke dalam daftar dengan generik seperti itu , karena bagaimanapun juga ia memiliki semua metode yang diimplementasikan dari nenek moyangnya. Tapi kita tidak akan bisa menambahkan objek bertipe Animal , karena tidak ada kepastian bahwa akan ada objek bertipe ini di dalamnya, dan bukan, misalnya Dog . Lagi pula, kita dapat meminta dari elemen daftar ini sebuah metode kelas Dog , yang mana Animal tidak akan memilikinya . Dalam hal ini, kesalahan kompilasi akan terjadi. Juga, jika kita ingin menerapkan metode sebelumnya, tetapi dengan metode generik ini:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Dog dog : dogs) {
   dog.voice();
 }
}
kita akan mendapatkan kesalahan kompilasi di loop for , karena kita tidak dapat memastikan bahwa daftar yang dikembalikan berisi objek bertipe Dog dan bebas menggunakan metodenya. Jika kita memanggil metode dog.get(0) di daftar ini . - kita akan mendapatkan objek bertipe Object . Artinya, agar metode animalVoice() berfungsi , setidaknya kita perlu menambahkan manipulasi kecil dengan mempersempit tipe data:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Object obj : dogs) {
   if (obj instanceof Dog) {
     Dog dog = (Dog) obj;
     dog.voice();
   }
 }
}
Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 7

16. Bagaimana cara menggunakan metode di kelas Object?

Di bagian seri ini, di paragraf 11, saya sudah menjawab pertanyaan ini, jadi saya sangat menyarankan Anda untuk membacanya jika Anda belum melakukannya. Di situlah kita akan mengakhiri hari ini. Sampai jumpa di bagian selanjutnya! Analisis tanya jawab dari wawancara untuk pengembang Java.  Bagian 15 - 8
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION