Reflectionin suorituskyky ja vaihtoehdot
Mittaa Reflectionin yleiskustannuksia suorien kutsujen vastineena ja tutustu MethodHandles-tyyppiin nopeampana vaihtoehtona.
Reflectionin suorituskyky ja vaihtoehdot on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.
Reflektion aiheuttama kuormitus
Reflektiiviset kutsut ovat huomattavasti hitaampia kuin suorat kutsut: metodin haku sisältää kartan läpikäynnin, tietoturvatarkistuksia ja kääreolioiden luomista. JIT-lämmityksen jälkeen invoke on noin 10–50 kertaa hitaampi kuin suora kutsu.
Reflektion suorituskyvyn mittaaminen
Käyttäkää JMH:ta (Java Microbenchmark Harness) reflektion ja suorien kutsujen aiheuttaman kuormituksen mittaamiseen. Mitatkaa aina todellisessa käyttöyhteydessä — JIT saattaa optimoida osan kuormituksesta pois.
@Benchmark
public String directCall() { return user.getName(); }
@Benchmark
public String reflectiveCall() throws Exception {
return (String) NAME_METHOD.invoke(user); // NAME_METHOD cached
}Field- ja Method-olioiden välittäminen
Method- ja Field-olion haku (getDeclaredMethod) on kallein vaihe. Välittäkää tulos static final-kenttään. Välimuistissa olevan olion invoke-kutsu on paljon nopeampi.
public class UserAccessor {
private static final Method GET_NAME;
static {
try {
GET_NAME = User.class.getDeclaredMethod("getName");
GET_NAME.setAccessible(true);
} catch (NoSuchMethodException e) { throw new ExceptionInInitializerError(e); }
}
public static String getName(User u) throws Exception { return (String) GET_NAME.invoke(u); }
}MethodHandles: Lähes suoran kutsun nopeus
MethodHandles.lookup().findVirtual() luo käsittelijän, jonka JIT voi optimoida muutaman kutsun jälkeen lähes suoran kutsun nopeuteen. Se on suositeltava suorituskyvyn kannalta kriittisessä reflektiokoodissa.
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(User.class, "getName",
MethodType.methodType(String.class));
// Cast to functional interface for max speed:
Function<User, String> getName = user -> {
try { return (String) mh.invokeExact(user); }
catch (Throwable t) { throw new RuntimeException(t); }
};LambdaMetafactory: Paras suorituskyky
LambdaMetafactory luo ajonaikana lambdan MethodHandle-oliosta ja tarjoaa JIT-optimoinnin jälkeen suoran kutsun nopeuden. Jackson ja Kryo käyttävät sitä sisäisesti.
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(User.class, "getName",
MethodType.methodType(String.class));
CallSite site = LambdaMetafactory.metafactory(lookup, "get",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class),
mh, MethodType.methodType(String.class, User.class));
Function<User, String> fn = (Function<User, String>) site.getTarget().invokeExact();
System.out.println(fn.apply(user));Käännösaikainen koodigenerointi APT:llä
Annotaatioprosessorit luovat lähdetiedostoja käännösaikana. Lombokin ja MapStructin kaltaiset kehykset käyttävät APT:tä tyyppiturvallisen ja täysin reflektiottoman boilerplate-koodin tuottamiseen — näin ajonaikainen suorituskyky on paras mahdollinen.
Byte Buddy ajonaikaiseen koodigenerointiin
Byte Buddy luo aliluokkia ja välityspalvelimia ajonaikana tavukoodia muokkaamalla. Se on suorituskyvyn kannalta kriittisissä kohdissa paljon dynaamisia välityspalvelimia nopeampi. Sitä käyttävät muun muassa Mockito, Hibernate ja ByteCodeLib.
// Byte Buddy example — create a class with a method:
Class<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("Hello Byte Buddy!"))
.make()
.load(getClass().getClassLoader())
.getLoaded();
System.out.println(dynamicType.newInstance()); // Hello Byte Buddy!Reflektion välttäminen suorituskyvyn kannalta kriittisissä kohdissa
Käyttäkää reflektiota kehyksen alustamiseen eli käynnistysaikana, älkää pyyntökohtaisissa suorituspoluissa. Siirtäkää reflektiota käyttävä työ sovelluksen käynnistykseen ja välittäkää kaikki mahdollinen aggressiivisesti.
Moduulijärjestelmä ja reflektio (Java 9+)
Java 9:n ja sitä uudempien versioiden moduulit estävät syvän reflektion oletusarvoisesti. Myöntäkää käyttöoikeus --add-opens-valitsimella tai module-info.java opens-direktiiveillä. Kirjastot käyttävät yhä useammin MethodHandles-ratkaisua välttääkseen --add-opens-valitsimen tarpeen.
// module-info.java:
module com.example.app {
opens com.example.model to com.example.framework; // allow reflective access
}Reflektion ja koodigeneroinnin kompromissit
Reflektio on yksinkertaista ja joustavaa, mutta hidasta. Koodigenerointi (APT/Byte Buddy) on nopeaa ja tyyppiturvallista, mutta sen käyttöönotto on monimutkaista. Valitkaa lähestymistapa sen perusteella, tapahtuuko työ käynnistysaikana (reflektio sopii) vai pyyntöaikana (välttäkää reflektiota).
Reflektion käytön profilointi
Käyttäkää JFR:ää (Java Flight Recorder) tai async-profileria selvittääksenne, missä reflektion aiheuttama kuormitus kertyy. Etsikää sun.reflect.*- tai java.lang.reflect.*-kohtia kuumien metodien luettelosta.
Pikatarkistus
Mikä on nopein ajonaikainen vaihtoehto Method.invoke-metodille suorituskyvyn kannalta kriittisissä reflektiivisissä kutsuissa?
Kertaus
Välittäkää Method- ja Field-oliot haun aiheuttaman kustannuksen vähentämiseksi. Käyttäkää MethodHandles-ratkaisua suorituskyvyn kannalta kriittisissä kohdissa. Käyttäkää LambdaMetafactory-ratkaisua parhaan suorituskyvyn saavuttamiseksi. Käyttäkää APT:tä tai Byte Buddya reflektion poistamiseen kokonaan kriittisistä osioista.
Opi Java tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 104
- Oppitunnit
- 374
Usein kysytyt kysymykset
Onko oppitunti ”Reflectionin suorituskyky ja vaihtoehdot” ilmainen?
Kyllä – oppitunnin ”Reflectionin suorituskyky ja vaihtoehdot” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Reflectionin suorituskyky ja vaihtoehdot”?
Mittaa Reflectionin yleiskustannuksia suorien kutsujen vastineena ja tutustu MethodHandles-tyyppiin nopeampana vaihtoehtona. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Reflectionin suorituskyky ja vaihtoehdot”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?
Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Luokkien tarkastelu Reflectionilla
- Metodien kutsuminen ja kenttien käyttäminen
- Dynaamiset proxyt InvocationHandlerilla
- Reflectionin suorituskyky ja vaihtoehdot