代码执行结果如下:
[xiaoju@ed3e13fd9af6 test_method_handle]$ java -cp . MethodHandleTest
warm-up begin
timing warm-up begin
timing warm-up end
plain call warm-up begin
plain call warm-up end, time consumed = 7
reflection call warm-up begin
reflection call warm-up end, time consumed = 191
methodhandle call warm-up begin
methodhandle call warm-up end, time consumed = 73
warm-up end
test begin
plain call test begin
plain call test end, time consumed = 10
reflection call test begin
reflection call test end, time consumed = 155
methodhandle call warm-up begin
methodhandle call warm-up end, time consumed = 66
[xiaoju@ed3e13fd9af6 test_method_handle]$
从中可以看到,使用MethodHandle
的执行效率比反射高不少。添加打印编译信息,结果如下:
[xiaoju@ed3e13fd9af6 test_method_handle]$ java -XX:+PrintCompilation -cp . MethodHandleTest
62 1 3 java.lang.String::charAt (29 bytes)
62 2 3 java.lang.String::indexOf (70 bytes)
62 3 3 java.lang.String::hashCode (55 bytes)
62 4 3 java.lang.String::length (6 bytes)
64 5 3 java.lang.Object::<init> (1 bytes)
65 6 3 java.lang.AbstractStringBuilder::ensureCapacityInternal (27 bytes)
65 7 n 0 java.lang.System::arraycopy (native) (static)
65 8 3 java.lang.String::equals (81 bytes)
65 9 3 java.lang.Math::min (11 bytes)
65 11 1 java.lang.ref.Reference::get (5 bytes)
65 10 3 java.util.Arrays::copyOfRange (63 bytes)
65 12 3 java.lang.String::<init> (82 bytes)
66 13 1 java.lang.ThreadLocal::access$400 (5 bytes)
67 14 3 java.lang.String::getChars (62 bytes)
69 15 3 java.lang.System::getSecurityManager (4 bytes)
warm-up begin
timing warm-up begin
74 16 n 0 java.lang.System::currentTimeMillis (native) (static)
78 17 % 3 MethodHandleTest::main @ 41 (619 bytes)
84 18 3 MethodHandleTest::main (619 bytes)
89 19 % 4 MethodHandleTest::main @ 41 (619 bytes)
90 17 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
479 19 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
timing warm-up end
plain call warm-up begin
479 21 % 3 MethodHandleTest::main @ 82 (619 bytes)
479 20 3 MethodHandleTest::add (4 bytes)
480 22 1 MethodHandleTest::add (4 bytes)
480 20 3 MethodHandleTest::add (4 bytes) made not entrant
485 23 % 4 MethodHandleTest::main @ 82 (619 bytes)
486 21 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
486 23 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
plain call warm-up end, time consumed = 7
reflection call warm-up begin
488 24 3 sun.reflect.ClassFileAssembler::emitByte (11 bytes)
488 25 3 sun.reflect.ByteVectorImpl::add (38 bytes)
489 27 3 sun.reflect.ByteVectorImpl::getLength (7 bytes)
489 28 3 sun.reflect.ByteVectorImpl::get (26 bytes)
489 26 3 sun.reflect.ClassFileAssembler::emitShort (24 bytes)
490 29 1 java.lang.Integer::intValue (5 bytes)
490 31 3 java.lang.Number::<init> (5 bytes)
490 30 3 java.lang.Integer::valueOf (32 bytes)
490 32 3 java.lang.Integer::<init> (10 bytes)
490 34 n 0 sun.reflect.Reflection::getClassAccessFlags (native) (static)
490 33 3 java.lang.reflect.Modifier::isPublic (12 bytes)
490 35 3 sun.reflect.Reflection::quickCheckMemberAccess (10 bytes)
491 36 3 java.lang.reflect.Method::invoke (62 bytes)
491 37 3 sun.reflect.DelegatingMethodAccessorImpl::invoke (10 bytes)
491 38 ! 3 sun.reflect.GeneratedMethodAccessor1::invoke (228 bytes)
491 39 % 3 MethodHandleTest::main @ 180 (619 bytes)
492 40 4 java.lang.Integer::valueOf (32 bytes)
493 30 3 java.lang.Integer::valueOf (32 bytes) made not entrant
493 41 4 java.lang.reflect.Method::invoke (62 bytes)
494 42 4 sun.reflect.DelegatingMethodAccessorImpl::invoke (10 bytes)
494 43 ! 4 sun.reflect.GeneratedMethodAccessor1::invoke (228 bytes)
498 38 ! 3 sun.reflect.GeneratedMethodAccessor1::invoke (228 bytes) made not entrant
498 37 3 sun.reflect.DelegatingMethodAccessorImpl::invoke (10 bytes) made not entrant
499 36 3 java.lang.reflect.Method::invoke (62 bytes) made not entrant
502 44 % 4 MethodHandleTest::main @ 180 (619 bytes)
510 39 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
678 44 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
reflection call warm-up end, time consumed = 191
methodhandle call warm-up begin
680 45 3 java.lang.Byte::<init> (10 bytes)
680 46 3 java.lang.Short::<init> (10 bytes)
681 40 4 java.lang.Integer::valueOf (32 bytes) made not entrant
681 47 3 java.lang.Long::<init> (10 bytes)
683 48 n 0 java.lang.invoke.MethodHandle::linkToVirtual(LIIL)I (native) (static)
684 49 3 java.util.concurrent.ConcurrentHashMap::tabAt (21 bytes)
685 50 n 0 sun.misc.Unsafe::getObjectVolatile (native)
685 51 1 java.lang.Object::<init> (1 bytes)
685 5 3 java.lang.Object::<init> (1 bytes) made not entrant
687 52 n 0 java.lang.invoke.MethodHandle::linkToStatic(LLLL)L (native) (static)
687 53 1 java.lang.reflect.Method::getName (5 bytes)
687 54 n 0 java.lang.invoke.MethodHandle::linkToStatic(LL)L (native) (static)
692 55 n 0 java.lang.Object::hashCode (native)
692 56 n 0 java.lang.invoke.MethodHandle::linkToStatic(LL)V (native) (static)
692 57 4 java.lang.String::charAt (29 bytes)
692 58 3 java.lang.String::indexOf (7 bytes)
692 59 1 java.lang.Class::getClassLoader0 (5 bytes)
692 60 n 0 java.lang.invoke.MethodHandle::linkToStatic(LL)J (native) (static)
693 1 3 java.lang.String::charAt (29 bytes) made not entrant
693 61 3 java.lang.String::lastIndexOf (52 bytes)
693 62 n 0 java.lang.invoke.MethodHandle::linkToStatic(LLL)L (native) (static)
694 63 1 java.lang.Enum::ordinal (5 bytes)
694 64 n 0 java.lang.Class::isPrimitive (native)
694 65 3 java.lang.invoke.MemberName::testFlags (16 bytes)
694 66 3 java.lang.Class::getName (21 bytes)
695 67 3 java.lang.ref.Reference::<init> (25 bytes)
695 68 1 java.lang.invoke.MethodType::returnType (5 bytes)
695 69 3 java.lang.AbstractStringBuilder::append (29 bytes)
695 70 1 java.lang.invoke.MemberName::getDeclaringClass (5 bytes)
696 71 3 jdk.internal.org.objectweb.asm.ByteVector::putUTF8 (142 bytes)
696 72 3 java.lang.AbstractStringBuilder::append (50 bytes)
696 74 3 jdk.internal.org.objectweb.asm.ClassWriter::get (49 bytes)
696 73 3 jdk.internal.org.objectweb.asm.Item::set (143 bytes)
696 75 3 java.lang.StringBuilder::append (8 bytes)
696 77 3 java.lang.StringBuilder::append (8 bytes)
696 76 3 jdk.internal.org.objectweb.asm.ByteVector::putShort (52 bytes)
697 78 3 jdk.internal.org.objectweb.asm.Item::<init> (66 bytes)
697 79 3 jdk.internal.org.objectweb.asm.ClassWriter::put (152 bytes)
697 80 3 java.lang.AbstractStringBuilder::<init> (12 bytes)
697 81 1 java.lang.invoke.MethodType$ConcurrentWeakInternSet$WeakEntry::hashCode (5 bytes)
697 82 3 java.lang.AbstractStringBuilder::newCapacity (39 bytes)
698 83 3 jdk.internal.org.objectweb.asm.ByteVector::putByte (39 bytes)
698 84 3 jdk.internal.org.objectweb.asm.ClassWriter::newUTF8 (70 bytes)
699 88 3 java.lang.invoke.MemberName::testAnyFlags (15 bytes)
699 87 1 java.util.SubList::access$200 (5 bytes)
699 86 1 java.util.AbstractList$ListItr::nextIndex (5 bytes)
699 85 1 java.util.SubList::access$000 (5 bytes)
699 89 3 java.lang.Class::getClassLoader (28 bytes)
699 90 3 java.util.concurrent.ConcurrentHashMap::spread (10 bytes)
699 91 1 java.lang.String::length (6 bytes)
700 4 3 java.lang.String::length (6 bytes) made not entrant
700 92 1 java.util.ArrayList::access$100 (5 bytes)
700 93 3 java.util.Objects::requireNonNull (14 bytes)
700 94 3 java.lang.invoke.MemberName::isInvocable (7 bytes)
700 95 3 java.util.concurrent.ConcurrentHashMap::setTabAt (19 bytes)
700 96 n 0 sun.misc.Unsafe::putObjectVolatile (native)
701 97 3 java.lang.String::replace (127 bytes)
701 98 1 java.util.ArrayList::size (5 bytes)
701 99 3 java.lang.String::lastIndexOf (13 bytes)
702 100 3 java.lang.ref.Reference::<init> (7 bytes)
702 101 ! 3 java.util.concurrent.ConcurrentHashMap::putVal (362 bytes)
702 102 n 0 java.lang.Object::getClass (native)
702 103 ! 3 java.lang.ref.ReferenceQueue::poll (28 bytes)
703 104 3 java.util.concurrent.ConcurrentHashMap::putIfAbsent (8 bytes)
703 105 n 0 java.lang.invoke.MethodHandle::linkToStatic(LLL)V (native) (static)
703 106 3 java.lang.StringBuilder::toString (17 bytes)
704 107 n 0 java.lang.invoke.MethodHandle::invokeBasic(LII)I (native)
704 108 n 0 java.lang.invoke.MethodHandle::linkToSpecial(LLIIL)I (native) (static)
704 109 3 java.lang.invoke.MethodTypeForm::canonicalize (233 bytes)
704 110 1 sun.invoke.util.Wrapper::basicTypeChar (5 bytes)
705 112 3 java.lang.invoke.MethodType::hashCode (53 bytes)
705 111 3 java.lang.invoke.MethodType$ConcurrentWeakInternSet::expungeStaleElements (27 bytes)
706 113 3 java.lang.StringBuilder::<init> (7 bytes)
707 114 1 java.lang.invoke.MethodType::ptypes (5 bytes)
707 115 n 0 java.lang.Class::isArray (native)
707 117 3 java.lang.invoke.MethodType::checkSlotCount (33 bytes)
707 116 3 java.lang.reflect.Modifier::isStatic (13 bytes)
708 118 n 0 java.lang.invoke.MethodHandle::linkToStatic(LLLLL)L (native) (static)
708 119 3 java.lang.invoke.MemberName::isStatic (8 bytes)
708 120 3 jdk.internal.org.objectweb.asm.ByteVector::put12 (64 bytes)
709 121 n 0 java.lang.invoke.MethodHandle::invokeBasic(LLLL)L (native)
709 122 3 jdk.internal.org.objectweb.asm.Frame::execute (2252 bytes)
709 123 3 java.lang.String::substring (79 bytes)
710 124 3 java.lang.invoke.MethodType::checkPtype (19 bytes)
710 125 n 0 java.lang.invoke.MethodHandle::invokeBasic(II)V (native)
710 126 n 0 java.lang.invoke.MethodHandle::linkToSpecial(LIIL)V (native) (static)
710 127 1 java.lang.invoke.MethodType::form (5 bytes)
710 128 n 0 java.lang.Object::clone (native)
710 129 3 java.lang.invoke.MemberName::testAllFlags (7 bytes)
711 130 3 java.lang.String::indexOf (166 bytes)
711 131 1 java.lang.invoke.LambdaForm$Name::index (5 bytes)
711 132 4 java.lang.String::hashCode (55 bytes)
712 133 3 jdk.internal.org.objectweb.asm.Item::isEqualTo (354 bytes)
712 134 3 java.lang.invoke.DirectMethodHandle::internalMemberName (8 bytes)
712 136 3 java.lang.invoke.Invokers::checkGenericType (16 bytes)
712 135 3 java.lang.invoke.LambdaForm$MH/1950409828::invoke_MT (26 bytes)
712 137 3 java.lang.invoke.MethodHandle::asType (28 bytes)
713 138 3 java.lang.invoke.MethodHandle::asTypeCached (21 bytes)
713 140 3 java.lang.invoke.LambdaForm$DMH/1670675563::invokeVirtual_LII_I (18 bytes)
713 139 3 java.lang.invoke.Invokers::checkCustomized (20 bytes)
713 142 % 3 MethodHandleTest::main @ 309 (619 bytes)
713 141 3 java.lang.invoke.LambdaForm$BMH/2016447921::reinvoke (34 bytes)
714 143 4 java.lang.invoke.LambdaForm$MH/1950409828::invoke_MT (26 bytes)
714 144 4 java.lang.invoke.LambdaForm$BMH/2016447921::reinvoke (34 bytes)
714 3 3 java.lang.String::hashCode (55 bytes) made not entrant
714 141 3 java.lang.invoke.LambdaForm$BMH/2016447921::reinvoke (34 bytes) made not entrant
716 135 3 java.lang.invoke.LambdaForm$MH/1950409828::invoke_MT (26 bytes) made not entrant
721 145 4 java.lang.invoke.MethodHandle::asType (28 bytes)
721 146 % 4 MethodHandleTest::main @ 309 (619 bytes)
721 137 3 java.lang.invoke.MethodHandle::asType (28 bytes) made not entrant
724 142 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
782 146 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
methodhandle call warm-up end, time consumed = 73
warm-up end
test begin
plain call test begin
782 147 % 3 MethodHandleTest::main @ 397 (619 bytes)
792 148 % 4 MethodHandleTest::main @ 397 (619 bytes)
794 147 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
794 148 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
plain call test end, time consumed = 12
reflection call test begin 795
149 1 java.nio.Buffer::position (5 bytes)
795 150 3 java.lang.Integer::valueOf (32 bytes)
795 151 4 java.lang.Integer::<init> (10 bytes)
795 152 % 3 MethodHandleTest::main @ 471 (619 bytes)
795 32 3 java.lang.Integer::<init> (10 bytes) made not entrant
796 153 4 java.lang.Integer::valueOf (32 bytes)
797 150 3 java.lang.Integer::valueOf (32 bytes) made not entrant
805 154 % 4 MethodHandleTest::main @ 471 (619 bytes)
816 152 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
948 154 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
reflection call test end, time consumed = 153
methodhandle call warm-up begin
949 155 % 3 MethodHandleTest::main @ 562 (619 bytes)
957 156 % 4 MethodHandleTest::main @ 562 (619 bytes)
960 155 % 3 MethodHandleTest::main @ -2 (619 bytes) made not entrant
1014 156 % 4 MethodHandleTest::main @ -2 (619 bytes) made not entrant
methodhandle call warm-up end, time consumed = 65
[xiaoju@ed3e13fd9af6 test_method_handle]$