--- a/jdk/src/share/classes/java/lang/Class.java Wed Jun 11 16:33:23 2014 +0800
+++ b/jdk/src/share/classes/java/lang/Class.java Tue Jun 10 14:40:20 2014 +0200
@@ -2696,12 +2696,26 @@
}
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() {
- methods = new Method[20];
+ 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) {
@@ -2709,6 +2723,9 @@
methods = Arrays.copyOf(methods, 2 * methods.length);
}
methods[length++] = m;
+
+ if (m != null && m.isDefault())
+ defaults++;
}
void addAll(Method[] ma) {
@@ -2742,7 +2759,10 @@
}
}
- void addAllNonStatic(Method[] methods) {
+ /* 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);
@@ -2758,19 +2778,35 @@
return methods[i];
}
- void removeByNameAndSignature(Method toRemove) {
+ 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 &&
- m.getReturnType() == toRemove.getReturnType() &&
- m.getName() == toRemove.getName() &&
- arrayContentsEq(m.getParameterTypes(),
- toRemove.getParameterTypes())) {
- methods[i] = null;
+ 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
@@ -2788,9 +2824,48 @@
}
}
+ /* 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);
+ }
}
@@ -2819,7 +2894,7 @@
// the end.
MethodArray inheritedMethods = new MethodArray();
for (Class<?> i : getInterfaces()) {
- inheritedMethods.addAllNonStatic(i.privateGetPublicMethods());
+ inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
}
if (!isInterface()) {
Class<?> c = getSuperclass();
@@ -2830,8 +2905,10 @@
// interface methods
for (int i = 0; i < supers.length(); i++) {
Method m = supers.get(i);
- if (m != null && !Modifier.isAbstract(m.getModifiers())) {
- inheritedMethods.removeByNameAndSignature(m);
+ if (m != null &&
+ !Modifier.isAbstract(m.getModifiers()) &&
+ !m.isDefault()) {
+ inheritedMethods.removeByNameAndDescriptor(m);
}
}
// Insert superclass's inherited methods before
@@ -2844,9 +2921,10 @@
// Filter out all local methods from inherited ones
for (int i = 0; i < methods.length(); i++) {
Method m = methods.get(i);
- inheritedMethods.removeByNameAndSignature(m);
+ inheritedMethods.removeByNameAndDescriptor(m);
}
methods.addAllIfNotPresent(inheritedMethods);
+ methods.removeLessSpecifics();
methods.compactAndTrim();
res = methods.getArray();
if (rd != null) {
@@ -2919,8 +2997,21 @@
return (res == null ? res : getReflectionFactory().copyMethod(res));
}
-
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;
+
+ // Not found on class or superclass directly
+ interfaceCandidates.removeLessSpecifics();
+ return interfaceCandidates.getFirst(); // may be null
+ }
+
+ private Method privateGetMethodRecursive(String name,
+ Class<?>[] parameterTypes,
+ 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
@@ -2928,6 +3019,14 @@
// 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),
@@ -2949,7 +3048,7 @@
Class<?>[] interfaces = getInterfaces();
for (Class<?> c : interfaces)
if ((res = c.getMethod0(name, parameterTypes, false)) != null)
- return res;
+ allInterfaceCandidates.add(res);
// Not found
return null;
}