
public 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; } }
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 [] = {{}}; }

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:

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
;
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 4) D
class Test
// Doesn't compile Test
execute((Serializable) (() -> {}));
execute((Runnable & Serializable) (() -> {}));
GO TO FULL VERSION