最近,我在维护的一个应用程序中遇到了一种奇怪的行为。源代码使用版本 1.6_33 编译,但在 1.7u21 下运行。客户决定在没有咨询的情况下更改版本,我对他们的选择没有影响。
在架构中,一些接口在一定条件下被参数化以限制它们的使用。参数化的具体类必须使用定义的具体参数之一。为方便起见,PropertyDescritor 由负责实例化 ConcreteParameter(用于附加进程)的机制使用。此行为适用于版本 6,但不适用于版本 7。
在版本 7 中,当尝试获取参数的类时,返回类型始终是Parameter类型,而在版本 6 中,类型是ConcreteParameter。一个异常发生在 java 中,如下例所示。但是为什么在这种情况下会起作用?!
我浏览了JLS 7以及java 7 兼容性,但没有找到任何关于这种行为的解释。对我来说,没有具体类型是不合逻辑的。有人可以解释一下为什么会这样吗?这不是一个错误,反射适用于 getDeclaredMethod(...) 但不适用于 getDeclaredMethods() 吗?
提前致谢。
以下示例说明了过去的工作方式:
package fr.free.naoj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.junit.Test;
public class PropertyDescriptorAndReflectionTest {
@Test public void testPropertyDescriptorInnerWithJava7() {
PropertyDescriptor pd;
try {
// Fails
pd = new PropertyDescriptor("parameter", ConcreteClass.class);
assertEquals(ConcreteParameter.class, pd.getPropertyType());
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
@Test public void testReflectionOnGenericClassWithJava7() {
try {
// Works
Method m = ConcreteClass.class.getDeclaredMethod("getParameter", new Class<?>[]{});
m.setAccessible(true);
assertEquals(ConcreteParameter.class, m.getReturnType());
// Fails
for (Method me : ConcreteClass.class.getDeclaredMethods()) {
me.setAccessible(true);
if (me.getName().equals("getParameter")) {
assertEquals(ConcreteParameter.class, me.getReturnType());
}
}
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
private class ConcreteClass extends AbstractClass<ConcreteParameter> {
@Override public ConcreteParameter getParameter() {
this.parameter = new ConcreteParameter();
return this.parameter;
}
@Override public void setParameter(ConcreteParameter parameter) {
this.parameter = parameter;
}
}
private abstract class AbstractClass<P extends Parameter> implements Super<P> {
protected P parameter;
}
private interface Super<P extends Parameter> {
P getParameter();
void setParameter(P parameter);
}
private class ConcreteParameter implements Parameter {
@Override public String sayHello() {
return "hello";
}
}
private interface Parameter {
String sayHello();
}
}