< prev index next >

src/java.base/share/classes/java/lang/Class.java

Print this page

        

@@ -24,10 +24,12 @@
  */
 
 package java.lang;
 
 import java.lang.annotation.Annotation;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReader;
 import java.lang.ref.SoftReference;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamField;

@@ -38,10 +40,11 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Field;
 import java.lang.reflect.GenericArrayType;
 import java.lang.reflect.GenericDeclaration;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Layer;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Module;
 import java.lang.reflect.Proxy;

@@ -49,26 +52,31 @@
 import java.lang.reflect.TypeVariable;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.loader.ResourceHelper;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.misc.VM;
+import jdk.internal.module.ModuleHashes;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.ConstantPool;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
 import jdk.internal.vm.annotation.ForceInline;

@@ -522,12 +530,11 @@
                     "Can not call newInstance() on the Class for java.lang.Class"
                 );
             }
             try {
                 Class<?>[] empty = {};
-                final Constructor<T> c = getReflectionFactory().copyConstructor(
-                    getConstructor0(empty, Member.DECLARED));
+                final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                 // Disable accessibility checks on the constructor
                 // since we have to do the security check here anyway
                 // (the stack depth is wrong for the Constructor's
                 // security check to work)
                 java.security.AccessController.doPrivileged(

@@ -1015,27 +1022,22 @@
      * returned in that order.
      *
      * @return an array of interfaces directly implemented by this class
      */
     public Class<?>[] getInterfaces() {
-        // defensively copy before handing over to user code
-        return getInterfaces(true);
-    }
-
-    private Class<?>[] getInterfaces(boolean cloneArray) {
         ReflectionData<T> rd = reflectionData();
         if (rd == null) {
             // no cloning required
             return getInterfaces0();
         } else {
             Class<?>[] interfaces = rd.interfaces;
             if (interfaces == null) {
                 interfaces = getInterfaces0();
                 rd.interfaces = interfaces;
             }
-            // defensively copy if requested
-            return cloneArray ? interfaces.clone() : interfaces;
+            // defensively copy before handing over to user code
+            return interfaces.clone();
         }
     }
 
     private native Class<?>[] getInterfaces0();
 

@@ -1763,10 +1765,19 @@
      * Returns an array containing {@code Method} objects reflecting all the
      * public methods of the class or interface represented by this {@code
      * Class} object, including those declared by the class or interface and
      * those inherited from superclasses and superinterfaces.
      *
+     * <p> If this {@code Class} object represents a type that has multiple
+     * public methods with the same name and parameter types, but different
+     * return types, then the returned array has a {@code Method} object for
+     * each such method.
+     *
+     * <p> If this {@code Class} object represents a type with a class
+     * initialization method {@code <clinit>}, then the returned array does
+     * <em>not</em> have a corresponding {@code Method} object.
+     *
      * <p> If this {@code Class} object represents an array type, then the
      * returned array has a {@code Method} object for each of the public
      * methods inherited by the array type from {@code Object}. It does not
      * contain a {@code Method} object for {@code clone()}.
      *

@@ -1775,58 +1786,20 @@
      * {@code Object}. Therefore, if no methods are explicitly declared in
      * this interface or any of its superinterfaces then the returned array
      * has length 0. (Note that a {@code Class} object which represents a class
      * always has public methods, inherited from {@code Object}.)
      *
-     * <p> The returned array never contains methods with names "{@code <init>}"
-     * or "{@code <clinit>}".
+     * <p> If this {@code Class} object represents a primitive type or void,
+     * then the returned array has length 0.
+     *
+     * <p> Static methods declared in superinterfaces of the class or interface
+     * represented by this {@code Class} object are not considered members of
+     * the class or interface.
      *
      * <p> The elements in the returned array are not sorted and are not in any
      * particular order.
      *
-     * <p> Generally, the result is computed as with the following 4 step algorithm.
-     * Let C be the class or interface represented by this {@code Class} object:
-     * <ol>
-     * <li> A union of methods is composed of:
-     *   <ol type="a">
-     *   <li> C's declared public instance and static methods as returned by
-     *        {@link #getDeclaredMethods()} and filtered to include only public
-     *        methods.</li>
-     *   <li> If C is a class other than {@code Object}, then include the result
-     *        of invoking this algorithm recursively on the superclass of C.</li>
-     *   <li> Include the results of invoking this algorithm recursively on all
-     *        direct superinterfaces of C, but include only instance methods.</li>
-     *   </ol></li>
-     * <li> Union from step 1 is partitioned into subsets of methods with same
-     *      signature (name, parameter types) and return type.</li>
-     * <li> Within each such subset only the most specific methods are selected.
-     *      Let method M be a method from a set of methods with same signature
-     *      and return type. M is most specific if there is no such method
-     *      N != M from the same set, such that N is more specific than M.
-     *      N is more specific than M if:
-     *   <ol type="a">
-     *   <li> N is declared by a class and M is declared by an interface; or</li>
-     *   <li> N and M are both declared by classes or both by interfaces and
-     *        N's declaring type is the same as or a subtype of M's declaring type
-     *        (clearly, if M's and N's declaring types are the same type, then
-     *        M and N are the same method).</li>
-     *   </ol></li>
-     * <li> The result of this algorithm is the union of all selected methods from
-     *      step 3.</li>
-     * </ol>
-     *
-     * @apiNote There may be more than one method with a particular name
-     * and parameter types in a class because while the Java language forbids a
-     * class to declare multiple methods with the same signature but different
-     * return types, the Java virtual machine does not.  This
-     * increased flexibility in the virtual machine can be used to
-     * implement various language features.  For example, covariant
-     * returns can be implemented with {@linkplain
-     * java.lang.reflect.Method#isBridge bridge methods}; the bridge
-     * method and the overriding method would have the same
-     * signature but different return types.
-     *
      * @return the array of {@code Method} objects representing the
      *         public methods of this class
      * @throws SecurityException
      *         If a security manager, <i>s</i>, is present and
      *         the caller's class loader is not the same as or an

@@ -1930,11 +1903,11 @@
         checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
         Field field = getField0(name);
         if (field == null) {
             throw new NoSuchFieldException(name);
         }
-        return getReflectionFactory().copyField(field);
+        return field;
     }
 
 
     /**
      * Returns a {@code Method} object that reflects the specified public

@@ -1944,73 +1917,51 @@
      * {@code parameterTypes} parameter is an array of {@code Class}
      * objects that identify the method's formal parameter types, in declared
      * order. If {@code parameterTypes} is {@code null}, it is
      * treated as if it were an empty array.
      *
-     * <p> If this {@code Class} object represents an array type, then this
-     * method finds any public method inherited by the array type from
-     * {@code Object} except method {@code clone()}.
-     *
-     * <p> If this {@code Class} object represents an interface then this
-     * method does not find any implicitly declared method from
-     * {@code Object}. Therefore, if no methods are explicitly declared in
-     * this interface or any of its superinterfaces, then this method does not
-     * find any method.
+     * <p> If the {@code name} is "{@code <init>}" or "{@code <clinit>}" a
+     * {@code NoSuchMethodException} is raised. Otherwise, the method to
+     * be reflected is determined by the algorithm that follows.  Let C be the
+     * class or interface represented by this object:
+     * <OL>
+     * <LI> C is searched for a <I>matching method</I>, as defined below. If a
+     *      matching method is found, it is reflected.</LI>
+     * <LI> If no matching method is found by step 1 then:
+     *   <OL TYPE="a">
+     *   <LI> If C is a class other than {@code Object}, then this algorithm is
+     *        invoked recursively on the superclass of C.</LI>
+     *   <LI> If C is the class {@code Object}, or if C is an interface, then
+     *        the superinterfaces of C (if any) are searched for a matching
+     *        method. If any such method is found, it is reflected.</LI>
+     *   </OL></LI>
+     * </OL>
      *
-     * <p> This method does not find any method with name "{@code <init>}" or
-     * "{@code <clinit>}".
+     * <p> To find a matching method in a class or interface C:&nbsp; If C
+     * declares exactly one public method with the specified name and exactly
+     * the same formal parameter types, that is the method reflected. If more
+     * than one such method is found in C, and one of these methods has a
+     * return type that is more specific than any of the others, that method is
+     * reflected; otherwise one of the methods is chosen arbitrarily.
      *
-     * <p> Generally, the method to be reflected is determined by the 4 step
-     * algorithm that follows.
-     * Let C be the class or interface represented by this {@code Class} object:
-     * <ol>
-     * <li> A union of methods is composed of:
-     *   <ol type="a">
-     *   <li> C's declared public instance and static methods as returned by
-     *        {@link #getDeclaredMethods()} and filtered to include only public
-     *        methods that match given {@code name} and {@code parameterTypes}</li>
-     *   <li> If C is a class other than {@code Object}, then include the result
-     *        of invoking this algorithm recursively on the superclass of C.</li>
-     *   <li> Include the results of invoking this algorithm recursively on all
-     *        direct superinterfaces of C, but include only instance methods.</li>
-     *   </ol></li>
-     * <li> This union is partitioned into subsets of methods with same
-     *      return type (the selection of methods from step 1 also guarantees that
-     *      they have the same method name and parameter types).</li>
-     * <li> Within each such subset only the most specific methods are selected.
-     *      Let method M be a method from a set of methods with same VM
-     *      signature (return type, name, parameter types).
-     *      M is most specific if there is no such method N != M from the same
-     *      set, such that N is more specific than M. N is more specific than M
-     *      if:
-     *   <ol type="a">
-     *   <li> N is declared by a class and M is declared by an interface; or</li>
-     *   <li> N and M are both declared by classes or both by interfaces and
-     *        N's declaring type is the same as or a subtype of M's declaring type
-     *        (clearly, if M's and N's declaring types are the same type, then
-     *        M and N are the same method).</li>
-     *   </ol></li>
-     * <li> The result of this algorithm is chosen arbitrarily from the methods
-     *      with most specific return type among all selected methods from step 3.
-     *      Let R be a return type of a method M from the set of all selected methods
-     *      from step 3. M is a method with most specific return type if there is
-     *      no such method N != M from the same set, having return type S != R,
-     *      such that S is a subtype of R as determined by
-     *      R.class.{@link #isAssignableFrom}(S.class).
-     * </ol>
-     *
-     * @apiNote There may be more than one method with matching name and
-     * parameter types in a class because while the Java language forbids a
-     * class to declare multiple methods with the same signature but different
+     * <p>Note that there may be more than one matching method in a
+     * class because while the Java language forbids a class to
+     * declare multiple methods with the same signature but different
      * return types, the Java virtual machine does not.  This
      * increased flexibility in the virtual machine can be used to
      * implement various language features.  For example, covariant
      * returns can be implemented with {@linkplain
      * java.lang.reflect.Method#isBridge bridge methods}; the bridge
-     * method and the overriding method would have the same
-     * signature but different return types. This method would return the
-     * overriding method as it would have a more specific return type.
+     * method and the method being overridden would have the same
+     * signature but different return types.
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code clone()} method.
+     *
+     * <p> Static methods declared in superinterfaces of the class or interface
+     * represented by this {@code Class} object are not considered members of
+     * the class or interface.
      *
      * @param name the name of the method
      * @param parameterTypes the list of parameters
      * @return the {@code Method} object that matches the specified
      *         {@code name} and {@code parameterTypes}

@@ -2031,15 +1982,15 @@
      */
     @CallerSensitive
     public Method getMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
         checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
-        Method method = getMethod0(name, parameterTypes);
+        Method method = getMethod0(name, parameterTypes, true);
         if (method == null) {
             throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
         }
-        return getReflectionFactory().copyMethod(method);
+        return method;
     }
 
     /**
      * Returns a {@code Method} object that reflects the specified public
      * member method of the class or interface represented by this

@@ -2051,12 +2002,11 @@
      *         {@code name} and {@code parameterTypes}; {@code null}
      *         if the method is not found or the name is
      *         "&lt;init&gt;"or "&lt;clinit&gt;".
      */
     Method getMethodOrNull(String name, Class<?>... parameterTypes) {
-        Method method = getMethod0(name, parameterTypes);
-        return method == null ? null : getReflectionFactory().copyMethod(method);
+        return getMethod0(name, parameterTypes, true);
     }
 
 
     /**
      * Returns a {@code Constructor} object that reflects the specified

@@ -2089,12 +2039,11 @@
      */
     @CallerSensitive
     public Constructor<T> getConstructor(Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
         checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
-        return getReflectionFactory().copyConstructor(
-            getConstructor0(parameterTypes, Member.PUBLIC));
+        return getConstructor0(parameterTypes, Member.PUBLIC);
     }
 
 
     /**
      * Returns an array of {@code Class} objects reflecting all the

@@ -2337,11 +2286,11 @@
         checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         Field field = searchFields(privateGetDeclaredFields(false), name);
         if (field == null) {
             throw new NoSuchFieldException(name);
         }
-        return getReflectionFactory().copyField(field);
+        return field;
     }
 
 
     /**
      * Returns a {@code Method} object that reflects the specified

@@ -2397,11 +2346,11 @@
         checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
         Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
         if (method == null) {
             throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
         }
-        return getReflectionFactory().copyMethod(method);
+        return method;
     }
 
 
     /**
      * Returns a {@code Constructor} object that reflects the specified

@@ -2443,12 +2392,11 @@
      */
     @CallerSensitive
     public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
         checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
-        return getReflectionFactory().copyConstructor(
-            getConstructor0(parameterTypes, Member.DECLARED));
+        return getConstructor0(parameterTypes, Member.DECLARED);
     }
 
     /**
      * Finds a resource with a given name.
      *

@@ -3054,10 +3002,184 @@
             }
         }
         return res;
     }
 
+    static class MethodArray {
+        // Don't add or remove methods except by add() or remove() calls.
+        private Method[] methods;
+        private int length;
+        private int defaults;
+
+        MethodArray() {
+            this(20);
+        }
+
+        MethodArray(int initialSize) {
+            if (initialSize < 2)
+                throw new IllegalArgumentException("Size should be 2 or more");
+
+            methods = new Method[initialSize];
+            length = 0;
+            defaults = 0;
+        }
+
+        boolean hasDefaults() {
+            return defaults != 0;
+        }
+
+        void add(Method m) {
+            if (length == methods.length) {
+                methods = Arrays.copyOf(methods, 2 * methods.length);
+            }
+            methods[length++] = m;
+
+            if (m != null && m.isDefault())
+                defaults++;
+        }
+
+        void addAll(Method[] ma) {
+            for (Method m : ma) {
+                add(m);
+            }
+        }
+
+        void addAll(MethodArray ma) {
+            for (int i = 0; i < ma.length(); i++) {
+                add(ma.get(i));
+            }
+        }
+
+        void addIfNotPresent(Method newMethod) {
+            for (int i = 0; i < length; i++) {
+                Method m = methods[i];
+                if (m == newMethod || (m != null && m.equals(newMethod))) {
+                    return;
+                }
+            }
+            add(newMethod);
+        }
+
+        void addAllIfNotPresent(MethodArray newMethods) {
+            for (int i = 0; i < newMethods.length(); i++) {
+                Method m = newMethods.get(i);
+                if (m != null) {
+                    addIfNotPresent(m);
+                }
+            }
+        }
+
+        /* Add Methods declared in an interface to this MethodArray.
+         * Static methods declared in interfaces are not inherited.
+         */
+        void addInterfaceMethods(Method[] methods) {
+            for (Method candidate : methods) {
+                if (!Modifier.isStatic(candidate.getModifiers())) {
+                    add(candidate);
+                }
+            }
+        }
+
+        int length() {
+            return length;
+        }
+
+        Method get(int i) {
+            return methods[i];
+        }
+
+        Method getFirst() {
+            for (Method m : methods)
+                if (m != null)
+                    return m;
+            return null;
+        }
+
+        void removeByNameAndDescriptor(Method toRemove) {
+            for (int i = 0; i < length; i++) {
+                Method m = methods[i];
+                if (m != null && matchesNameAndDescriptor(m, toRemove)) {
+                    remove(i);
+                }
+            }
+        }
+
+        private void remove(int i) {
+            if (methods[i] != null && methods[i].isDefault())
+                defaults--;
+                    methods[i] = null;
+                }
+
+        private boolean matchesNameAndDescriptor(Method m1, Method m2) {
+            return m1.getReturnType() == m2.getReturnType() &&
+                   m1.getName() == m2.getName() && // name is guaranteed to be interned
+                   arrayContentsEq(m1.getParameterTypes(),
+                           m2.getParameterTypes());
+            }
+
+        void compactAndTrim() {
+            int newPos = 0;
+            // Get rid of null slots
+            for (int pos = 0; pos < length; pos++) {
+                Method m = methods[pos];
+                if (m != null) {
+                    if (pos != newPos) {
+                        methods[newPos] = m;
+                    }
+                    newPos++;
+                }
+            }
+            if (newPos != methods.length) {
+                methods = Arrays.copyOf(methods, newPos);
+            }
+        }
+
+        /* Removes all Methods from this MethodArray that have a more specific
+         * default Method in this MethodArray.
+         *
+         * Users of MethodArray are responsible for pruning Methods that have
+         * a more specific <em>concrete</em> Method.
+         */
+        void removeLessSpecifics() {
+            if (!hasDefaults())
+                return;
+
+            for (int i = 0; i < length; i++) {
+                Method m = get(i);
+                if  (m == null || !m.isDefault())
+                    continue;
+
+                for (int j  = 0; j < length; j++) {
+                    if (i == j)
+                        continue;
+
+                    Method candidate = get(j);
+                    if (candidate == null)
+                        continue;
+
+                    if (!matchesNameAndDescriptor(m, candidate))
+                        continue;
+
+                    if (hasMoreSpecificClass(m, candidate))
+                        remove(j);
+                }
+            }
+        }
+
+        Method[] getArray() {
+            return methods;
+        }
+
+        // Returns true if m1 is more specific than m2
+        static boolean hasMoreSpecificClass(Method m1, Method m2) {
+            Class<?> m1Class = m1.getDeclaringClass();
+            Class<?> m2Class = m2.getDeclaringClass();
+            return m1Class != m2Class && m2Class.isAssignableFrom(m1Class);
+        }
+    }
+
+
     // Returns an array of "root" methods. These Method objects must NOT
     // be propagated to the outside world, but must instead be copied
     // via ReflectionFactory.copyMethod.
     private Method[] privateGetPublicMethods() {
         Method[] res;

@@ -3066,33 +3188,55 @@
             res = rd.publicMethods;
             if (res != null) return res;
         }
 
         // No cached value available; compute value recursively.
-        // Start by fetching public declared methods...
-        PublicMethods pms = new PublicMethods();
-        for (Method m : privateGetDeclaredMethods(/* publicOnly */ true)) {
-            pms.merge(m);
-        }
-        // ...then recur over superclass methods...
-        Class<?> sc = getSuperclass();
-        if (sc != null) {
-            for (Method m : sc.privateGetPublicMethods()) {
-                pms.merge(m);
-            }
-        }
-        // ...and finally over direct superinterfaces.
-        for (Class<?> intf : getInterfaces(/* cloneArray */ false)) {
-            for (Method m : intf.privateGetPublicMethods()) {
-                // static interface methods are not inherited
-                if (!Modifier.isStatic(m.getModifiers())) {
-                    pms.merge(m);
-                }
+        // Start by fetching public declared methods
+        MethodArray methods = new MethodArray();
+        {
+            Method[] tmp = privateGetDeclaredMethods(true);
+            methods.addAll(tmp);
             }
+        // Now recur over superclass and direct superinterfaces.
+        // Go over superinterfaces first so we can more easily filter
+        // out concrete implementations inherited from superclasses at
+        // the end.
+        MethodArray inheritedMethods = new MethodArray();
+        for (Class<?> i : getInterfaces()) {
+            inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
         }
-
-        res = pms.toArray();
+        if (!isInterface()) {
+            Class<?> c = getSuperclass();
+            if (c != null) {
+                MethodArray supers = new MethodArray();
+                supers.addAll(c.privateGetPublicMethods());
+                // Filter out concrete implementations of any
+                // interface methods
+                for (int i = 0; i < supers.length(); i++) {
+                    Method m = supers.get(i);
+                    if (m != null &&
+                            !Modifier.isAbstract(m.getModifiers()) &&
+                            !m.isDefault()) {
+                        inheritedMethods.removeByNameAndDescriptor(m);
+                    }
+                }
+                // Insert superclass's inherited methods before
+                // superinterfaces' to satisfy getMethod's search
+                // order
+                supers.addAll(inheritedMethods);
+                inheritedMethods = supers;
+            }
+        }
+        // Filter out all local methods from inherited ones
+        for (int i = 0; i < methods.length(); i++) {
+            Method m = methods.get(i);
+            inheritedMethods.removeByNameAndDescriptor(m);
+        }
+        methods.addAllIfNotPresent(inheritedMethods);
+        methods.removeLessSpecifics();
+        methods.compactAndTrim();
+        res = methods.getArray();
         if (rd != null) {
             rd.publicMethods = res;
         }
         return res;
     }

@@ -3100,24 +3244,21 @@
 
     //
     // Helpers for fetchers of one field, method, or constructor
     //
 
-    // This method does not copy the returned Field object!
     private static Field searchFields(Field[] fields, String name) {
+        String internedName = name.intern();
         for (Field field : fields) {
-            if (field.getName().equals(name)) {
-                return field;
+            if (field.getName() == internedName) {
+                return getReflectionFactory().copyField(field);
             }
         }
         return null;
     }
 
-    // Returns a "root" Field object. This Field object must NOT
-    // be propagated to the outside world, but must instead be copied
-    // via ReflectionFactory.copyField.
-    private Field getField0(String name) {
+    private Field getField0(String name) throws NoSuchFieldException {
         // Note: the intent is that the search algorithm this routine
         // uses be equivalent to the ordering imposed by
         // privateGetPublicFields(). It fetches only the declared
         // public fields for each class, however, to reduce the number
         // of Field objects which have to be created for the common

@@ -3127,11 +3268,11 @@
         // Search declared public fields
         if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
             return res;
         }
         // Direct superinterfaces, recursively
-        Class<?>[] interfaces = getInterfaces(/* cloneArray */ false);
+        Class<?>[] interfaces = getInterfaces();
         for (Class<?> c : interfaces) {
             if ((res = c.getField0(name)) != null) {
                 return res;
             }
         }

@@ -3145,89 +3286,91 @@
             }
         }
         return null;
     }
 
-    // This method does not copy the returned Method object!
     private static Method searchMethods(Method[] methods,
                                         String name,
                                         Class<?>[] parameterTypes)
     {
-        ReflectionFactory fact = getReflectionFactory();
         Method res = null;
+        String internedName = name.intern();
         for (Method m : methods) {
-            if (m.getName().equals(name)
-                && arrayContentsEq(parameterTypes,
-                                   fact.getExecutableSharedParameterTypes(m))
+            if (m.getName() == internedName
+                && arrayContentsEq(parameterTypes, m.getParameterTypes())
                 && (res == null
-                    || (res.getReturnType() != m.getReturnType()
-                        && res.getReturnType().isAssignableFrom(m.getReturnType()))))
+                    || res.getReturnType().isAssignableFrom(m.getReturnType())))
                 res = m;
         }
-        return res;
+
+        return (res == null ? res : getReflectionFactory().copyMethod(res));
     }
 
-    private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+    private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
+        MethodArray interfaceCandidates = new MethodArray(2);
+        Method res =  privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
+        if (res != null)
+            return res;
 
-    // Returns a "root" Method object. This Method object must NOT
-    // be propagated to the outside world, but must instead be copied
-    // via ReflectionFactory.copyMethod.
-    private Method getMethod0(String name, Class<?>[] parameterTypes) {
-        PublicMethods.MethodList res = getMethodsRecursive(
-            name,
-            parameterTypes == null ? EMPTY_CLASS_ARRAY : parameterTypes,
-            /* includeStatic */ true);
-        return res == null ? null : res.getMostSpecific();
+        // Not found on class or superclass directly
+        interfaceCandidates.removeLessSpecifics();
+        return interfaceCandidates.getFirst(); // may be null
     }
 
-    // Returns a list of "root" Method objects. These Method objects must NOT
-    // be propagated to the outside world, but must instead be copied
-    // via ReflectionFactory.copyMethod.
-    private PublicMethods.MethodList getMethodsRecursive(String name,
+    private Method privateGetMethodRecursive(String name,
                                                          Class<?>[] parameterTypes,
-                                                         boolean includeStatic) {
-        // 1st check declared public methods
-        Method[] methods = privateGetDeclaredMethods(/* publicOnly */ true);
-        PublicMethods.MethodList res = PublicMethods.MethodList
-            .filter(methods, name, parameterTypes, includeStatic);
-        // if there is at least one match among declared methods, we need not
-        // search any further as such match surely overrides matching methods
-        // declared in superclass(es) or interface(s).
-        if (res != null) {
+            boolean includeStaticMethods,
+            MethodArray allInterfaceCandidates) {
+        // Note: the intent is that the search algorithm this routine
+        // uses be equivalent to the ordering imposed by
+        // privateGetPublicMethods(). It fetches only the declared
+        // public methods for each class, however, to reduce the
+        // number of Method objects which have to be created for the
+        // common case where the method being requested is declared in
+        // the class which is being queried.
+        //
+        // Due to default methods, unless a method is found on a superclass,
+        // methods declared in any superinterface needs to be considered.
+        // Collect all candidates declared in superinterfaces in {@code
+        // allInterfaceCandidates} and select the most specific if no match on
+        // a superclass is found.
+
+        // Must _not_ return root methods
+        Method res;
+        // Search declared public methods
+        if ((res = searchMethods(privateGetDeclaredMethods(true),
+                                 name,
+                                 parameterTypes)) != null) {
+            if (includeStaticMethods || !Modifier.isStatic(res.getModifiers()))
             return res;
         }
-
-        // if there was no match among declared methods,
-        // we must consult the superclass (if any) recursively...
-        Class<?> sc = getSuperclass();
-        if (sc != null) {
-            res = sc.getMethodsRecursive(name, parameterTypes, includeStatic);
+        // Search superclass's methods
+        if (!isInterface()) {
+            Class<? super T> c = getSuperclass();
+            if (c != null) {
+                if ((res = c.getMethod0(name, parameterTypes, true)) != null) {
+                    return res;
         }
-
-        // ...and coalesce the superclass methods with methods obtained
-        // from directly implemented interfaces excluding static methods...
-        for (Class<?> intf : getInterfaces(/* cloneArray */ false)) {
-            res = PublicMethods.MethodList.merge(
-                res, intf.getMethodsRecursive(name, parameterTypes,
-                                              /* includeStatic */ false));
         }
-
-        return res;
+        }
+        // Search superinterfaces' methods
+        Class<?>[] interfaces = getInterfaces();
+        for (Class<?> c : interfaces)
+            if ((res = c.getMethod0(name, parameterTypes, false)) != null)
+                allInterfaceCandidates.add(res);
+        // Not found
+        return null;
     }
 
-    // Returns a "root" Constructor object. This Constructor object must NOT
-    // be propagated to the outside world, but must instead be copied
-    // via ReflectionFactory.copyConstructor.
     private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
                                         int which) throws NoSuchMethodException
     {
-        ReflectionFactory fact = getReflectionFactory();
         Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
         for (Constructor<T> constructor : constructors) {
             if (arrayContentsEq(parameterTypes,
-                                fact.getExecutableSharedParameterTypes(constructor))) {
-                return constructor;
+                                constructor.getParameterTypes())) {
+                return getReflectionFactory().copyConstructor(constructor);
             }
         }
         throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
     }
 
< prev index next >