Oraclen Java 7 -julkaisu esitteli uuden kutsutaan dynaamiseksi
tavukoodikäsky Java-virtuaalikoneelle (JVM) ja uusi java.lang.invoke
API-paketti luokan vakiokirjastoon. Tämä viesti esittelee sinut tähän ohjeeseen ja sovellusliittymään.
Mitä ja miten kutsutaan dynaamiseksi
K: Mikä on kutsutaan dynaamiseksi
?
A:kutsutaan dynaamiseksi
on tavukoodikäsky, joka helpottaa dynaamisten kielten (JVM) käyttöönottoa dynaamisen menetelmän kutsun avulla. Tämä ohje on kuvattu JVM-määrityksen Java SE 7 -versiossa.
Dynaamiset ja staattiset kielet
A dynaaminen kieli (tunnetaan myös nimellä dynaamisesti kirjoitettu kieli) on korkean tason ohjelmointikieli, jonka tyyppitarkistus suoritetaan yleensä ajon aikana, ominaisuus tunnetaan nimellä dynaaminen kirjoittaminen. Tyyppitarkistus varmistaa, että ohjelma on tyyppi turvallinen: kaikilla toimintoargumenteilla on oikea tyyppi. Groovy, Ruby ja JavaScript ovat esimerkkejä dynaamisista kielistä. ( @ groovy.transform.TypeChecked
huomautus saa Groovyn kirjoittamaan tarkistuksen kääntöhetkellä.)
Sen sijaan a staattinen kieli (tunnetaan myös nimellä staattisesti kirjoitettu kieli) suorittaa tyypin tarkistuksen kääntöhetkellä, ominaisuus tunnetaan nimellä staattinen kirjoittaminen. Kääntäjä tarkistaa, että ohjelma on tyypiltään oikea, vaikka se saattaa lykätä tietyn tyyppitarkistusta ajonaikaan (think casts ja tarkistuslähetys
ohje). Java on esimerkki staattisesta kielestä. Java-kääntäjä käyttää tämän tyyppisiä tietoja vahvasti kirjoitettujen tavukoodien tuottamiseen, jotka JVM voi suorittaa tehokkaasti.
K: Kuinka kutsutaan dynaamiseksi
helpottaa kielen dynaamista käyttöönottoa?
A: Dynaamisella kielellä tyyppitarkistus tapahtuu tyypillisesti ajon aikana. Kehittäjien on läpäistävä sopivat tyypit tai riski suorituksenaikaisia epäonnistumisia. Se on usein niin java.lang.objekti
on tarkin menetelmäargumentin tyyppi. Tämä tilanne vaikeuttaa tyyppitarkistusta, mikä vaikuttaa suorituskykyyn.
Toinen haaste on, että dynaamiset kielet tarjoavat tyypillisesti mahdollisuuden lisätä kenttiä / menetelmiä ja poistaa niitä olemassa olevista luokista. Seurauksena on, että luokan, menetelmän ja kentän tarkkuutta on lykättävä ajonaikaiseksi. Lisäksi on usein tarpeen mukauttaa menetelmän kutsu kohteeseen, jolla on erilainen allekirjoitus.
Nämä haasteet ovat perinteisesti edellyttäneet tapauskohtaisen ajonaikaisen tuen rakentamista JVM: n päälle. Tämä tuki sisältää käärintätyyppiluokkia, hash-taulukoiden käyttämisen dynaamisen symbolien tarkkuuden aikaansaamiseksi ja niin edelleen. Bytecode luodaan aloituspisteillä ajonaikaan menetelmäpuheluiden muodossa käyttäen mitä tahansa neljästä menetelmäkutsuohjeesta:
invokestaattinen
käytetään kutsumaanstaattinen
menetelmiä.invokevirtuaali
käytetään kutsumaanjulkinen
jasuojattu
ei-staattinen
menetelmiä dynaamisen lähettämisen kautta.invokeinterface
on samanlainen kuininvokevirtuaali
lukuun ottamatta menetelmälähetystä, joka perustuu rajapintatyyppiin.vetoaa erityiseen
käytetään myös esiintymien alustusmenetelmien (konstruktoreiden) käyttämiseenyksityinen
nykyisen luokan superluokan menetelmät ja menetelmät.
Tämä ajonaikainen tuki vaikuttaa suorituskykyyn. Luodut tavukoodit vaativat usein useita todellisia JVM-menetelmäkutsuja yhdelle dynaamiselle kielimenetelmän kutsulle. Heijastusta käytetään laajalti ja se heikentää suorituskykyä. Myös monet erilaiset toteutuspolut tekevät JVM: n juuri-in-time (JIT) -kääntäjältä mahdottomaksi optimointien soveltamisen.
Huonon suorituskyvyn korjaamiseksi kutsutaan dynaamiseksi
ohjeet poistavat väliaikaisen ajonaikaisen tuen. Sen sijaan ensimmäinen puhelu bootstraps kutsumalla ajonaikaisen logiikan, joka valitsee kohdemenetelmän tehokkaasti, ja seuraavat puhelut kutsuvat tavallisesti kohdemenetelmän tarvitsematta käynnistää uudelleen.
kutsutaan dynaamiseksi
hyödyttää myös dynaamisia kielen toteuttajia tukemalla dynaamisesti muuttuvia puhelusivustokohteita - a soita sivustolletarkemmin sanottuna a dynaamisen puhelun sivusto on kutsutaan dynaamiseksi
ohje. Lisäksi koska JVM tukee sisäisesti kutsutaan dynaamiseksi
, tämä ohje voidaan optimoida paremmin JIT-kääntäjällä.
Menetelmä käsittelee
K: Ymmärrän, että kutsutaan dynaamiseksi
toimii metodikahvojen kanssa dynaamisen menetelmän kutsumisen helpottamiseksi. Mikä on menetelmäkahva?
A: A menetelmän kahva on "kirjoitettu, suoraan suoritettava viittaus taustalla olevaan menetelmään, konstruktoriin, kenttään tai vastaavaan matalan tason operaatioon, vaihtoehtoisilla argumenttien tai palautusarvojen muunnoksilla". Toisin sanoen se on samanlainen kuin C-tyylinen funktiosoitin, joka osoittaa suoritettavaa koodia - a kohde - ja joihin voidaan viitata tämän koodin käyttämiseksi. Menetelmän kahvat kuvataan tiivistelmällä java.lang.invoke.MethodHandle
luokassa.
K: Voitteko antaa yksinkertaisen esimerkin menetelmän luomisesta ja kutsumisesta?
A: Tutustu luetteloon 1.
Listaus 1. MHD.java
(versio 1)
tuo java.lang.invoke.MethodHandle; tuo java.lang.invoke.MethodHandles; tuo java.lang.invoke.MethodType; public class MHD {public static void main (String [] args) heittää Throwable {MethodHandles.Lookup lookup = MethodHandles.lookup (); MethodHandle mh = lookup.findStatic (MHD.luokka, "hei", MethodType.methodType (void.class)); mh.invokeExact (); } static void hello () {System.out.println ("hei"); }}
Luettelossa 1 kuvataan menetelmäkahvan esittelyohjelma, joka koostuu main ()
ja Hei()
luokan menetelmät. Tämän ohjelman tavoitteena on vedota Hei()
menetelmäkahvan kautta.
main ()
Ensimmäinen tehtävä on hankkia a java.lang.invoke.MethodHandles.Lookup
esine. Tämä objekti on tehdas metodikahvojen luomiseen, ja sitä käytetään kohteiden, kuten virtuaalisten menetelmien, staattisten menetelmien, erikoismenetelmien, rakentajien ja kenttäyhteyksien, etsimiseen. Lisäksi se riippuu puhelusivuston kutsukontekstista ja pakottaa menetelmän käsittelyn käyttörajoitukset joka kerta, kun menetelmän käsittely luodaan. Toisin sanoen, puhelusivusto (kuten Listing 1: t main ()
menetelmä, joka toimii puhelusivustona), joka hankkii hakuobjektin, voi käyttää vain niitä kohteita, jotka ovat puhelusivuston käytettävissä. Hakuobjekti saadaan kutsumalla java.lang.invoke.MethodHandles
luokan MethodHandles.Lookup-haku ()
menetelmä.
publicLookup ()
MethodHandles
ilmoittaa myös a MethodHandles.Lookup publicLookup ()
menetelmä. Toisin kuin Katso ylös()
, jota voidaan käyttää menetelmän käsittelemiseen mihin tahansa käytettävissä olevaan menetelmään / rakentajaan tai kenttään, publicLookup ()
voidaan käyttää menetelmäkahvan hankkimiseen vain julkisesti käytettävissä olevaan kenttään tai julkisesti käytettävissä olevaan menetelmään / rakentajaan.
Saatuaan hakuobjektin tämä objekti on MethodHandle findStatic (luokan viite, merkkijonon nimi, MethodType-tyyppi)
- menetelmää kutsutaan menetelmäkahvan saamiseksi Hei()
menetelmä. Ensimmäinen argumentti välitettiin findStatic ()
on viittaus luokkaan (MHD
) josta menetelmä (Hei()
), ja toinen argumentti on menetelmän nimi. Kolmas argumentti on esimerkki a menetelmän tyyppi, joka "edustaa argumentteja ja palautustyyppiä, jotka metodikahva on hyväksynyt ja palauttanut, tai argumentteja ja palautustyyppiä, jotka metodikahvan soittaja on hyväksynyt ja odottanut". Sitä edustaa java.lang.invoke.MethodType
luokka ja saatu (tässä esimerkissä) soittamalla java.lang.invoke.MethodType
on MethodType methodType (luokan rtype)
menetelmä. Tätä menetelmää kutsutaan koska Hei()
tarjoaa vain palautustyypin, joka sattuu olemaan mitätön
. Tämä palautustyyppi on saatavissa methodType ()
ohittamalla mitätön. luokka
tähän menetelmään.
Palautettu menetelmäkahva on määritetty mh
. Tätä objektia käytetään sitten soittamiseen MenetelmäKahva
on Object invokeExact (Object ... argumentit)
method, vedota menetelmäkahvaan. Toisin sanoen, invokeExact ()
johtaa Hei()
kutsutaan, ja Hei
kirjoitetaan normaaliin ulostulovirtaan. Koska invokeExact ()
ilmoitetaan heittävän Heitettävä
, Olen liittänyt heittää Heitettävä
että main ()
method-otsikko.
K: Edellisessä vastauksessasi mainitsit, että hakuobjekti voi käyttää vain niitä kohteita, joihin puhelusivusto pääsee. Voitteko antaa esimerkin, joka osoittaa, kuinka yritetään hankkia menetelmän kahva saavuttamattomaan kohteeseen?
A: Tutustu luetteloon 2.
Listaus 2. MHD.java
(versio 2)
tuo java.lang.invoke.MethodHandle; tuo java.lang.invoke.MethodHandles; tuo java.lang.invoke.MethodType; luokka HW {public void hello1 () {System.out.println ("hello from hello1"); } private void hello2 () {System.out.println ("hei hello2"); }} public class MHD {public static void main (String [] args) heittää Heitettävä {HW hw = new HW (); MethodHandles.Lookup lookup = MethodHandles.lookup (); MethodHandle mh = lookup.findVirtual (HW.luokka, "hei1", MethodType.methodType (void.class)); mh.invoke (hw); mh = lookup.findVirtual (HW.luokka, "hei2", MethodType.methodType (void.luokka)); }}
Listaus 2 julistaa HW
(Hei, maailma) ja MHD
luokat. HW
julistaa a julkinen
hei1 ()
instanssimenetelmä ja a yksityinen
hei2 ()
instanssimenetelmä. MHD
julistaa a main ()
menetelmä, joka yrittää vedota näihin menetelmiin.
main ()
Ensimmäinen tehtävä on instantisoida HW
valmistautumalla vetoamiseen hei1 ()
ja hei2 ()
. Seuraavaksi se hankkii hakuobjektin ja käyttää tätä objektia saadakseen menetelmän kahvan kutsumiseen hei1 ()
. Tällä kertaa, MethodHandles.Lookup
on findVirtual ()
kutsutaan ja ensimmäinen tähän menetelmään välitetty argumentti on a Luokka
objektia kuvaava HW
luokassa.
Osoittautuu niin findVirtual ()
onnistuu, ja sitä seuraavat mh.invoke (hw);
lauseke käynnistää hei1 ()
, johtaen hei hei1
tuotos.
Koska hei1 ()
On julkinen
, se on saatavilla main ()
method call site. Verrattuna, hei2 ()
ei ole käytettävissä. Tämän seurauksena toinen findVirtual ()
kutsu epäonnistuu IllegalAccessException
.
Kun suoritat tämän sovelluksen, sinun on noudatettava seuraavaa tulosta:
hello from hello1 Poikkeus säikeessä "main" java.lang.IllegalAccessException: jäsen on yksityinen: HW.hello2 () void, MHD: stä osoitteessa java.lang.invoke.MemberName.makeAccessException (MemberName.java:507) java.lang. invoke.MethodHandles $ Lookup.checkAccess (MethodHandles.java:1172) osoitteessa java.lang.invoke.MethodHandles $ Lookup.checkMethod (MethodHandles.java:1152) osoitteessa java.lang.invoke.MethodHandles $ Lookup.accessVirtual (Method: 648) osoitteessa java.lang.invoke.MethodHandles $ Lookup.findVirtual (MethodHandles.java:641) osoitteessa MHD.main (MHD.java:27)
K: Luettelot 1 ja 2 käyttävät invokeExact ()
ja vedota()
menetelmiä suorittamaan menetelmäkahva. Mitä eroa on näiden menetelmien välillä?
A: Siitä huolimatta invokeExact ()
ja vedota()
on suunniteltu suorittamaan metodikahva (itse asiassa kohdekoodi, johon metodikahva viittaa), ne eroavat toisistaan, kun argumenteille ja palautusarvolle suoritetaan tyyppimuunnoksia. invokeExact ()
ei suorita automaattista yhteensopivan tyypin muunnosta argumenteissa. Sen argumenttien (tai argumenttilausekkeiden) on oltava täsmälliset tyypin vastaavuudet menetelmän allekirjoituksen kanssa, kukin argumentti on annettava erikseen, tai kaikki argumentit on toimitettava yhdessä matriisina. vedota()
vaatii, että sen argumenttien (tai argumenttilausekkeiden) on oltava yhteensopivia tyypin kanssa menetelmän allekirjoituksen kanssa - automaattiset tyyppimuunnokset suoritetaan siten, että kukin argumentti annetaan erikseen tai kaikki argumentit annetaan yhdessä matriisina.
K: Voitteko antaa minulle esimerkin, joka osoittaa kuinka kutsua esiintymäkentän getter ja setter?
A: Tutustu luetteloon 3.
Listaus 3. MHD.java
(versio 3)
tuo java.lang.invoke.MethodHandle; tuo java.lang.invoke.MethodHandles; tuo java.lang.invoke.MethodType; luokka Piste {int x; int y; } public class MHD {public static void main (String [] args) heittää Throwable {MethodHandles.Lookup lookup = MethodHandles.lookup (); Pistepiste = uusi piste (); // Aseta x- ja y-kentät. MethodHandle mh = lookup.findSetter (kohta.luokka, "x", sis. Luokka); mh. kutsu (kohta 15); mh = lookup.findSetter (kohta.luokka, "y", sis. luokka); mh. kutsu (kohta 30); mh = lookup.findGetter (kohta.luokka, "x", sis. luokka); int x = (int) mh. kutsu (piste); System.out.printf ("x =% d% n", x); mh = lookup.findGetter (kohta.luokka, "y", sis. luokka); int y = (int) mh. kutsu (piste); System.out.printf ("y =% d% n", y); }}
Luettelossa 3 esitellään a Kohta
luokka, jossa on pari 32-bittistä kokonaislukukenttää x
ja y
. Jokaisen kentän setteriin ja getteriin pääsee soittamalla MethodHandles.Lookup
on findSetter ()
ja findGetter ()
menetelmiä ja niistä johtuvia MenetelmäKahva
palautetaan. Jokainen findSetter ()
ja findGetter ()
vaatii a Luokka
argumentti, joka tunnistaa kentän luokan, kentän nimen ja a Luokka
objekti, joka tunnistaa kentän allekirjoituksen.
vedota()
menetelmää käytetään setterin tai getterin suorittamiseen - kulissien takana esiintymäkenttiin pääsee JVM: n kautta putfield
ja getfield
ohjeet. Tämä menetelmä edellyttää, että viittaus objektiin, jonka kenttää käytetään, välitetään alkuperäisenä argumenttina. Setter-kutsuja varten on lähetettävä myös toinen argumentti, joka koostuu kentälle määritetystä arvosta.
Kun suoritat tämän sovelluksen, sinun on noudatettava seuraavaa tulosta:
x = 15 y = 30
K: Metodikahvan määrittelysi sisältää lauseen "argumenttien tai palautusarvojen valinnaisilla muunnoksilla". Voitteko antaa esimerkin argumentin muunnoksesta?
A: Olen luonut esimerkin Matematiikka
luokan kaksoisvoima (kaksinkertainen a, kaksinkertainen b)
luokan menetelmä. Tässä esimerkissä saan menetelmän kahvan Pow ()
ja muuntaa tämän menetelmän kahva siten, että toinen argumentti välitettiin Pow ()
on aina 10
. Tutustu luetteloon 4.