JavaRush /Java Blog /Random-TL /10 bagay na hindi mo alam tungkol sa Java
minuteman
Antas

10 bagay na hindi mo alam tungkol sa Java

Nai-publish sa grupo
Kaya, nagsimula ka na bang magtrabaho sa Java kamakailan? Alalahanin ang mga araw na tinawag itong "Oak", kung kailan mainit na paksa pa rin ang object-orientation, noong inakala ng mga taong C++ na walang pagkakataon ang Java, at noong wala pang nakarinig ng mga applet? Maaari kong ipagpalagay na hindi mo alam ang kalahati ng mga sumusunod na bagay. Simulan natin ang linggo na may ilang mga cool na sorpresa tungkol sa mga panloob na gawain ng Java. 10 bagay na hindi mo alam tungkol sa Java - 11. Walang naka-check na exception. Tama iyan! Ang JVM ay walang ideya tungkol sa isang bagay, tanging ang wikang Java lamang ang nakakaalam. Ngayon, lahat ay sumasang-ayon na ang mga nasuri na pagbubukod ay isang pagkakamali. Gaya ng sinabi ni Bruce Eckel sa kanyang huling pag-uusap sa GeeCON sa Prague, wala nang ibang wika dahil gumagamit ang Java ng may check na exception, kahit na ang Java 8 ay hindi na sumasaklaw sa mga ito sa bagong Streams API (na maaaring maging isang istorbo kapag ang iyong mga lambdas ay gumagamit ng IO o JDBC ). Gusto mo ba ng patunay na hindi alam ng JVM ang ganoong bagay? Subukan ang sumusunod na code: Hindi lamang ito mag-compile, magtapon din ito ng SQLException, hindi mo na kailangang gumamit ng @SneakyThrows ng Lombok para dito. 2. Maaari kang magkaroon ng mga overloaded na pamamaraan na naiiba lamang sa kanilang mga uri ng pagbabalikpublic 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; } } Hindi ito mag-compile, tama ba? class Test { Object x() { return "abc"; } String x() { return "123"; } } Tama. Ang wikang Java ay hindi pinapayagan ang dalawang pamamaraan na ma-overridden nang pantay-pantay sa loob ng parehong klase sa parehong oras, anuman ang kanilang mga pagkakaiba sa mga throws o return type. Pero sandali lang. Suriin muli ang dokumentasyon para sa Class.getMethod(String, Class…). Sinasabi nito: Tandaan na posibleng mayroong higit sa isang kaukulang pamamaraan sa isang klase, dahil habang ipinagbabawal ng wikang Java ang maraming pamamaraan na may parehong lagda ngunit magkaibang uri ng pagbabalik, ang Java Virtual Machine ay hindi. Ang kakayahang umangkop na ito sa isang virtual machine ay maaaring gamitin upang ipatupad ang iba't ibang mga tampok ng wika. Halimbawa, ang mga covariant return ay maaaring gawin sa mga pamamaraan ng tulay; Ang paraan ng tulay at ang na-override na paraan ay magkakaroon ng parehong lagda ngunit magkaibang mga uri ng pagbabalik. Wow, may katuturan iyon. Marami talagang nangyayari kapag isinulat mo ang sumusunod: Tingnan ang nabuong bytecode: Kaya t ay talagang isang bagay sa bytecode. Ito ay lubos na naiintindihan. Ang synthetic bridge method ay aktwal na nabuo ng compiler dahil ang return type ng Parent.x() ay maaaring asahan sa ilang bahagi ng mga tawag. Ang pagdaragdag ng mga generic na walang ganitong paraan ng tulay ay hindi na posible sa binary na representasyon. Kaya, ang pagpapalit ng JVM upang payagan ang naturang tampok ay gumawa ng mas kaunting sakit (na nagpapahintulot din sa covariant na paraan ng overriding bilang isang side effect...) Matalino tama? 3. Ang lahat ng sumusunod ay dalawang-dimensional na array. Ito ay talagang totoo. Kahit na hindi agad maunawaan ng iyong mental analyzer ang uri ng pagbabalik mula sa mga pamamaraan na inilarawan sa itaas, pareho silang lahat! Tulad ng susunod na piraso ng code. Sa tingin mo ito ay baliw? Ang dami ng pagkakataong magsulat ay sumasabog din sa imahinasyon! I-type ang anotasyon. Isang aparato na ang misteryo ay pangalawa lamang sa kapangyarihan nito. O sa madaling salita: Kapag ginawa ko ang aking huling pangako bago ang aking 4 na linggong bakasyon. Binibigyan kita ng pahintulot na gamitin ito sa anumang paraan na gusto mo. 4. Hindi ka makakakuha ng kondisyon Kaya, naisip mo na alam mo na ang lahat tungkol sa mga kondisyon noong sinimulan mong gamitin ang mga ito? Hayaan mong biguin kita - nagkamali ka. Iisipin ng karamihan sa inyo na ang sumusunod na dalawang halimbawa ay katumbas: katumbas nito? Hindi. Gumamit tayo ng mabilisang pagsubok Ilalabas ng programa ang sumusunod: Oo! Ang conditional operator ay magsasagawa ng mga uri ng cast kung kinakailangan. Dahil kung hindi, inaasahan mong maghagis ang programa ng NullPointerException? 5. Hindi ka rin makakakuha ng compound assignment operator. Sapat na ba ang pagiging maparaan? Tingnan natin ang sumusunod na dalawang snippet ng code: 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 bagay na hindi mo alam tungkol sa 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; Intuitively, dapat magkapantay sila diba? Ngunit alam mo kung ano - magkaiba sila. Ang detalye ng JLS ay nagsasabing: Ang isang tambalang expression ng uri E1 op = E2 ay katumbas ng E1 = (T) ((E1) op (E2)), kung saan ang T ay ang uri ng E1, maliban na ang E1 ay sinusuri nang isang beses lamang. Ang isang magandang halimbawa ay ang paggamit ng *= o /= : byte b = 10; b *= 5.7; System.out.println(b); // prints 57 o: byte b = 100; b /= 2.5; System.out.println(b); // prints 40 o: char ch = '0'; ch *= 1.1; System.out.println(ch); // prints '4' o: char ch = 'A'; ch *= 1.5; System.out.println(ch); // prints 'a' Kaya, ito pa rin ba ay isang kapaki-pakinabang na tool? 6. Random na mga integer Ngayon para sa isang mas mahirap na gawain. Huwag basahin ang solusyon. Tingnan kung mahahanap mo ang sagot sa iyong sarili. Kapag pinapatakbo ko ang sumusunod na programa: for (int i = 0; i < 10; i++) { System.out.println((Integer) i); } Minsan nakukuha ko ang sumusunod na output: 92 221 45 48 236 183 39 193 33 84 Ngunit paano ito posible? Ok, ang sagot ay nakasalalay sa pag-override sa Integer cache ng JDK sa pamamagitan ng pagmuni-muni, at pagkatapos ay gamit ang auto-boxing at auto-unboxing. Huwag gawin ito nang walang pahintulot ng nasa hustong gulang! O sa madaling salita: 10 bagay na hindi mo alam tungkol sa Java - 3 7. GOTO Isa sa mga paborito ko. May GOTO ang Java! Isulat ito: int goto = 1; at nakuha mo ito: Iyon ay dahil ang goto ay isang hindi nagamit na nakalaan na salita, kung sakali... Ngunit hindi iyon ang kapana-panabik na bahagi. Ang cool na bagay ay maaari mong isama ang goto na ipinares sa break, magpatuloy at minarkahang mga bloke: Paglukso pasulong Sa byte code: Paglukso pabalik Sa byte code: 8. Ang Java ay may mga alias ng uri Sa ibang mga wika (tulad ng Ceylon), maaari nating tukuyin ang uri napakadali ng mga alias: Ang klase ng Mga Tao dito ay binuo sa paraang maaari itong ipagpalit sa isang 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 ; : Sa Java, hindi natin basta-basta matukoy ang isang alias sa pinakamataas na antas. Ngunit magagawa natin ito para sa mga pangangailangan ng isang klase o pamamaraan. Ipagpalagay natin na hindi tayo nasisiyahan sa mga pangalan tulad ng Integer, Long, atbp. at gusto namin ng mas maiikling pangalan: I at L. Madali: Sa halimbawa sa itaas, ang Integer ay kino-convert sa I para sa visibility ng Test class, habang ang Long ay na-convert sa L para sa mga pangangailangan ng x() method. Ngayon ay maaari nating tawaging ganito ang pamamaraang ito: Siyempre, hindi dapat seryosohin ang pamamaraang ito. Sa kasong ito, ang Integer at Long ay mga panghuling uri, na nangangahulugan na ang I at L ay mahusay na mga conversion (halos, ang conversion ay napupunta lamang sa isang paraan). Kung nagpasya kaming gumamit ng mga hindi pangwakas na uri (halimbawa, Object), pagkatapos ay makakamit namin ang mga regular na generic. Naglaro kami ng kaunti at sapat na iyon. Lumipat tayo sa isang bagay na talagang kawili-wili. 9. Ang ilang uri ng mga relasyon ay hindi mapagpasyahan! Okay, ngayon ito ay magiging talagang kawili-wili, kaya kumuha ng isang tasa ng puro kape at tingnan natin ang sumusunod na dalawang uri: 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 >>> {} Kaya ano ang ibig sabihin ng C at D? Sa isang kahulugan sila ay recursive, katulad ng recursion sa java.lang.Enum. Isaalang-alang: Dahil sa mga pagtutukoy sa itaas, ang aktwal na pagpapatupad ng enum ay syntactic sugar lamang: Sa pag-iisip na iyon, bumalik tayo sa aming dalawang uri. Mag-iipon ba ang sumusunod na code? Isang mahirap na tanong... at hindi talaga ito nireresolba? Ang C ba ay isang subtype ng Uri ? Subukang i-compile ito sa iyong Eclipse o Idea at sasabihin nila sa iyo kung ano ang iniisip nila. I-flush ito sa alisan ng tubig... Ang ilang uri ng mga ugnayan sa Java ay hindi mapagpasyahan! 10. Uri ng Intersection Ang Java ay may isang napaka-kagiliw-giliw na tampok na tinatawag na uri ng intersection. Maaari kang magdeklara ng isang (generic) na uri na talagang intersection ng dalawang uri. Halimbawa: Ang custom na uri ng parameter na T na iniuugnay mo sa mga instance ng Test class ay dapat na kasama ang Serializable at Cloneable na mga interface. Halimbawa, hindi maaaring paghigpitan ang String, ngunit ang Petsa ay maaaring: Ang feature na ito ay maraming gamit sa Java8, kung saan maaari kang mag-cast ng mga uri. Paano ito nakakatulong? Halos wala, ngunit kung gusto mong i-cast ang iyong lambda expression sa uri na kailangan mo, wala nang ibang paraan. Sabihin nating mayroon kang napakabaliw na limitasyon sa iyong pamamaraan: Gusto mo ang Runnable na sa parehong oras ay Serializable lamang kung gusto mong isagawa ito sa ibang lugar at ipadala ang resulta sa network. Ang Lambda at serialization ay nagdaragdag ng kaunting kabalintunaan. Maaari mong i-serialize ang iyong lambda expression kung ang target na uri at argumento nito ay serializable. Ngunit kahit na ito ay totoo, hindi nila awtomatikong pinapagana ang Serializable na interface. Dapat mong dalhin sila sa ganitong uri ng iyong sarili. Ngunit kapag nag-cast ka lang sa Serializable: kung gayon ang lambda ay hindi na Runnable, kaya i-cast ang mga ito sa parehong uri: At bilang konklusyon: 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) (() -> {}));

Ang Java ay kasing lakas ng pagiging misteryoso nito.

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