JavaRush /Blog Java /Random-MS /10 perkara yang anda tidak tahu tentang Java
minuteman
Tahap

10 perkara yang anda tidak tahu tentang Java

Diterbitkan dalam kumpulan
Jadi, adakah anda baru-baru ini mula bekerja dengan Java? Ingat hari-hari apabila ia dipanggil "Oak", apabila orientasi objek masih menjadi topik hangat, apabila orang C++ menganggap Java tidak mempunyai peluang, dan apabila tiada siapa yang pernah mendengar tentang applet? Saya boleh menganggap bahawa anda tidak tahu separuh daripada perkara berikut. Mari mulakan minggu ini dengan beberapa kejutan hebat tentang kerja dalaman Java. 10 perkara yang anda tidak tahu tentang Java - 11. Tiada perkara seperti pengecualian yang diperiksa. betul! JVM tidak tahu tentang perkara sedemikian, hanya bahasa Java sahaja. Hari ini semua orang bersetuju bahawa pengecualian yang disemak adalah satu kesilapan. Seperti yang dikatakan Bruce Eckel dalam ceramah terakhirnya di GeeCON di Prague, tiada bahasa lain sejak Java menggunakan pengecualian yang diperiksa, malah Java 8 tidak lagi meliputinya dalam API Aliran baharu (yang boleh menjadi sedikit gangguan apabila lambdas anda menggunakan IO atau JDBC ). Adakah anda mahu bukti bahawa JVM tidak mengetahui perkara sedemikian? Cuba kod berikut: Bukan sahaja ini akan dikompil, ia juga akan membuang SQLException, anda bahkan tidak perlu menggunakan @SneakyThrows Lombok untuk ini. 2. Anda boleh mempunyai kaedah terlebih beban yang berbeza hanya dalam jenis pulangannyapublic class Test { // No throws clause here public static void main(String[] args) { doThrow(new SQLException()); } static void doThrow(Exception e) { Test. doThrow0(e); } @SuppressWarnings("unchecked") static void doThrow0(Exception e) throws E { throw (E) e; } } Ini tidak akan disusun, bukan? class Test { Object x() { return "abc"; } String x() { return "123"; } } Betul. Bahasa Java tidak membenarkan dua kaedah ditindih secara setara dalam kelas yang sama pada masa yang sama, tanpa mengira perbezaannya dalam jenis lontaran atau pengembalian. Tapi tunggu sekejap. Semak dokumentasi sekali lagi untuk Class.getMethod(String, Class…). Ia berkata: Ambil perhatian bahawa ada kemungkinan terdapat lebih daripada satu kaedah yang sepadan dalam kelas, kerana walaupun bahasa Java melarang berbilang kaedah dengan tandatangan yang sama tetapi jenis pulangan yang berbeza, Mesin Maya Java tidak. Fleksibiliti dalam mesin maya ini boleh digunakan untuk melaksanakan pelbagai ciri bahasa. Sebagai contoh, pulangan kovarian boleh dilakukan dengan kaedah jambatan; Kaedah jambatan dan kaedah yang ditindih akan mempunyai tandatangan yang sama tetapi jenis pulangan yang berbeza. Wah, masuk akal. Sebenarnya banyak perkara yang berlaku apabila anda menulis perkara berikut: Lihat kod bait yang dijana: Jadi t sebenarnya adalah objek dalam kod bait. Ini difahami dengan baik. Kaedah jambatan sintetik sebenarnya dijana oleh pengkompil kerana jenis pemulangan Parent.x() boleh dijangka pada bahagian tertentu panggilan. Menambah generik tanpa kaedah jambatan sedemikian tidak lagi boleh dilakukan dalam perwakilan binari. Jadi, menukar JVM untuk membenarkan ciri sedemikian menghasilkan kesakitan yang kurang (yang juga membenarkan kaedah kovarian mengatasi sebagai kesan sampingan...) Pintar betul? 3. Semua yang berikut ialah tatasusunan dua dimensi. Ini sebenarnya benar. Walaupun penganalisis mental anda tidak dapat memahami dengan segera jenis pulangan daripada kaedah yang diterangkan di atas, semuanya adalah sama! Seperti sekeping kod seterusnya. Adakah anda fikir ini gila? Bilangan peluang untuk menulis juga hanya meletupkan imaginasi! Taip anotasi. Peranti yang misterinya kedua selepas kuasanya. Atau dengan kata lain: Apabila saya membuat komitmen terakhir saya sebelum cuti 4 minggu saya. Saya memberi anda kebenaran untuk menggunakannya dalam apa jua cara yang anda suka. 4. Anda tidak akan mendapat bersyarat Jadi, anda fikir anda sudah tahu segala-galanya tentang syarat apabila anda mula menggunakannya? Biar saya kecewakan awak - awak silap. Kebanyakan anda akan berfikir bahawa dua contoh berikut adalah setara: bersamaan dengan ini? Tidak. Mari gunakan ujian cepat Program ini akan mengeluarkan yang berikut: Ya! Operator bersyarat akan melakukan hantaran jenis jika perlu. Kerana jika tidak, anda akan mengharapkan program itu membuang NullPointerException? 5. Anda juga tidak akan mendapat pengendali tugasan kompaun. Adakah kepintaran cukup? Mari lihat dua coretan kod berikut: abstract class Parent { abstract T x(); } class Child extends Parent { @Override String x() { return "abc"; } } // Method descriptor #15 ()Ljava/lang/String; // Stack: 1, Locals: 1 java.lang.String x(); 0 ldc [16] 2 areturn Line numbers: [pc: 0, line: 7] Local variable table: [pc: 0, pc: 3] local: this index: 0 type: Child // Method descriptor #18 ()Ljava/lang/Object; // Stack: 1, Locals: 1 bridge synthetic java.lang.Object x(); 0 aload_0 [this] 1 invokevirtual Child.x() : java.lang.String [19] 4 areturn Line numbers: [pc: 0, line: 1] class Test { int[][] a() { return new int[0][]; } int[] b() [] { return new int[0][]; } int c() [][] { return new int[0][]; } } class Test { int[][] a = {{}}; int[] b[] = {{}}; int c[][] = {{}}; } @Target(ElementType.TYPE_USE) @interface Crazy {} class Test { @Crazy int[][] a1 = {{}}; int @Crazy [][] a2 = {{}}; int[] @Crazy [] a3 = {{}}; @Crazy int[] b1[] = {{}}; int @Crazy [] b2[] = {{}}; int[] b3 @Crazy [] = {{}}; @Crazy int c1[][] = {{}}; int c2 @Crazy [][] = {{}}; int c3[] @Crazy [] = {{}}; } 10 perkara yang anda tidak tahu tentang Java - 2 Object o1 = true ? new Integer(1) : new Double(2.0); Object o2; if (true) o2 = new Integer(1); else o2 = new Double(2.0); System.out.println(o1); System.out.println(o2); 1.0 1 Integer i = new Integer(1); if (i.equals(1)) i = null; Double d = new Double(2.0); Object o = true ? i : d; // NullPointerException! System.out.println(o); i += j; i = i + j; Secara intuitif, mereka sepatutnya sama, bukan? Tetapi anda tahu apa - mereka berbeza. Spesifikasi JLS mengatakan: Ungkapan majmuk jenis E1 op = E2 adalah bersamaan dengan E1 = (T) ((E1) op (E2)), dengan T ialah jenis E1, kecuali E1 dinilai sekali sahaja. Contoh yang baik ialah menggunakan *= atau /= : byte b = 10; b *= 5.7; System.out.println(b); // prints 57 atau: byte b = 100; b /= 2.5; System.out.println(b); // prints 40 atau: char ch = '0'; ch *= 1.1; System.out.println(ch); // prints '4' atau: char ch = 'A'; ch *= 1.5; System.out.println(ch); // prints 'a' Jadi, adakah ini masih alat yang berguna? 6. Integer rawak Sekarang untuk tugas yang lebih sukar. Jangan baca penyelesaiannya. Lihat jika anda boleh mencari jawapannya sendiri. Apabila saya menjalankan program berikut: for (int i = 0; i < 10; i++) { System.out.println((Integer) i); } Kadang-kadang saya mendapat output berikut: 92 221 45 48 236 183 39 193 33 84 Tetapi bagaimana ini mungkin? Ok, jawapannya terletak pada mengatasi cache Integer JDK melalui pantulan, dan kemudian menggunakan auto-tinju dan auto-nyahkotak. Jangan lakukan ini tanpa kebenaran orang dewasa! Atau dengan kata lain: 10 perkara yang anda tidak tahu tentang Java - 3 7. GOTO Salah satu kegemaran saya. Java mempunyai GOTO! Tulis ini: int goto = 1; dan anda mendapat ini: Itu kerana goto ialah perkataan terpelihara yang tidak digunakan, untuk berjaga-jaga... Tetapi itu bukan bahagian yang menarik. Perkara yang menarik ialah anda boleh memasukkan goto berpasangan dengan blok break, continue dan ditandai: Melompat ke hadapan Dalam kod bait: Melompat ke belakang Dalam kod bait: 8. Java mempunyai jenis alias Dalam bahasa lain (seperti Ceylon), kita boleh menentukan jenis alias sangat mudah: Kelas Orang di sini dibina dengan cara yang boleh ditukar ganti dengan Set Test.java:44: error: expected int goto = 1; ^ label: { // do stuff if (check) break label; // do more stuff } 2 iload_1 [check] 3 ifeq 6 // Jumping forward 6 .. label: do { // do stuff if (check) continue label; // do more stuff break label; } while(true); 2 iload_1 [check] 3 ifeq 9 6 goto 2 // Jumping backward 9 .. interface People => Set ; : Di Jawa, kita tidak boleh mentakrifkan alias di peringkat teratas. Tetapi kita boleh melakukan ini untuk keperluan kelas atau kaedah. Mari kita anggap bahawa kita tidak berpuas hati dengan nama seperti Integer, Long, dll. dan kami mahukan nama yang lebih pendek: I dan L. Mudah: Dalam contoh di atas, Integer ditukar kepada I untuk keterlihatan kelas Ujian, manakala Long ditukar kepada L untuk keperluan kaedah x(). Sekarang kita boleh memanggil kaedah ini seperti ini: Sudah tentu, teknik ini tidak boleh diambil serius. Dalam kes ini, Integer dan Long ialah jenis akhir, yang bermaksud bahawa I dan L ialah penukaran yang cekap (hampir, penukaran hanya berjalan sehala). Jika kami memutuskan untuk menggunakan jenis bukan akhir (contohnya Objek), maka kami boleh bertahan dengan generik biasa. Kami bermain sedikit dan itu sudah memadai. Mari kita beralih kepada sesuatu yang sangat menarik. 9. Beberapa jenis hubungan tidak dapat ditentukan! Okay, sekarang ini akan menjadi sangat menarik, jadi dapatkan secawan kopi pekat dan mari lihat dua jenis berikut: People? p1 = null; Set ? p2 = p1; People? p3 = p2; class Test { void x(I i, L l) { System.out.println( i.intValue() + ", " + l.longValue() ); } } new Test().x(1, 2L);// A helper type. You could also just use List interface Type {} class C implements Type > {} class D

implements Type >>> {} Jadi apakah maksud C dan D? Dari satu segi, ia adalah rekursif, sama dengan rekursi dalam java.lang.Enum. Pertimbangkan: Memandangkan spesifikasi di atas, pelaksanaan sebenar enum hanyalah gula sintaksis: Dengan itu, mari kembali kepada dua jenis kami. Adakah kod berikut akan disusun? Soalan yang sukar... dan ia sebenarnya tidak diselesaikan? Adakah C subjenis Jenis ? Cuba kumpulkan ini dalam Eclipse atau Idea anda dan mereka akan memberitahu anda apa yang mereka fikirkan. Siramkannya ke dalam longkang... Sesetengah jenis perhubungan di Jawa tidak dapat ditentukan! 10. Type Intersection Java mempunyai ciri yang sangat menarik iaitu type intersection. Anda boleh mengisytiharkan jenis (generik) yang sebenarnya merupakan persimpangan dua jenis. Contohnya: Parameter jenis tersuai T yang anda kaitkan dengan kejadian kelas Ujian mesti termasuk antara muka Boleh Bersiri dan Boleh Diklon. Sebagai contoh, String tidak boleh dihadkan, tetapi Tarikh boleh: Ciri ini mempunyai berbilang kegunaan dalam Java8, di mana anda boleh menghantar jenis. Bagaimanakah ini membantu? Hampir tiada, tetapi jika anda ingin menghantar ungkapan lambda anda ke dalam jenis yang anda perlukan, maka tiada cara lain. Katakan anda mempunyai had yang gila dalam kaedah anda: Anda mahu Runnable yang pada masa yang sama boleh Serializable hanya jika anda mahu melaksanakannya di tempat lain dan menghantar hasilnya melalui rangkaian. Lambda dan bersiri menambah sedikit ironi. Anda boleh mensirikan ungkapan lambda anda jika jenis sasaran dan hujahnya boleh bersiri. Tetapi walaupun ini benar, mereka tidak mendayakan antara muka Serializable secara automatik. Anda mesti membawa mereka ke jenis ini sendiri. Tetapi apabila anda menghantar hanya ke Serializable: maka lambda tidak lagi boleh Runnable, jadi hantarkannya ke kedua-dua jenis: Dan sebagai kesimpulan: public abstract class Enum > { ... } // This enum MyEnum {} // Is really just sugar for this class MyEnum extends Enum { ... } class Test { Type c = new C(); Type> d = new D (); } Step 0) C Step 1) Type > >? Step 0) D > Step 1) Type >>> > Step 2) D >> Step 3) List >> > Step 4) D > >> Step . . . (expand forever) class Test { } // Doesn't compile Test s = null; // Compiles Test d = null; void execute(T t) {} execute((Serializable) (() -> {}));execute((Runnable & Serializable) (() -> {}));

Java adalah sama berkuasa kerana ia misteri.

Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION