Programiranje

Invokedynamic 101

Oraclova izdaja Java 7 je predstavila novo invokedynamic bytecode navodilo za navidezni stroj Java (JVM) in novo java.lang.invoke Paket API za standardno knjižnico razredov. Ta objava vas seznani s tem navodilom in API-jem.

Kaj in kako invokedynamic

V: Kaj je invokedynamic?

A:invokedynamic je navodilo bytecode, ki olajša izvajanje dinamičnih jezikov (za JVM) z dinamičnim priklicem metode. Ta navodila so opisana v izdaji Java SE 7 v specifikaciji JVM.

Dinamični in statični jeziki

A dinamični jezik (znan tudi kot dinamično tipkan jezik) je programski jezik na visoki ravni, katerega preverjanje tipa se običajno izvaja med izvajanjem, funkcija, znana kot dinamično tipkanje. Preverjanje tipa preverja, ali je program tip varno: vsi argumenti operacije imajo pravilno vrsto. Groovy, Ruby in JavaScript so primeri dinamičnih jezikov. (The @ groovy.transform.TypeChecked opomba povzroči, da Groovy preveri tip v času prevajanja.)

Nasprotno pa a statični jezik (znan tudi kot statično tipkan jezik) izvaja preverjanje tipa med prevajanjem, funkcija, znana kot statično tipkanje. Prevajalnik preveri, ali je program pravilen, čeprav lahko nekatere vrste preverjanja prestavi na izvajalno okolje (pomislite na oddaj in checkcast navodila). Java je primer statičnega jezika. Prevajalnik Java uporablja informacije o tem tipu za izdelavo močno vtipkane bajtne kode, ki jo lahko učinkovito izvede JVM.

V: Kako invokedynamic olajšati dinamično izvajanje jezika?

A: V dinamičnem jeziku se preverjanje tipa običajno zgodi med izvajanjem. Razvijalci morajo prenesti ustrezne vrste ali tvegati napake med izvajanjem. Pogosto je tako java.lang.Object je najbolj natančen tip za argument metode. Ta situacija otežuje preverjanje vrste, kar vpliva na zmogljivost.

Drug izziv je, da dinamični jeziki običajno omogočajo dodajanje polj / metod in njihovo odstranjevanje iz obstoječih razredov. Posledično je treba razred, metodo in ločljivost polja prestaviti na izvajanje. Pogosto je tudi treba prilagoditi priklic metode cilju, ki ima drugačen podpis.

Ti izzivi že tradicionalno zahtevajo ad hoc podporo za izvajanje, ki jo je treba zgraditi na vrhu JVM. Ta podpora vključuje razrede vrste ovoja, uporabo razprševalnih tabel za zagotavljanje dinamične ločljivosti simbolov itd. Bytecode se ustvari z vstopnimi točkami v času izvajanja v obliki klicev metode z uporabo katerega koli od štirih navodil za priklic metode:

  • invokestatičen se uporablja za klicanje statično metode.
  • invokevirtual se uporablja za klicanje javnosti in zaščiten ne-statično metode prek dinamične odpreme.
  • invokeinterface je podoben invokevirtual razen odpreme metode, ki temelji na tipu vmesnika.
  • invokespecial se uporablja za priklic načinov inicializacije primerkov (konstruktorjev), pa tudi zasebno metode in metode nadrazreda trenutnega razreda.

Ta izvajalna podpora vpliva na zmogljivost. Ustvarjena bajtoda pogosto zahteva več dejanskih klicev metode JVM za en klic metode dinamičnega jezika. Odsev se pogosto uporablja in prispeva k poslabšanju zmogljivosti. Poleg tega številne različne izvedbene poti onemogočajo, da JVM-jev prevajalnik ravno v času (JIT) uporabi optimizacije.

Za odpravo slabe uspešnosti je invokedynamic navodilo odpravlja ad hoc podporo za izvajanje. Namesto tega prvi klic zagonske trakove tako, da prikliče izvajalno logiko, ki učinkovito izbere ciljno metodo, poznejši klici pa običajno prikličejo ciljno metodo, ne da bi se morali ponovno zagnati.

invokedynamic koristi tudi implementatorjem dinamičnih jezikov s podporo dinamično spreminjajočim se ciljem klicnih mest - a pokličite spletno mesto, natančneje, a dinamično klicno mesto je invokedynamic navodila. Poleg tega, ker JVM interno podpira invokedynamic, lahko ta navodila bolje optimizira prevajalnik JIT.

Metode ročaji

V: Razumem, da invokedynamic deluje z ročaji metod za olajšanje dinamičnega priklica metode. Kaj je ročaj metode?

A: A ročaj metode je "tipiziran, neposredno izvedljiv sklic na osnovno metodo, konstruktor, polje ali podobno operacijo na nizki ravni, z neobveznimi transformacijami argumentov ali vrnjenih vrednosti." Z drugimi besedami, podoben je kazalcu funkcije v slogu C, ki kaže na izvršljivo kodo - a cilj - in za katero je mogoče določiti referenco za klic te kode. Ročaji metod so opisani v povzetku java.lang.invoke.MethodHandle razred.

V: Ali lahko navedete preprost primer ustvarjanja in priklica ročice metode?

A: Oglejte si seznam 1.

Seznam 1. MHD.java (različica 1)

import java.lang.invoke.MethodHandle; uvoz java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; javni razred MHD {javna statična void main (String [] args) meče Throwable {MethodHandles.Lookup lookup = MethodHandles.lookup (); MethodHandle mh = lookup.findStatic (MHD.class, "hello", MethodType.methodType (void.class)); mh.invokeExact (); } statična void hello () {System.out.println ("hello"); }}

V seznamu 1 je opisan predstavitveni program, ki sestoji iz glavni () in zdravo() razredne metode. Cilj tega programa je sklicevanje zdravo() prek ročaja metode.

glavni ()Prva naloga je pridobiti a java.lang.invoke.MethodHandles.Lookup predmet. Ta predmet je tovarna za ustvarjanje ročajev metod in se uporablja za iskanje ciljev, kot so navidezne metode, statične metode, posebne metode, konstruktorji in dostop do polj. Poleg tega je odvisen od klicnega konteksta spletnega mesta klica in uveljavlja omejitve dostopa do ročaja metode vsakič, ko se ustvari ročaj metode. Z drugimi besedami, klicno mesto (na primer seznam 1 glavni () metoda, ki deluje kot klicno mesto), ki pridobi iskalni objekt, lahko dostopa samo do tistih ciljev, ki so dostopni klicnemu mestu. Iskalni objekt dobimo s klicem java.lang.invoke.MethodHandles razredov Iskanje MethodHandles.Lookup () metoda.

publicLookup ()

Metoda Ročaji izjavlja tudi a MethodHandles.Lookup publicLookup () metoda. Za razliko Poglej gor(), ki se lahko uporablja za pridobitev ročaja metode za katero koli dostopno metodo / konstruktor ali polje, publicLookup () se lahko uporablja za pridobivanje ročaja metode v javno dostopnem polju ali samo javno dostopni metodi / konstruktorju.

Po pridobitvi iskalnega predmeta ta objekt MethodHandle findStatic (refc razreda, ime niza, vrsta metode) metoda se pokliče za pridobitev ročaja metode za zdravo() metoda. Prvi argument je bil poslan findStatic () je sklic na razred (MHD), iz katerega je uporabljena metoda (zdravo()), drugi argument pa je ime metode. Tretji argument je primer a vrsta metode, ki "predstavlja argumente in vrsto vrnitve, ki jih je sprejel in vrnil ročaj metode, ali argumente in vrsto vrnitve, ki jih je klicalnik ročice metode prenesel in pričakoval." Predstavlja ga primerek java.lang.invoke.MethodType razred in pridobljen (v tem primeru) s klicem java.lang.invoke.MethodTypeje MethodType methodType (vrsta razreda) metoda. Ta metoda se imenuje, ker zdravo() ponuja samo vrsto vrnitve, kar se zgodi praznino. Ta vrsta vračila je na voljo methodType () mimo void.class tej metodi.

Vrnjeni ročaj metode je dodeljen mh. Ta predmet se nato uporabi za klic MethodHandleje Object invokeExact (Object ... args) , da prikličete ročico metode. Z drugimi besedami, invokeExact () Rezultati v zdravo() klic, in zdravo zapisan v standardni izhodni tok. Ker invokeExact () je razglašen za metanje Mečljivo, Sem dodal vrže Throwable do glavni () glavo metode.

V: V prejšnjem odgovoru ste omenili, da lahko iskalni objekt dostopa samo do tistih ciljev, ki so dostopni mestu klica. Ali lahko navedete primer, ki prikazuje poskus, kako pridobiti ročaj metode do nedostopnega cilja?

A: Oglejte si seznam 2.

Seznam 2. MHD.java (različica 2)

import java.lang.invoke.MethodHandle; uvoz java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; razred HW {public void hello1 () {System.out.println ("hello from hello1"); } private void hello2 () {System.out.println ("hello from hello2"); }} javni razred MHD {javna statična void main (String [] args) vrže Throwable {HW hw = new HW (); MethodHandles.Lookup lookup = MethodHandles.lookup (); MethodHandle mh = lookup.findVirtual (HW.class, "hello1", MethodType.methodType (void.class)); mh.invoke (hw); mh = lookup.findVirtual (HW.class, "hello2", MethodType.methodType (void.class)); }}

Seznam 2 navaja HW (Pozdravljeni, Svet) in MHD razredih. HW izjavlja a javnostipozdrav1 () primerka in a zasebnozdravo2 () metoda primerka. MHD izjavlja a glavni () metoda, ki bo poskušala priklicati te metode.

glavni ()Prva naloga je ustvariti primerek HW v pripravi na klicanje pozdrav1 () in zdravo2 (). Nato pridobi iskalni objekt in s tem objektom pridobi ročaj metode za klicanje pozdrav1 (). Tokrat, MethodHandles.Lookupje findVirtual () pokliče se metoda in prvi argument, ki se ji posreduje, je Razred predmet, ki opisuje HW razred.

Izkazalo se je, da findVirtual () bo uspelo in nadaljnje mh.invoke (hw); izraz bo poklical pozdrav1 (), kaže v živjo od hello1 izhod.

Ker pozdrav1 () je javnosti, je dostopen za glavni () spletno mesto klic metode. V nasprotju, zdravo2 () ni dostopna. Kot rezultat, drugi findVirtual () klic ne bo uspel z IllegalAccessException.

Ko zaženete to aplikacijo, upoštevajte naslednje rezultate:

hello from hello1 Izjema v niti "main" java.lang.IllegalAccessException: član je zaseben: HW.hello2 () void, iz MHD na java.lang.invoke.MemberName.makeAccessException (MemberName.java:507) na java.lang. invoke.MethodHandles $ Lookup.checkAccess (MethodHandles.java:1172) na java.lang.invoke.MethodHandles $ Lookup.checkMethod (MethodHandles.java:1152) na java.lang.invoke.MethodHandles $ Lookup.accessVirtual (MethodHavaVav. 648) na java.lang.invoke.MethodHandles $ Lookup.findVirtual (MethodHandles.java:641) na MHD.main (MHD.java:27)

V: Seznam 1 in 2 uporabljata invokeExact () in prikliči () metode za izvajanje ročaja metode. Kakšna je razlika med temi metodami?

A: Čeprav invokeExact () in prikliči () so namenjeni izvajanju ročaja metode (pravzaprav ciljne kode, na katero se nanaša ročaj metode), razlikujejo pa se pri izvedbi pretvorbe tipa na argumentih in vrnjeni vrednosti. invokeExact () ne izvede samodejne pretvorbe združljivega tipa za argumente. Njeni argumenti (ali izrazi argumentov) se morajo natančno ujemati s podpisom metode, pri čemer mora biti vsak argument naveden posebej, ali vsi argumenti skupaj kot matrika. prikliči () zahteva, da se njeni argumenti (ali izrazi argumentov) skladno s tipom ujemajo s podpisom metode - izvedejo se samodejne pretvorbe tipov, pri čemer je vsak argument naveden posebej, ali vsi argumenti skupaj v obliki matrike.

V: Ali mi lahko navedete primer, ki prikazuje, kako priklicati getter in setter polja primerka?

A: Oglejte si seznam 3.

Seznam 3. MHD.java (različica 3)

import java.lang.invoke.MethodHandle; uvoz java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; razred Point {int x; int y; } javni razred MHD {javna statična void main (String [] args) meče Throwable {MethodHandles.Lookup lookup = MethodHandles.lookup (); Točka točka = nova točka (); // Nastavi polji x in y. MethodHandle mh = lookup.findSetter (Point.class, "x", int.class); mh.invoke (točka, 15); mh = lookup.findSetter (Point.class, "y", int.class); mh.invoke (točka, 30); mh = lookup.findGetter (Point.class, "x", int.class); int x = (int) mh.invoke (točka); System.out.printf ("x =% d% n", x); mh = lookup.findGetter (Point.class, "y", int.class); int y = (int) mh.invoke (točka); System.out.printf ("y =% d% n", y); }}

Seznam 3 uvaja a Točka razred z imenom 32-bitnih polj celoštevilčnega primerka x in y. Do nastavitelja in pridobivalca vsakega polja pridete s klicem MethodHandles.Lookupje findSetter () in findGetter () metode in posledično MethodHandle se vrne. Vsak od findSetter () in findGetter () zahteva a Razred argument, ki določa razred polja, ime polja in a Razred predmet, ki identificira podpis polja.

The prikliči () metoda se uporablja za izvajanje nastavitelja ali pridobivalca - v ozadju so polja primerov dostopna prek JVM-jev putfield in getfield navodila. Ta metoda zahteva, da se kot začetni argument posreduje sklic na objekt, do katerega se dostopa. Za klice nastavitelja je treba poslati tudi drugi argument, sestavljen iz vrednosti, ki je dodeljena polju.

Ko zaženete to aplikacijo, upoštevajte naslednje rezultate:

x = 15 y = 30

V: Vaša definicija ročaja metode vključuje besedno zvezo "z neobveznimi transformacijami argumentov ali vrnjenih vrednosti". Ali lahko navedete primer pretvorbe argumentov?

A: Ustvaril sem primer, ki temelji na Matematika razredov dvojni prah (dvojni a, dvojni b) razredna metoda. V tem primeru dobim ročaj metode za prah () in pretvorite to ročico metode tako, da se drugi argument posreduje prah () je vedno 10. Oglejte si seznam 4.

$config[zx-auto] not found$config[zx-overlay] not found