-
Bug
-
Resolution: Fixed
-
P3
-
8
-
b151
Dan writes:
---
To illustrate, the JDK 7 implementation of getMethods includes the following:
1) The class's/interface's declared (public) methods
2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1)
3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2)
So, for example, as expected:
interface I { void m(); }
interface J extends I { void m(); }
interface K extends J {}
K.class.getMethods() = [ J.m ]
But:
interface I { void m(); }
interface J extends I { void m(); }
interface K extends ***I,*** J {}
K.class.getMethods() = [ I.m, J.m ]
This is consistent with a reasonable reading of JLS 7 (though it is vague)*, but conflicts with JLS 8. We changed the 8 spec because, unlike abstract methods, inheriting two conflicting default methods is a compiler error, and that should be avoided.
[* There was a time when I thought the current behavior could be considered a 7 bug, but having experimented with it more, I no longer think that's the case. This is a new issue in 8.]
An implementation of getMethods consistent with JLS 8 would include the following (see Lambda Spec, Part H, 9.4.1 and 8.4.8):
1) The class's/interface's declared (public) methods
2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1)
3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2) ***or a match from a more-specific class/interface in (2) or (3)***
However, there is a compatibility concern: the behavior of K.class.getMethods in the second example above changes. How much do we care about this? The spec change was made with the understanding that this was simply an internal change to an intermediate result, without observable consequences. Reflection exposes that intermediate result. But, even so, client code should not be depending on the rather vague notion of how many identical abstract methods are members of a class.
---
That is, the spec changed in 8 but the implementation (which was correct up through 7) has not changed.
This issue is for the general case, there is a separate issue:JDK-8029674 for the case of default methods, which since new to the platform, has less of a compatibility baggage.
---
To illustrate, the JDK 7 implementation of getMethods includes the following:
1) The class's/interface's declared (public) methods
2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1)
3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2)
So, for example, as expected:
interface I { void m(); }
interface J extends I { void m(); }
interface K extends J {}
K.class.getMethods() = [ J.m ]
But:
interface I { void m(); }
interface J extends I { void m(); }
interface K extends ***I,*** J {}
K.class.getMethods() = [ I.m, J.m ]
This is consistent with a reasonable reading of JLS 7 (though it is vague)*, but conflicts with JLS 8. We changed the 8 spec because, unlike abstract methods, inheriting two conflicting default methods is a compiler error, and that should be avoided.
[* There was a time when I thought the current behavior could be considered a 7 bug, but having experimented with it more, I no longer think that's the case. This is a new issue in 8.]
An implementation of getMethods consistent with JLS 8 would include the following (see Lambda Spec, Part H, 9.4.1 and 8.4.8):
1) The class's/interface's declared (public) methods
2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1)
3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2) ***or a match from a more-specific class/interface in (2) or (3)***
However, there is a compatibility concern: the behavior of K.class.getMethods in the second example above changes. How much do we care about this? The spec change was made with the understanding that this was simply an internal change to an intermediate result, without observable consequences. Reflection exposes that intermediate result. But, even so, client code should not be depending on the rather vague notion of how many identical abstract methods are members of a class.
---
That is, the spec changed in 8 but the implementation (which was correct up through 7) has not changed.
This issue is for the general case, there is a separate issue:
- relates to
-
JDK-8030869 Class.getMethods returns methods that are not members of the class
-
- Resolved
-
-
JDK-8062389 Class.getMethod() is inconsistent with Class.getMethods() results
-
- Closed
-
-
JDK-8172048 Re-examine use of AtomicReference in java.security.Policy
-
- Closed
-
-
JDK-8061950 Class.getMethods() exhibits quadratic time complexity
-
- Resolved
-
-
JDK-8171988 Backout of fix for 8062389, 8029459, 8061950
-
- Closed
-
-
JDK-8029674 (reflect) getMethods returns default methods that are not members of the class
-
- Closed
-
(1 relates to)