{"id":3794,"date":"2017-03-03T13:22:03","date_gmt":"2017-03-03T11:22:03","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=3794"},"modified":"2017-03-03T13:22:03","modified_gmt":"2017-03-03T11:22:03","slug":"schneller-aufrufen-mit-methodtype-und-methodhandle","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2017\/03\/schneller-aufrufen-mit-methodtype-und-methodhandle\/","title":{"rendered":"Schneller aufrufen mit MethodType und MethodHandle"},"content":{"rendered":"<p>Um dynamische Programmiersprachen wie JavaScript performant auf die JVM zu bringen wurde in Java 7 der neue Bytecode invokedynamic eingef\u00fchrt und das Paket lang.invoke. Java8 greift zur Umsetzung der Lambda-Ausdr\u00fccke massiv auf invokedynamic zur\u00fcck.<\/p>\n<p>Aufgabe des Pakets ist es, dynamisch Methoden schnell aufzurufen, und zwar deutlich schneller als Reflection das kann, weil in der JVM der Methodenaufruf so optimiert wird wie ein ganz normaler Methodenaufruf auf ein Zielobjekt. Dazu m\u00fcssen aber die Typen exakt vorliegen, sodass es sch\u00e4rfere Anforderungen gibt als bei Reflection, dort ist z. B. der R\u00fcckgabetyp beim Aufruf irrelevant.<\/p>\n<p>Um einen dynamischen Methodenaufruf zu starten ist zun\u00e4chst eine exakte Beschreibung der R\u00fcckgabe- und Parametertypen n\u00f6tig \u2013 das \u00fcbernimmt ein MethodType-Objekt. Ist das aufgebaut, wird ein MethodHandle\u00a0erfragt, ein getypter, direkt ausf\u00fchrbarer Verweis auf die repr\u00e4sentierte Methode. Die MethodHandle-Methode invoke(\u2026) f\u00fchrt dann den Aufruf mit gegebenen Argumente auf.<\/p>\n<p>Dazu ein Beispiel. Wir m\u00f6chten auf einem Rectangle-Objekt die Methode union(Rectangle) aufrufen, um als Ergebnis ein neues Rectangle zu bekommen, was die beiden Rechtecke vereinigt.<\/p>\n<pre>Object rect1 = new Rectangle( 10, 10, 10, 10 );\n\nString methodName = \"union\";\u00a0\n\nClass&lt;?&gt; resultType = Rectangle.class;\n\nObject rect2 = new Rectangle( 20, 20, 100, 100 );\n\nClass&lt;? &gt; parameterType = rect2.getClass();<\/pre>\n<p>rect1 ist das eigentliche Objekt auf dem die methodName aufgerufen werden soll. resultType ist der Ergebnistyp den wir von der Methode erwarten, als Class-Objekt. rect2 ist das Argument f\u00fcr union(\u2026). Der parameterType f\u00fcr die union(\u2026)-Methode ergibt sich aus dem Class-Objekt vom rect2.<\/p>\n<pre>MethodType mt = MethodType.methodType( resultType, parameterType );\n\nMethodHandle methodHandle = MethodHandles.lookup().findVirtual(\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rect1.getClass(), methodName, mt );\n\nSystem.out.println( methodHandle.invoke( rect1, rect2 ) );<\/pre>\n<p>Als erstes erfragen wir MethodType und geben Ergebnis- und Parametertyp an; noch nicht den Methodennamen, hier geht es nur um die Typen. Der MethodHandle verheiratet den Methodennamen und die Typangaben mit einer Klasse, die so eine Methode anbietet. invoke(\u2026) f\u00fchrt letztendlich den Aufruf aus; das erste Argument ist das \u201ethis\u201c-Objekt, also das Objekt auf dem die Methode aufgerufen werden soll, als n\u00e4chstes folgenden die Argumente von union(\u2026), also das zweite Rechteck. Als Ergebnis bekommen wir das Rectangle-Objekt, was genau der Vereinigung entspricht.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Um dynamische Programmiersprachen wie JavaScript performant auf die JVM zu bringen wurde in Java 7 der neue Bytecode invokedynamic eingef\u00fchrt und das Paket lang.invoke. Java8 greift zur Umsetzung der Lambda-Ausdr\u00fccke massiv auf invokedynamic zur\u00fcck. Aufgabe des Pakets ist es, dynamisch Methoden schnell aufzurufen, und zwar deutlich schneller als Reflection das kann, weil in der JVM [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1,11],"tags":[],"class_list":["post-3794","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-insel"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3794","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=3794"}],"version-history":[{"count":3,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3794\/revisions"}],"predecessor-version":[{"id":3797,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3794\/revisions\/3797"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=3794"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=3794"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=3794"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}