< 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: 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
* "<init>"or "<clinit>".
*/
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 >