Konten berikut adalah pertanyaan dan jawaban yang bertanggung jawab yang diberikan setelah set pertanyaan dan jawaban wawancara Java asli sepenuhnya direvisi. Ada banyak pertanyaan duplikat dan pertanyaan berharga dalam pertanyaan asli, dan banyak jawaban referensi juga salah. Set pertanyaan wawancara Java yang dimodifikasi mengacu pada versi terbaru JDK, menghilangkan konten yang tidak berguna seperti EJB 2.x, dan melengkapi struktur data dan pertanyaan terkait algoritma, pertanyaan pemrograman wawancara klasik, arsitektur teknis situs web besar, sistem operasi, basis data, pengujian perangkat lunak, pola desain, UML dan konten lainnya. Pada saat yang sama, banyak titik pengetahuan telah dianalisis secara mendalam, seperti desain metode kode hash, tumpukan dan generasi pengumpulan sampah, pemrograman bersamaan baru Java, Nio.2, dll. Saya percaya itu akan bermanfaat bagi pemrogram Java yang sedang mempersiapkan untuk bergabung.
Pertanyaan Wawancara Programmer Java (1-50)
1. Dasar -dasar Java
1. Apa aspek karakteristik yang berorientasi objek?
Jawaban: Aspek utama fitur yang berorientasi objek adalah:
1) Abstrak: Abstraksi adalah proses merangkum karakteristik umum dari jenis objek ke dalam kelas objek, termasuk abstraksi data dan abstraksi perilaku. Abstraksi hanya berfokus pada atribut dan perilaku apa yang dimiliki objek, dan tidak memperhatikan apa detail perilaku ini.
2) Warisan: Warisan adalah proses mendapatkan informasi warisan dari kelas yang ada dan membuat kelas baru. Kelas yang menyediakan informasi warisan disebut kelas induk (superclass, kelas dasar); Kelas yang memperoleh informasi warisan disebut subkelas (kelas turunan). Warisan memberikan sistem perangkat lunak yang berubah tingkat kontinuitas tertentu, dan warisan juga merupakan cara penting untuk merangkum faktor variabel dalam program ini (jika Anda tidak dapat memahaminya, silakan baca bagian tentang mode jembatan dalam "java dan pola" Dr. Yan Hong, atau "pola desain yang luar biasa").
3) Enkapsulasi: Secara umum diyakini bahwa enkapsulasi adalah untuk mengikat data dengan metode data operasi, dan akses ke data hanya dapat dicapai melalui antarmuka yang ditentukan. Inti dari objek-berorientasi adalah untuk menggambarkan dunia nyata sebagai serangkaian objek yang sepenuhnya otonom dan tertutup. Metode yang kami tulis di kelas adalah merangkum detail implementasi; Kami menulis kelas adalah merangkum operasi data dan data. Dapat dikatakan bahwa pengemasan adalah untuk menyembunyikan segala sesuatu yang dapat disembunyikan, dan hanya menyediakan antarmuka pemrograman paling sederhana ke dunia luar (Anda dapat memikirkan perbedaan antara mesin cuci biasa dan mesin cuci yang sepenuhnya otomatis. Jelas bahwa mesin cuci yang sepenuhnya otomatis dikemas dengan lebih baik dan karenanya lebih mudah untuk beroperasi; smartphone yang kami gunakan sekarang juga dikemas dengan baik karena beberapa kancing dapat menangani segala hal.
4) Polimorfisme: Polimorfisme mengacu pada memungkinkan objek subtipe yang berbeda untuk merespons secara berbeda terhadap pesan yang sama. Sederhananya, itu untuk memanggil metode yang sama dengan referensi objek yang sama tetapi melakukan hal yang berbeda. Polimorfisme dibagi menjadi polimorfisme waktu kompilasi dan polimorfisme run-time. Jika metode objek dianggap sebagai layanan yang disediakan oleh objek ke dunia luar, maka polimorfisme runtime dapat dijelaskan sebagai: Ketika sistem A mengakses layanan yang disediakan oleh Sistem B, Sistem B memiliki banyak cara untuk menyediakan layanan, tetapi semuanya transparan ke sistem A (seperti halnya case listrik, Sistem A, sistem catu daya adalah sistem B, sistem B dapat diberdayakan oleh baterai A atau SOLEY MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MAI MABA SOLY. objek, tetapi tidak tahu apa implementasi yang mendasari sistem catu daya dan bagaimana ia memperoleh daya). Metode Overloading mengimplementasikan polimorfisme waktu kompilasi (juga dikenal sebagai prebinding), sedangkan metode override mengimplementasikan polimorfisme run-time (juga dikenal sebagai pascapung). Polimorfisme runtime adalah hal yang paling penting tentang berorientasi objek. Untuk mengimplementasikan polimorfisme, dua hal perlu dilakukan: 1. Metode penulisan ulang (subkelas mewarisi kelas induk dan menulis ulang metode yang ada atau abstrak dalam kelas induk); 2. Pemodelan Objek (Mengacu pada objek tipe anak dengan referensi tipe induk, sehingga referensi yang sama memanggil metode yang sama akan menunjukkan perilaku yang berbeda sesuai dengan objek subclass yang berbeda).
2. Apa perbedaan antara mengakses pengubah publik, pribadi, terlindungi, dan tidak menulis (default)?
Jawaban: Perbedaannya adalah sebagai berikut:
Lingkupnya sama dengan subkelas Bun.
publik √ √ √ √ √ √
Dilindungi √ √ √ ×
default √ √ × × ×
Pribadi √ × × × × ×
Standarnya default ketika anggota kelas tidak menulis modifikasi akses. Secara default, setara dengan publik untuk kelas lain dalam paket yang sama, dan pribadi untuk kelas lain yang tidak dalam paket yang sama. Dilindungi setara dengan publik dengan subkelas, dan pribadi ke kelas yang tidak dalam paket yang sama yang tidak memiliki hubungan orangtua-anak.
3. Apakah string tipe data paling dasar?
Jawaban: Tidak. Hanya ada 8 tipe data dasar di java: byte, pendek, int, long, float, double, char, dan boolean; Kecuali untuk tipe dasar (tipe primitif) dan tipe enumerasi (tipe enumerasi), sisanya adalah jenis referensi (tipe referensi).
4. Mengapung f = 3.4; Apakah itu benar?
Jawaban: Salah. 3.4 adalah nomor presisi ganda. Menetapkan tipe titik floating double to floating (float) akan menyebabkan kehilangan akurasi (down-casting, juga dikenal sebagai penyempitan), jadi Anda perlu melemparkan float f = (float) 3.4; atau tulis float f = 3.4f;.
5. Pendek S1 = 1; S1 = S1 + 1; Apakah ada yang salah? S1 pendek = 1; S1 += 1; Apakah ada yang salah?
Jawaban: untuk S1 pendek = 1; S1 = S1 + 1; Karena 1 adalah tipe int, hasil operasi S1+1 juga merupakan tipe int, dan tipe cast diperlukan untuk menetapkan nilai pada tipe pendek. Dan S1 pendek = 1; S1 += 1; dapat dikompilasi dengan benar karena S1+= 1; setara dengan S1 = (pendek) (S1 + 1); Ada gips implisit.
6. Apakah ada goto di java?
Jawaban: GOTO adalah kata yang dipesan di java dan tidak digunakan dalam versi java saat ini. (Daftar kata kunci Java diberikan dalam lampiran buku "The Java Programming Language" yang ditulis oleh James Gosling (bapak Java) yang mencakup Goto dan Const, tetapi keduanya adalah kata kunci yang saat ini tidak dapat digunakan, sehingga beberapa tempat yang disediakan oleh kata -kata yang diketahui bahwa kata -kata yang disediakan oleh kata -kata yang disediakan oleh kata -kata yang lebih luas, karena makna yang lebih luas, karena pemrograman yang diketahui bahwa kata -kata yang diketahui oleh kata -kata yang lebih luas, karena makna yang lebih luas, karena pemrograman yang diketahui bahwa kata -kata yang diketahui oleh kata -kata yang diketahui oleh kata -kata yang lebih luas, karena program yang lebih luas, karena program, karena program yang sudah ada. dianggap kata -kata yang dipesan)
7. Apa perbedaan antara int dan integer?
Jawaban: Java adalah bahasa pemrograman yang berorientasi objek yang hampir murni, tetapi untuk kenyamanan pemrograman, masih memperkenalkan tipe data dasar yang bukan objek. Namun, untuk mengoperasikan tipe data dasar ini sebagai objek, Java telah memperkenalkan kelas pembungkus yang sesuai untuk setiap tipe data dasar. Kelas pengemasan int adalah bilangan bulat. Sejak JDK 1.5, mekanisme pengemasan/unboxing otomatis telah diperkenalkan, sehingga keduanya dapat dikonversi satu sama lain.
Java menyediakan jenis pembungkus untuk setiap jenis primitif:
Jenis Primitif: Boolean, Char, Byte, Short, Int, Long, Float, Double
Jenis Pengemasan: Boolean, Karakter, Byte, Short, Integer, Long, Float, Double
paket com.lovo; // Mengapa bertanya tentang hovertree. Integer B = 3; // Kotak Otomatis 3 ke Integer Type Int C = 3; System.out.println (a == b); // Salah Dua referensi tidak merujuk pada sistem objek yang sama.out.println (a == c); // Benar a secara otomatis unbox ke jenis int dan kemudian dibandingkan dengan c}}
Ditambahkan: Saya baru -baru ini menemukan pertanyaan wawancara, yang juga terkait dengan pengemasan dan unboxing otomatis, kodenya adalah sebagai berikut:
test kelas publik03 {public static void main (string [] args) {integer f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println (f1 == f2); System.out.println (f3 == f4); }} // hovertree.comJika Anda tidak memahaminya, mudah untuk berpikir bahwa kedua output itu benar atau salah. Pertama -tama, penting untuk dicatat bahwa empat variabel F1, F2, F3, dan F4 adalah semua objek integer, sehingga operasi == berikut membandingkan nilai bukan tetapi referensi. Apa inti dari pengemasan? Ketika kami menetapkan nilai int ke objek integer, kami akan memanggil nilai metode statis dari kelas integer. Jika kita melihat kode sumber nilai, kita akan tahu apa yang sedang terjadi.
Nilai integer statis publik (int i) {if (i> = integercache.low && i <= integercache.high) mengembalikan integercache.cache [i + (-integercercache.low)]; mengembalikan bilangan bulat baru (i); } // hovertree.comIntegercache adalah kelas integer dalam, dan kodenya terlihat seperti ini:
/** * cache untuk mendukung semantik identitas objek autoboxing untuk nilai antara * -128 dan 127 (inklusif) seperti yang dipersyaratkan oleh JLS. * * Cache diinisialisasi pada penggunaan pertama. Ukuran cache * dapat dikontrol oleh opsi {@code -xx: autoboxCachemax = <Size>}. * Selama inisialisasi VM, java.lang.integer.integercache.high properti * dapat ditetapkan dan disimpan dalam properti sistem pribadi di kelas * sun.misc.vm. * hovertree.com */ private static class integercache {static final int low = -128; statis final int high; cache integer final statis []; static {// nilai tinggi dapat dikonfigurasi oleh properti int h = 127; String integercacheHighPropValue = sun.misc.vm.getsavedproperty ("java.lang.integer.integercache.high"); if (integercacheHighpropValue! = null) {coba {int i = parseInt (integercacheHighPropValue); i = Math.max (i, 127); // Ukuran array maksimum adalah integer.max_value h = math.min (i, integer.max_value -(-low) -1); } catch (NumberFormateException NFE) {// Jika properti tidak dapat diuraikan ke int, abaikan. }} tinggi = h; cache = bilangan bulat baru [(tinggi - rendah) + 1]; int j = rendah; untuk (int k = 0; k <cache.length; k ++) cache [k] = bilangan bulat baru (j ++); // rentang [-128, 127] harus diinternalisasi (JLS7 5.1.7) menegaskan integercache.high> = 127; } private integercache () {}}Sederhananya, jika nilai literal adalah antara -128 dan 127, maka objek integer baru tidak akan menjadi baru, tetapi objek integer di kumpulan konstan akan langsung direferensikan. Oleh karena itu, hasil F1 == F2 dalam pertanyaan wawancara di atas adalah benar, dan hasil F3 == F4 salah. Semakin sederhana pertanyaan wawancara, semakin banyak misteri yang ada, dan pewawancara perlu memiliki keterampilan yang cukup besar.
8. Apa perbedaan antara & dan &&?
Jawaban: Ada dua penggunaan & operator: (1) bitwise dan (2) logis dan. Operator && adalah sirkuit pendek dan operasi. Perbedaan antara logika dan sirkuit pendek sangat besar, meskipun keduanya mensyaratkan bahwa nilai boolean di ujung kiri dan kanan operator sesuai dengan nilai seluruh ekspresi. && disebut operasi sirkuit pendek karena jika nilai ekspresi di sebelah kiri && adalah false, ekspresi di sebelah kanan akan secara langsung secara langsung dan operasi tidak akan dilakukan. Berkali -kali kita mungkin perlu menggunakan && bukan &. Misalnya, ketika memverifikasi bahwa nama pengguna bukan nol dan bukan string kosong, itu harus ditulis sebagai: nama pengguna! = Null &&! Username.equals (""). Urutan keduanya tidak dapat dipertukarkan, dan operator & tidak dapat digunakan, karena jika kondisi pertama tidak benar, sama dengan perbandingan string tidak dapat dilakukan sama sekali, jika tidak nullpointerException akan dihasilkan. Catatan: Hal yang sama berlaku untuk perbedaan antara logis atau operator (|) dan sirkuit pendek atau operator (||).
Ditambahkan: Jika Anda terbiasa dengan JavaScript, Anda mungkin dapat merasakan kekuatan komputasi hubung singkat lebih banyak. Jika Anda ingin menjadi master JavaScript, mulailah dengan memainkan komputasi sirkuit pendek.
9. Jelaskan penggunaan tumpukan, tumpukan dan area penyimpanan statis dalam memori.
Jawaban: Biasanya kami mendefinisikan variabel dari tipe data dasar, referensi objek, dan penyimpanan fungsi di tempat panggilan semua menggunakan ruang tumpukan dalam memori; dan objek yang dibuat melalui kata kunci dan konstruktor baru ditempatkan di ruang tumpukan; Literal dalam program, seperti 100, "halo" dan konstanta yang ditulis secara langsung ditempatkan di area penyimpanan statis. Ruang tumpukan mengoperasikan tercepat tetapi juga sangat kecil. Biasanya sejumlah besar objek ditempatkan di ruang tumpukan, dan seluruh memori, termasuk memori virtual pada hard disk, dapat digunakan sebagai ruang tumpukan.
String str = string baru ("halo");
Dalam pernyataan di atas, STR ditempatkan pada tumpukan, objek string yang dibuat dengan yang baru ditempatkan di tumpukan, dan "halo" literal ditempatkan di area penyimpanan statis.
Suplemen: Versi Java yang lebih baru menggunakan teknologi yang disebut "Analisis Escape" yang dapat menempatkan beberapa objek lokal di tumpukan untuk meningkatkan kinerja operasional objek.
10. Apa itu Math.round (11.5) sama dengan? Apa itu Math.round (-11.5) sama dengan?
Jawaban: Nilai pengembalian Math.round (11.5) adalah 12, dan nilai pengembalian Math.round (-11.5) adalah -11. Prinsip pembulatan adalah menambahkan 0,5 ke parameter dan kemudian membulatkannya.
11. Bisakah swtich bertindak atas byte, bertindak panjang dengan string?
Jawaban: Di JDK awal, di switch (expr), expr dapat byte, pendek, char, dan int. Mulai dari versi 1.5, Java telah memperkenalkan tipe enum (enum), dan Expr juga dapat enum, mulai dari versi 1.7 JDK, dan juga string (string). Tipe panjang tidak diperbolehkan.
12. Gunakan metode yang paling efisien untuk menghitung 2 kali 8?
Jawaban: 2 << 3 (bergerak 3 bit di sebelah kiri setara dengan dikalikan dengan 2 dengan kekuatan 3, dan memindahkan 3 bit di sebelah kanan setara dengan membagi dengan 2 dengan kekuatan 3).
Suplemen: Ketika kami menulis ulang metode kode hash untuk kelas yang kami tulis, kami dapat melihat kode yang ditunjukkan di bawah ini. Faktanya, kami tidak begitu mengerti mengapa kami menggunakan perkalian seperti itu untuk menghasilkan kode hash (kode hash), dan mengapa angka ini merupakan bilangan prima, dan mengapa angka 31 biasanya dipilih? Anda dapat Baidu pada jawaban atas dua pertanyaan pertama. Pilih 31 karena operasi shift dan pengurangan dapat digunakan sebagai pengganti multiplikasi, sehingga mencapai kinerja yang lebih baik. Berbicara tentang hal ini, Anda mungkin telah memikirkan: 31 * num <==> (num << 5) - num, menggeser 5 bit kiri setara dengan dikalikan dengan 2 ke daya ke -5 (32) dan mengurangi dirinya sendiri setara dengan dikalikan dengan 31. Semua VM secara otomatis dapat menyelesaikan optimisasi ini.
Paket com.Loonstudio; phonenumber kelas publik {private int AreaCode; awalan string pribadi; linenumber string pribadi; @Override public int hashCode () {final int prime = 31; Hasil int = 1; Hasil = Hasil Prime * + AreaCode; Hasil = Prime * hasil + ((linenumber == null)? 0: linenumber.hashcode ()); hasil = hasil prime * + ((prefix == null)? 0: prefix.hashcode ()); hasil pengembalian; } @Override public boolean sama (objek obj) {if (this == obj) mengembalikan true; if (obj == null) mengembalikan false; if (getClass ()! = obj.getClass ()) mengembalikan false; Fonenumber lainnya = (fonenumber) obj; if (AreaCode! = Other.Areacode) Return False; if (linenumber == null) {if (Other.linenumber! = null) return false; } lain jika (! linenumber.equals (Other.linenumber)) Return false; if (prefix == null) {if (Other.prefix! = null) return false; } else if (! prefix.equals (Other.prefix)) return false; Kembali Benar; }} // Mengapa bertanya tentang hovertree.com13. Apakah ada metode panjang () untuk array? Apakah ada metode panjang () untuk string?
Jawaban: Array tidak memiliki metode panjang (), tetapi memiliki atribut panjang. String memiliki metode panjang (). Dalam JavaScript, memperoleh panjang string diperoleh melalui atribut panjang, yang mudah dikacaukan dengan Java.
14. Di Java, bagaimana cara keluar dari beberapa loop bersarang saat ini?
Jawab: Tambahkan tanda seperti sebelum loop terluar, dan kemudian gunakan break a; Beberapa loop bisa rusak. (Java mendukung tagged break dan melanjutkan pernyataan, dan fungsinya sedikit mirip dengan pernyataan GOTO di C dan C ++, tetapi sama seperti menghindari GOTO, Anda harus menghindari Tagged Break dan melanjutkan karena tidak akan membuat program Anda lebih elegan, dan seringkali memiliki efek sebaliknya, jadi sintaks ini sebenarnya lebih baik.)
15. Bisakah konstruktor ditimpa?
Jawaban: Konstruktor tidak dapat diwarisi, sehingga tidak dapat ditulis ulang, tetapi dapat dikeluarkan.
16. Dua objek memiliki nilai yang sama (x.Equals (y) == Benar), tetapi mereka dapat memiliki kode hash yang berbeda. Apakah ini benar?
Jawaban: Tidak, jika kedua objek X dan Y memenuhi x.Equals (y) == Benar, kode hash mereka harus sama. Java menetapkan metode EQAULS dan metode kode hashcode sebagai berikut: (1) Jika dua objek sama (Equals Metode mengembalikan true), maka nilai kode hash mereka harus sama; (2) Jika kode hash dari kedua objek itu sama, mereka tidak harus sama. Tentu saja, Anda tidak perlu melakukan sesuai kebutuhan, tetapi jika Anda melanggar prinsip -prinsip di atas, Anda akan menemukan bahwa ketika menggunakan wadah, objek yang sama dapat muncul dalam koleksi yang ditetapkan, dan efisiensi penambahan elemen baru akan sangat berkurang (untuk sistem menggunakan penyimpanan hash, seringnya konflik dalam kode hash akan menyebabkan penurunan kinerja akses yang tajam).
Suplemen: Banyak program Java tahu tentang metode yang setara dan hashcode, tetapi banyak orang hanya mengetahuinya. Dalam karya agung Joshua Bloch "Java yang Efektif" (banyak perusahaan perangkat lunak, "Java yang efektif", "Pikiran Pemrograman Java" dan "Refactoring: Meningkatkan Kualitas Kode yang Ada" adalah buku yang harus dibaca oleh para programmer Java. Jika Anda belum membacanya, cepat-cepat, dan membeli satu di Amazon.) Ini adalah cara memperkenalkan metode yang sama. Benar), dan simetri (x.equals (y) mengembalikan true, y.Equals (x) juga harus mengembalikan true), transitivitas (x.Equals (y) dan y.Equals (z) juga mengembalikan true true) dan konsistensi (ketika informasi objek yang dirujuk oleh x dan y tidak dimodifikasi, beberapa panggilan ke x.equals (y) harus mendapatkan nilai pengembalian yang sama. Trik untuk mengimplementasikan metode setara berkualitas tinggi meliputi: 1. Gunakan operator == untuk memeriksa "apakah parameter tersebut merupakan referensi untuk objek ini"; 2. Gunakan instance dari operator untuk memeriksa "apakah parameter adalah tipe yang benar"; 3. Untuk atribut utama di kelas, periksa apakah atribut yang diteruskan ke objek mencocokkannya; 4. Setelah menulis metode yang sama, tanyakan pada diri sendiri apakah itu memenuhi simetri, transitivitas, dan konsistensi; 5. Selalu tulis kode hash saat menulis ulang sama dengan; 6. Jangan mengganti objek objek dalam parameter metode Equals dengan jenis lain, dan jangan lupa anotasi @Override saat menulis ulang.
17. Bisakah kelas string diwarisi?
Jawaban: Kelas string adalah kelas terakhir dan tidak dapat diwariskan.
Suplemen: Warisan string adalah perilaku yang salah dalam dirinya sendiri. Cara terbaik untuk menggunakan kembali tipe string adalah Association (HAS-A) daripada warisan (IS-A).
18. Ketika suatu objek dilewatkan sebagai parameter ke suatu metode, metode ini dapat mengubah sifat objek dan mengembalikan hasil yang diubah. Jadi apakah itu nilai pass atau lulus referensi di sini?
Jawaban: Ini adalah transfer nilai. Bahasa pemrograman Java hanya melewati parameter dengan nilai. Ketika instance objek diteruskan ke dalam metode sebagai parameter, nilai parameter adalah referensi ke objek. Properti suatu objek dapat diubah selama proses panggilan, tetapi referensi ke objek tidak akan pernah berubah. Dalam C ++ dan C#, nilai parameter yang ditularkan dapat diubah dengan lulus referensi atau mentransfer parameter.
Suplemen: Sangat tidak nyaman untuk tidak memberikan referensi di Java, yang belum ditingkatkan di Java 8. Justru dengan cara inilah sejumlah besar kelas pembungkus muncul dalam kode yang ditulis dalam Java (menempatkan referensi yang perlu dimodifikasi melalui panggilan metode ke dalam kelas pembungkus, dan kemudian meneruskan objek pembungkus ke dalam metode). Pendekatan ini hanya akan membuat kode membengkak, terutama untuk pengembang yang bertransformasi dari C ++ menjadi programmer Java menjadi tidak dapat ditoleransi.
19. Apa perbedaan antara String dan StringBuilder dan StringBuffer?
Jawaban: Platform Java menyediakan dua jenis string: String dan StringBuffer/StringBuilder, yang dapat menyimpan dan memanipulasi string. Di mana string adalah string hanya baca, yang berarti bahwa konten string yang dirujuk oleh string tidak dapat diubah. Objek String yang diwakili oleh kelas StringBuffer dan StringBuilder dapat dimodifikasi secara langsung. StringBuilder diperkenalkan di JDK 1.5. Ini persis sama dengan metode StringBuffer, perbedaannya adalah digunakan dalam lingkungan berulir tunggal karena semua aspeknya tidak dimodifikasi dengan disinkronkan, sehingga sedikit lebih efisien daripada StringBuffer.
Suplemen 1: Ada pertanyaan wawancara: Apakah ada situasi di mana menggunakan + untuk melakukan penggabungan string lebih baik daripada menyebut metode append dari objek StringBuffer/StringBuilder? Jika string yang diperoleh setelah koneksi sudah ada di area penyimpanan statis, maka menggunakan + untuk gabungan string lebih baik daripada metode append dari StringBuffer/StringBuilder.
Suplemen 2: Berikut ini juga merupakan pertanyaan wawancara, menanyakan output program untuk melihat apakah Anda dapat memberikan jawaban yang benar.
paket com.lovo; // Mengapa bertanya tentang hovertree. String b = string baru ("pemrograman"); String c = "Program" + "Ming"; System.out.println (a == b); System.out.println (a == C); System.out.println (A.Equals (b)); System.out.println (A.Equals (C)); System.out.println (a.intern () == B.Intern ()); }}20. Perbedaan antara kelebihan beban dan override. Dapatkah metode yang kelebihan beban dibedakan berdasarkan jenis pengembalian?
Jawaban: Kedua metode yang berlebihan dan penulisan ulang adalah cara untuk mengimplementasikan polimorfisme. Perbedaannya adalah bahwa yang pertama mengimplementasikan polimorfisme waktu yang dikompilasi, sedangkan yang terakhir mengimplementasikan polimorfisme run-time. Kelebihan terjadi di kelas. Jika metode dengan nama yang sama memiliki daftar parameter yang berbeda (jenis parameter yang berbeda, jumlah parameter yang berbeda, atau keduanya), itu dianggap kelebihan beban; Penulisan ulang terjadi antara subkelas dan kelas induk. Penulisan ulang mensyaratkan bahwa metode penulisan ulang subkelas dan kelas induk memiliki tipe pengembalian yang sama dengan metode penulisan ulang kelas induk, yang merupakan akses yang lebih baik daripada metode penulisan ulang kelas induk, dan tidak dapat menyatakan lebih banyak pengecualian daripada metode penulisan ulang kelas induk (prinsip substitusi Rischer). Kelebihan beban tidak memiliki persyaratan khusus untuk jenis pengembalian.
Suplemen: Huawei pernah mengajukan pertanyaan dalam pertanyaan wawancara: Mengapa Anda tidak dapat membedakan kelebihan beban berdasarkan jenis pengembalian dan memberi tahu jawaban Anda!
21. Jelaskan prinsip dan mekanisme file kelas pemuatan JVM?
Jawaban: Pemuatan kelas di JVM diimplementasikan oleh class loader (ClassLoader) dan subclass -nya. Loader kelas di Java adalah komponen sistem runtime Java yang penting, yang bertanggung jawab untuk menemukan dan memuat kelas di file kelas saat runtime.
Mengisi kembali:
1. Karena sifat cross-platform dari Java, program sumber Java yang dikompilasi bukanlah program yang dapat dieksekusi, tetapi satu atau lebih file kelas. Ketika program Java perlu menggunakan kelas, JVM memastikan bahwa kelas telah dimuat, terhubung (diverifikasi, disiapkan dan diuraikan) dan diinisialisasi. Pemuatan kelas mengacu pada membaca data dari file kelas .class ke dalam memori. Biasanya, membuat array byte untuk membacanya ke dalam file .class, dan kemudian menghasilkan objek kelas yang sesuai dengan kelas yang dimuat. Setelah pemuatan selesai, objek kelas masih belum lengkap, sehingga kelas tidak tersedia saat ini. Saat kelas dimuat, ia memasuki tahap koneksi. Tahap ini mencakup tiga langkah: verifikasi, persiapan (mengalokasikan memori untuk variabel statis dan mengatur nilai awal default) dan parsing (ganti referensi simbol dengan referensi langsung). Akhirnya, JVM menginisialisasi kelas, termasuk: 1. Jika kelas memiliki kelas induk langsung dan kelas belum diinisialisasi, maka kelas induk akan diinisialisasi terlebih dahulu; 2. Jika ada pernyataan inisialisasi di kelas, pernyataan inisialisasi ini akan dieksekusi secara bergantian.
2. Pemuatan kelas dilakukan oleh class loader, yang meliputi: root loader (bootstrap), ekstensi loader (ekstensi), pemuat sistem (sistem) dan class loader yang ditentukan pengguna (subclass dari java.lang.classloader). Mulai dari JDK 1.2, proses pemuatan kelas mengadopsi mekanisme delegasi ayah (PDM). PDM lebih baik memastikan keamanan platform Java. Dalam mekanisme ini, bootstrap JVM sendiri adalah root loader, dan loader lainnya memiliki dan hanya memiliki satu loader kelas induk. Pemuatan kelas pertama meminta pemuat kelas induk untuk memuat, dan loader kelas induk hanya akan dimuat oleh loader subkelasnya saat tidak berdaya. JVM tidak memberikan referensi untuk program Bootstrap ke Java. Berikut adalah beberapa instruksi untuk beberapa loader kelas:
A) Bootstrap: Secara umum diimplementasikan menggunakan kode lokal dan bertanggung jawab untuk memuat pustaka kelas inti dasar JVM (RT.Jar);
b) Ekstensi: Muat pustaka kelas dari direktori yang ditentukan oleh properti sistem java.ext.dirs, dan loader induknya adalah bootstrap;
C) Sistem: Juga dikenal sebagai loader kelas aplikasi, kelas induknya adalah ekstensi. Ini adalah loader kelas yang paling banyak digunakan. Ini mencatat kelas-kelas dari direktori yang ditentukan oleh variabel lingkungan ClassPath atau atribut sistem java.class.path, dan merupakan loader induk default dari loader yang ditentukan pengguna.
22. Bisakah karakter Cina disimpan dalam variabel tipe char? Mengapa?
Jawaban: Jenis char dapat menyimpan karakter Cina, karena pengkodean yang digunakan dalam java adalah unicode (tidak ada pengkodean spesifik yang dipilih, dan karakter secara langsung digunakan dalam nomor set karakter, yang merupakan satu -satunya metode terpadu). Jenis arang memakan 2 byte (16bit), jadi tidak masalah untuk menempatkan orang Cina.
Suplemen: Menggunakan Unicode berarti bahwa karakter memiliki manifestasi yang berbeda di dalam dan di luar JVM, dan keduanya unicode di dalam JVM. Ketika karakter ini ditransfer dari JVM ke luar (misalnya, disimpan dalam sistem file), diperlukan konversi pengkodean. Oleh karena itu, Java memiliki aliran byte dan aliran karakter, serta aliran konversi yang mengonversi antara aliran karakter dan aliran byte, seperti inputStreamReader dan outputStreamReader. Kedua kelas ini adalah kelas adaptor antara aliran byte dan aliran karakter, dan melakukan tugas pengkodean konversi; Untuk programmer C, untuk menyelesaikan konversi pengkodean tersebut, mereka mungkin mengandalkan karakteristik serikat pekerja (Union/Komunitas) untuk dicapai.
23. Apa persamaan dan perbedaan antara kelas abstrak dan antarmuka?
Jawaban: Baik kelas abstrak dan antarmuka tidak dapat dipakai, tetapi referensi ke kelas abstrak dan tipe antarmuka dapat didefinisikan. Jika kelas mewarisi kelas abstrak atau mengimplementasikan antarmuka, ia perlu menerapkan semua metode abstrak di dalamnya, jika tidak, kelas masih perlu dinyatakan sebagai kelas abstrak. Antarmuka lebih abstrak daripada kelas abstrak, karena konstruktor dapat didefinisikan dalam kelas abstrak, dan dapat ada metode abstrak dan metode konkret, sementara konstruktor tidak dapat didefinisikan dalam antarmuka, dan semua metode di dalamnya adalah metode abstrak. Anggota dalam kelas abstrak dapat bersifat pribadi, default, dilindungi, dan publik, sedangkan anggota dalam antarmuka semuanya bersifat publik. Variabel anggota dapat didefinisikan dalam kelas abstrak, sedangkan variabel anggota yang didefinisikan dalam antarmuka sebenarnya adalah konstanta. Kelas dengan metode abstrak harus dinyatakan sebagai kelas abstrak, dan kelas abstrak tidak selalu memiliki metode abstrak.
24. Apa perbedaan antara kelas bersarang statis dan kelas dalam (kelas dalam)?
Jawaban: Static Nested Class adalah kelas dalam yang dinyatakan statis, yang dapat dipakai tanpa mengandalkan contoh kelas eksternal. Kelas dalam yang biasa perlu dipakai setelah kelas eksternal dipakai, dan sintaksnya terlihat cukup aneh, seperti yang ditunjukkan di bawah ini.
paket com.lovo; / ** * Kelas poker (setumpuk poker) Mengapa bertanya tentang hovertree.com * */ kelas publik poker {private static string [] suite = {"spade", "rose", "rumput bunga", "kubus"}; private static int [] wajah = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; kartu pribadi [] kartu; / *** konstruktor**/ poker publik () {cards = kartu baru [52]; untuk (int i = 0; i <suites.length; i ++) {for (int j = 0; j <faces.length; j ++) {kartu [i * 13+j] = kartu baru (suite [i], wajah [j]); }}} / ** * shuffle (acak di luar urutan) * * / public void shuffle () {for (int i = 0, len = cards.length; i <len; i ++) {int index = (int) (math.random () * len); Kartu temp = kartu [indeks]; kartu [indeks] = kartu [i]; kartu [i] = temp; }} / *** kesepakatan kartu* @param indeks posisi kesepakatan** / kesepakatan kartu publik (indeks int) {kartu pengembalian [indeks]; } / ** * kelas kartu (sepotong poker) * [kelas internal] * @author luo hao * * / kartu kelas publik {private string suite; // Sesuai dengan wajah int pribadi; // poin kartu publik (string suite, int face) {this.suite = suite; this.face = wajah; } @Override Public String ToString () {String facestr = ""; sakelar (wajah) {case 1: facestr = "a"; merusak; Kasus 11: facestr = "j"; merusak; Kasus 12: facestr = "q"; merusak; Kasus 13: Facestr = "K"; merusak; default: facestr = string.valueof (face); } return suite + facestr; }}} Kelas Tes:
paket com.lovo; kelas pokertest {public static void main (string [] args) {poker poker = new poker (); poker.shuffle (); // shuffle poker.card c1 = poker.deal (0); // Melayani kartu pertama // untuk kartu kelas internal non-statis // objek kartu dapat dibuat hanya melalui kelas eksternal objek poker poker.card c2 = poker.new card ("red heart", 1); // Buat kartu sendiri System.out.println (C1); // System.out.println (C2) pertama; // Cetak: Red Heart A}} // Mengapa bertanya tentang hovertree.com25. Apakah akan ada kebocoran memori di Java? Jelaskan secara singkat.
Jawaban: Secara teori, Java tidak akan memiliki kebocoran memori karena memiliki mekanisme pengumpulan sampah (GC) (ini juga merupakan alasan penting mengapa Java banyak digunakan dalam pemrograman sisi server); Namun, dalam pengembangan aktual, mungkin ada objek yang tidak berguna tetapi dapat diakses, dan objek ini tidak dapat didaur ulang oleh GC dan kebocoran memori akan terjadi. Contohnya adalah bahwa objek dalam sesi Hibernate (level satu cache) persisten, dan pengumpul sampah tidak akan mendaur ulang objek ini, tetapi mungkin ada objek sampah yang tidak berguna di objek ini. Contoh berikut juga menunjukkan kebocoran memori di Java:
paket com.lovo; // Mengapa bertanya tentang hovertree.comImport java.util.arrays; impor java.util.emptttackException; elemen kelas publik mystack <t> {private t []; Ukuran int pribadi = 0; private static int int init_capacity = 16; public mystack () {elements = (t []) objek baru [init_capacity]; } public void push (t elem) {ensureCapacity (); elemen [ukuran ++] = elem; } public t pop () {if (size == 0) Lempar baru kosongStackException (); elemen pengembalian [-ukuran]; } private void ensureCapacity() { if(elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); }}}上面的代码实现了一个栈(先进后出(FILO))结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试。然而其中的pop方法却存在内存泄露的问题,当我们用pop方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,因为栈内部维护着对这些对象的过期引用(obsolete reference)。在支持垃圾回收的语言中,内存泄露是很隐蔽的,这种内存泄露其实就是无意识的对象保持。如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响,极端情况下会引发Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成OutOfMemoryError。
26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
27、静态变量和实例变量的区别?
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。在Java开发中,上下文类和工具类中通常会有大量的静态成员。
28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,因此在调用静态方法时可能对象并没有被初始化。
29、如何实现对象克隆?
答:有两种方式:
1.实现Cloneable接口并重写Object类中的clone()方法;
2.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下。
package com.lovo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class MyUtil { private MyUtil() { throw new AssertionError(); } public static <T> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源} } //何问起hovertree.com下面是测试代码:
package com.lovo; import java.io.Serializable; /** * Human* @author Luo Hao* */ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // Name private int age; // Age private Car car; // Car public Person(String name, int age, Car car) { this.name = name; this.age = usia; this.car = car; } public string getName () {return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } } /** * Car class* @author Luo Hao* */ class Car implements Serializable { private static final long serialVersionUID = -5713945027627603702L; private String brand; // Brand private int maxSpeed; // Top speed public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; } } //Why ask about hovertree.comclass CloneTest { public static void main(String[] args) { try { Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300)); Person p2 = MyUtil.clone(p1); // Deep cloning p2.getCar().setBrand("BYD"); // Modify the brand attributes of the cloned Person object p2-associated car object// The original Person object p1-associated car will not be affected in any way// Because when cloning Person object, the car object associated with it is also cloned System.out.println(p1); } catch (Exception e) {E.PrintStackTrace (); }}}注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。
30、GC 是什么?为什么要有GC?
答: GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
与垃圾回收相关的JVM参数:
-Xms / -Xmx --- 堆的初始大小/ 堆的最大大小
-Xmn --- 堆中年轻代的大小
-XX:-DisableExplicitGC --- 让System.gc()不产生任何作用
-XX:+PrintGCDetail --- 打印GC的细节
-XX:+PrintGCDateStamps --- 打印GC操作的时间戳
31、String s=new String(“xyz”);创建了几个字符串对象?
答:两个对象,一个是静态存储区的"xyz",一个是用new创建在堆上的对象。
32、接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?
答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
33、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
答:可以,但一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。
34、Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?
答:可以继承其他类或实现其他接口,在Swing编程中常用此方式来实现事件监听和回调。
35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。
36、Java 中的final关键字有哪些用法?
答: (1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
37、指出下面程序的运行结果:
class A{ static{ System.out.print("1"); } public A(){ System.out.print("2"); } } class B extends A{ static{ System.out.print("a"); } public B(){ System.out.print("b"); } } //Why ask about hovertree.compublic class Hello{ public static void main(String[] args){ A ab = new B(); ab = new B(); }}答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。
38、数据类型之间的转换:
1)如何将字符串转换为基本数据类型?
2)如何将基本数据类型转换为字符串?
menjawab:
1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf(…)方法返回相应字符串
39、如何实现字符串的反转及替换?
答:方法很多,可以自己写实现也可以使用String或StringBuffer / StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:
public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr; return reverse(originStr.substring(1)) + originStr.charAt(0); } //何问起hovertree.com40、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?
答:代码如下所示:
String s1 = "你好";String s2 = newString(s1.getBytes("GB2312"), "ISO-8859-1");41、日期和时间:
1)如何取得年月日、小时分钟秒?
2)如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
3)如何取得某月的最后一天?
4)如何格式化日期?
答:操作方法如下所示:
1)创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值
2)以下方法均可获得该毫秒数:
Calendar.getInstance().getTimeInMillis(); System.currentTimeMillis(); //何问起hovertree.com
3)示例代码如下:
Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH); //何问起hovertree.com
4)利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。
42、打印昨天的当前时刻。
menjawab:
public class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); } } //何问起hovertree.com43、比较一下Java 和JavaSciprt。
答: JavaScript 与Java是两个公司开发的不同的两个产品。Java 是原Sun 公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而JavaScript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入Web页面中运行的基于对象和事件驱动的解释性语言,它的前身是LiveScript;而Java 的前身是Oak语言。
下面对两种语言间的异同作如下比较:
1)基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言。因而它本身提供了非常丰富的内部对象供设计人员使用;
2)解释和编译:Java 的源代码在执行之前,必须经过编译;JavaScript 是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行;
3)强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量声明,采用其弱类型。即变量在使用前不需作声明,而是解释器在运行时检查其数据类型;
4)代码格式不一样。
补充:上面列出的四点是原来所谓的标准答案中给出的。其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言。目前的编程语言的发展趋势是函数式语言和动态语言。在Java中类(class)是一等公民,而JavaScript中函数(function)是一等公民。对于这种问题,在面试时还是用自己的语言回答会更加靠谱。
44、什么时候用assert?
答: assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后, assertion检查通常是关闭的。在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式计算为false,那么系统会报告一个AssertionError。
断言用于调试目的:
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两种形式:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。
断言在默认情况下是禁用的,要在编译时启用断言,需使用source 1.4 标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用-enableassertions 或者-ea 标记。
要在运行时选择禁用断言,可使用-da 或者-disableassertions 标记。
要在系统类中启用断言,可使用-esa 或者-dsa 标记。还可以在包的基础上启用或者禁用断言。可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。
45、Error 和Exception 有什么区别?
答: Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
Supplement: During the interview with Motorola in 2005, I asked a question like "If a process reports a stack overflow run-time error, what's the most possible cause?", giving four options a. lack of memory; B. write on an invalid memory space; C. recursive function calling; D. array index out of boundary. Java programs may also encounter StackOverflowError when running. This is an error that cannot be recovered, so I can only re-modify the code. The answer to this interview question is c. If you write recursion that cannot converge quickly, it is very likely to cause a stack overflow error, as shown below:
package com.lovo; public class StackOverflowErrorTest { public static void main(String[] args) { main(null); } } //何问起hovertree.com因此,用递归编写程序时一定要牢记两点:1. 递归公式;2. 收敛条件(什么时候就不再递归而是回溯了)。
46、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
答:会执行,在方法返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法上规定不能做这样的事。
47、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答: Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java 中,每个异常都是一个对象,它是Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java 的异常处理是通过5 个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;try用来指定一块预防所有“异常”的程序;catch 子句紧跟在try块后面,用来指定你想要捕捉的“异常”的类型;throw 语句用来明确地抛出一个“异常”;throws用来标明一个成员函数可能抛出的各种“异常”;finally 为确保一段代码不管发生什么“异常”都被执行一段代码;可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try 语句,“异常”的框架就放到栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的try 语句。
48、运行时异常与受检异常有何异同?
答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,神作《Effective Java》中对异常的使用给出了以下指导原则:
不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
对可以恢复的情况使用受检异常,对编程错误使用运行时异常避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
优先使用标准的异常每个方法抛出的异常都要有文档保持异常的原子性不要在catch中忽略掉捕获到的异常
49、列出一些你常见的运行时异常?
menjawab:
ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下表越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)
50、final, finally, finalize 的区别?
答: final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final 的方法也同样只能使用,不能在子类中被重写。finally:通常放在try…catch的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。
Di atas adalah semua konten artikel ini. I hope it will be helpful to everyone in the Java interview, and I hope everyone will support Wulin.com more.