< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Print this page

2786          * If the returned method handle is invoked, the constructor's class will
2787          * be initialized, if it has not already been initialized.
2788          * <p><b>Example:</b>
2789          * {@snippet lang="java" :
2790 import static java.lang.invoke.MethodHandles.*;
2791 import static java.lang.invoke.MethodType.*;
2792 ...
2793 MethodHandle MH_newArrayList = publicLookup().findConstructor(
2794   ArrayList.class, methodType(void.class, Collection.class));
2795 Collection orig = Arrays.asList("x", "y");
2796 Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
2797 assert(orig != copy);
2798 assertEquals(orig, copy);
2799 // a variable-arity constructor:
2800 MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
2801   ProcessBuilder.class, methodType(void.class, String[].class));
2802 ProcessBuilder pb = (ProcessBuilder)
2803   MH_newProcessBuilder.invoke("x", "y", "z");
2804 assertEquals("[x, y, z]", pb.command().toString());
2805          * }


2806          * @param refc the class or interface from which the method is accessed
2807          * @param type the type of the method, with the receiver argument omitted, and a void return type
2808          * @return the desired method handle
2809          * @throws NoSuchMethodException if the constructor does not exist
2810          * @throws IllegalAccessException if access checking fails
2811          *                                or if the method's variable arity modifier bit
2812          *                                is set and {@code asVarargsCollector} fails
2813          * @throws    SecurityException if a security manager is present and it
2814          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
2815          * @throws NullPointerException if any argument is null
2816          */
2817         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
2818             if (refc.isArray()) {
2819                 throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
2820             }



2821             String name = ConstantDescs.INIT_NAME;
2822             MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
2823             return getDirectConstructor(refc, ctor);
2824         }
2825 
2826         /**
2827          * Looks up a class by name from the lookup context defined by this {@code Lookup} object,
2828          * <a href="MethodHandles.Lookup.html#equiv">as if resolved</a> by an {@code ldc} instruction.
2829          * Such a resolution, as specified in JVMS {@jvms 5.4.3.1}, attempts to locate and load the class,
2830          * and then determines whether the class is accessible to this lookup object.
2831          * <p>
2832          * For a class or an interface, the name is the {@linkplain ClassLoader##binary-name binary name}.
2833          * For an array class of {@code n} dimensions, the name begins with {@code n} occurrences
2834          * of {@code '['} and followed by the element type as encoded in the
2835          * {@linkplain Class##nameFormat table} specified in {@link Class#getName}.
2836          * <p>
2837          * The lookup context here is determined by the {@linkplain #lookupClass() lookup class},
2838          * its class loader, and the {@linkplain #lookupModes() lookup modes}.
2839          *
2840          * @param targetName the {@linkplain ClassLoader##binary-name binary name} of the class

4069             final boolean doRestrict    = false;
4070             final boolean checkSecurity = true;
4071             return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, callerLookup);
4072         }
4073         /** Check access and get the requested method, eliding security manager checks. */
4074         private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Lookup callerLookup) throws IllegalAccessException {
4075             final boolean doRestrict    = true;
4076             final boolean checkSecurity = false;  // not needed for reflection or for linking CONSTANT_MH constants
4077             return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerLookup);
4078         }
4079         /** Common code for all methods; do not call directly except from immediately above. */
4080         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
4081                                                    boolean checkSecurity,
4082                                                    boolean doRestrict,
4083                                                    Lookup boundCaller) throws IllegalAccessException {
4084             checkMethod(refKind, refc, method);
4085             // Optionally check with the security manager; this isn't needed for unreflect* calls.
4086             if (checkSecurity)
4087                 checkSecurityManager(refc, method);
4088             assert(!method.isMethodHandleInvoke());
4089 
4090             if (refKind == REF_invokeSpecial &&
4091                 refc != lookupClass() &&
4092                 !refc.isInterface() && !lookupClass().isInterface() &&
4093                 refc != lookupClass().getSuperclass() &&
4094                 refc.isAssignableFrom(lookupClass())) {
4095                 assert(!method.getName().equals(ConstantDescs.INIT_NAME));  // not this code path
4096 
4097                 // Per JVMS 6.5, desc. of invokespecial instruction:
4098                 // If the method is in a superclass of the LC,
4099                 // and if our original search was above LC.super,
4100                 // repeat the search (symbolic lookup) from LC.super
4101                 // and continue with the direct superclass of that class,
4102                 // and so forth, until a match is found or no further superclasses exist.
4103                 // FIXME: MemberName.resolve should handle this instead.
4104                 Class<?> refcAsSuper = lookupClass();
4105                 MemberName m2;
4106                 do {
4107                     refcAsSuper = refcAsSuper.getSuperclass();
4108                     m2 = new MemberName(refcAsSuper,
4109                                         method.getName(),

5169     }
5170 
5171     /**
5172      * Produces a constant method handle of the requested return type which
5173      * returns the default value for that type every time it is invoked.
5174      * The resulting constant method handle will have no side effects.
5175      * <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
5176      * It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
5177      * since {@code explicitCastArguments} converts {@code null} to default values.
5178      * @param type the expected return type of the desired method handle
5179      * @return a constant method handle that takes no arguments
5180      *         and returns the default value of the given type (or void, if the type is void)
5181      * @throws NullPointerException if the argument is null
5182      * @see MethodHandles#constant
5183      * @see MethodHandles#empty
5184      * @see MethodHandles#explicitCastArguments
5185      * @since 9
5186      */
5187     public static MethodHandle zero(Class<?> type) {
5188         Objects.requireNonNull(type);
5189         return type.isPrimitive() ?  zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);




5190     }
5191 
5192     private static MethodHandle identityOrVoid(Class<?> type) {
5193         return type == void.class ? zero(type) : identity(type);
5194     }
5195 
5196     /**
5197      * Produces a method handle of the requested type which ignores any arguments, does nothing,
5198      * and returns a suitable default depending on the return type.
5199      * That is, it returns a zero primitive value, a {@code null}, or {@code void}.
5200      * <p>The returned method handle is equivalent to
5201      * {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
5202      *
5203      * @apiNote Given a predicate and target, a useful "if-then" construct can be produced as
5204      * {@code guardWithTest(pred, target, empty(target.type())}.
5205      * @param type the type of the desired method handle
5206      * @return a constant method handle of the given type, which returns a default value of the given return type
5207      * @throws NullPointerException if the argument is null
5208      * @see MethodHandles#zero
5209      * @see MethodHandles#constant

2786          * If the returned method handle is invoked, the constructor's class will
2787          * be initialized, if it has not already been initialized.
2788          * <p><b>Example:</b>
2789          * {@snippet lang="java" :
2790 import static java.lang.invoke.MethodHandles.*;
2791 import static java.lang.invoke.MethodType.*;
2792 ...
2793 MethodHandle MH_newArrayList = publicLookup().findConstructor(
2794   ArrayList.class, methodType(void.class, Collection.class));
2795 Collection orig = Arrays.asList("x", "y");
2796 Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
2797 assert(orig != copy);
2798 assertEquals(orig, copy);
2799 // a variable-arity constructor:
2800 MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
2801   ProcessBuilder.class, methodType(void.class, String[].class));
2802 ProcessBuilder pb = (ProcessBuilder)
2803   MH_newProcessBuilder.invoke("x", "y", "z");
2804 assertEquals("[x, y, z]", pb.command().toString());
2805          * }
2806          *
2807          *
2808          * @param refc the class or interface from which the method is accessed
2809          * @param type the type of the method, with the receiver argument omitted, and a void return type
2810          * @return the desired method handle
2811          * @throws NoSuchMethodException if the constructor does not exist
2812          * @throws IllegalAccessException if access checking fails
2813          *                                or if the method's variable arity modifier bit
2814          *                                is set and {@code asVarargsCollector} fails
2815          * @throws    SecurityException if a security manager is present and it
2816          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
2817          * @throws NullPointerException if any argument is null
2818          */
2819         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
2820             if (refc.isArray()) {
2821                 throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
2822             }
2823             if (type.returnType() != void.class) {
2824                 throw new NoSuchMethodException("Constructors must have void return type: " + refc.getName());
2825             }
2826             String name = ConstantDescs.INIT_NAME;
2827             MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
2828             return getDirectConstructor(refc, ctor);
2829         }
2830 
2831         /**
2832          * Looks up a class by name from the lookup context defined by this {@code Lookup} object,
2833          * <a href="MethodHandles.Lookup.html#equiv">as if resolved</a> by an {@code ldc} instruction.
2834          * Such a resolution, as specified in JVMS {@jvms 5.4.3.1}, attempts to locate and load the class,
2835          * and then determines whether the class is accessible to this lookup object.
2836          * <p>
2837          * For a class or an interface, the name is the {@linkplain ClassLoader##binary-name binary name}.
2838          * For an array class of {@code n} dimensions, the name begins with {@code n} occurrences
2839          * of {@code '['} and followed by the element type as encoded in the
2840          * {@linkplain Class##nameFormat table} specified in {@link Class#getName}.
2841          * <p>
2842          * The lookup context here is determined by the {@linkplain #lookupClass() lookup class},
2843          * its class loader, and the {@linkplain #lookupModes() lookup modes}.
2844          *
2845          * @param targetName the {@linkplain ClassLoader##binary-name binary name} of the class

4074             final boolean doRestrict    = false;
4075             final boolean checkSecurity = true;
4076             return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, callerLookup);
4077         }
4078         /** Check access and get the requested method, eliding security manager checks. */
4079         private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Lookup callerLookup) throws IllegalAccessException {
4080             final boolean doRestrict    = true;
4081             final boolean checkSecurity = false;  // not needed for reflection or for linking CONSTANT_MH constants
4082             return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerLookup);
4083         }
4084         /** Common code for all methods; do not call directly except from immediately above. */
4085         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
4086                                                    boolean checkSecurity,
4087                                                    boolean doRestrict,
4088                                                    Lookup boundCaller) throws IllegalAccessException {
4089             checkMethod(refKind, refc, method);
4090             // Optionally check with the security manager; this isn't needed for unreflect* calls.
4091             if (checkSecurity)
4092                 checkSecurityManager(refc, method);
4093             assert(!method.isMethodHandleInvoke());

4094             if (refKind == REF_invokeSpecial &&
4095                 refc != lookupClass() &&
4096                 !refc.isInterface() && !lookupClass().isInterface() &&
4097                 refc != lookupClass().getSuperclass() &&
4098                 refc.isAssignableFrom(lookupClass())) {
4099                 assert(!method.getName().equals(ConstantDescs.INIT_NAME));  // not this code path
4100 
4101                 // Per JVMS 6.5, desc. of invokespecial instruction:
4102                 // If the method is in a superclass of the LC,
4103                 // and if our original search was above LC.super,
4104                 // repeat the search (symbolic lookup) from LC.super
4105                 // and continue with the direct superclass of that class,
4106                 // and so forth, until a match is found or no further superclasses exist.
4107                 // FIXME: MemberName.resolve should handle this instead.
4108                 Class<?> refcAsSuper = lookupClass();
4109                 MemberName m2;
4110                 do {
4111                     refcAsSuper = refcAsSuper.getSuperclass();
4112                     m2 = new MemberName(refcAsSuper,
4113                                         method.getName(),

5173     }
5174 
5175     /**
5176      * Produces a constant method handle of the requested return type which
5177      * returns the default value for that type every time it is invoked.
5178      * The resulting constant method handle will have no side effects.
5179      * <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
5180      * It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
5181      * since {@code explicitCastArguments} converts {@code null} to default values.
5182      * @param type the expected return type of the desired method handle
5183      * @return a constant method handle that takes no arguments
5184      *         and returns the default value of the given type (or void, if the type is void)
5185      * @throws NullPointerException if the argument is null
5186      * @see MethodHandles#constant
5187      * @see MethodHandles#empty
5188      * @see MethodHandles#explicitCastArguments
5189      * @since 9
5190      */
5191     public static MethodHandle zero(Class<?> type) {
5192         Objects.requireNonNull(type);
5193         if (type.isPrimitive()) {
5194             return zero(Wrapper.forPrimitiveType(type), type);
5195         } else {
5196             return zero(Wrapper.OBJECT, type);
5197         }
5198     }
5199 
5200     private static MethodHandle identityOrVoid(Class<?> type) {
5201         return type == void.class ? zero(type) : identity(type);
5202     }
5203 
5204     /**
5205      * Produces a method handle of the requested type which ignores any arguments, does nothing,
5206      * and returns a suitable default depending on the return type.
5207      * That is, it returns a zero primitive value, a {@code null}, or {@code void}.
5208      * <p>The returned method handle is equivalent to
5209      * {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
5210      *
5211      * @apiNote Given a predicate and target, a useful "if-then" construct can be produced as
5212      * {@code guardWithTest(pred, target, empty(target.type())}.
5213      * @param type the type of the desired method handle
5214      * @return a constant method handle of the given type, which returns a default value of the given return type
5215      * @throws NullPointerException if the argument is null
5216      * @see MethodHandles#zero
5217      * @see MethodHandles#constant
< prev index next >