由 mruza 发表评论:
我已经根据指示添加了测试并更新了补丁。
以下是一些背后的原因。以下是 src/jvm/clojure/lang/Compiler.java 文件的摘录
1462: if(target.hasJavaClass() && target.getJavaClass() != null) 1463: { 1464: List methods = Reflector.getMethods(target.getJavaClass(), args.count(), methodName, false); 1465: if(methods.isEmpty()) 1466: { 1467: method = null; 1468: if(RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) 1469: { 1470: RT.errPrintWriter() 1471: .format("Reflection warning, %s:%d:%d - call to method %s on %s can't be resolved (no such method).\n", 1472: SOURCE_PATH.deref(), line, column, methodName, target.getJavaClass().getName()); 1473: } 1474: } 1475: else 1476: { 1477: int methodidx = 0; 1478: if(methods.size() > 1) 1479: { 1480: ArrayList<Class[]> params = new ArrayList(); 1481: ArrayList<Class> rets = new ArrayList(); 1482: for(int i = 0; i < methods.size(); i++) 1483: { 1484: java.lang.reflect.Method m = (java.lang.reflect.Method) methods.get(i); 1485: params.add(m.getParameterTypes()); 1486: rets.add(m.getReturnType()); 1487: } 1488: methodidx = getMatchingParams(methodName, params, args, rets); 1489: } 1490: java.lang.reflect.Method m = 1491: (java.lang.reflect.Method) (methodidx >= 0 ? methods.get(methodidx) : null); 1492: if(m != null && !Modifier.isPublic(m.getDeclaringClass().getModifiers())) 1493: { 1494: //public method of non-public class, try to find a public descendant 1495: if((type=Reflector.getDeepestPublicDescendant(m.getDeclaringClass(), target.getJavaClass())) == null) 1496: //if descendant not found, try to find an ancestor 1497: m = Reflector.getAsMethodOfPublicBase(m.getDeclaringClass(), m); 1498: } 1499: method = m; 1500: if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) 1501: { 1502: RT.errPrintWriter() 1503: .format("Reflection warning, %s:%d:%d - call to method %s on %s can't be resolved (argument types: %s).\n", 1504: SOURCE_PATH.deref(), line, column, methodName, target.getJavaClass().getName(), getTypeStringForArgs(args)); 1505: } 1506: } 1507: }
- 第 1462 行的条件确保了已知道目标类型/类的类型
- 在第 1464 行调用的 {{clojure.lang.Reflector.getMethods()}} 方法返回目标类型定义的所有给定名称的 公共 方法的列表
- 然后在第 1477-1491 行选择要调用的最佳方法
- 如果所选方法的声明类不是 公共 的,那么将尝试找到一个既是目标类型的超类又是所选方法声明类子类的 公共 类 - 这是在 {{clojure.lang.Reflector.getDeepestPublicDescendant()}} 方法中实现的
- 如果找到了这样一个类,则在为方法调用生成字节码时,将使用该类而不是方法声明类
- 如果找不到这样的类,则尝试在声明所选方法的类的 公共 祖先中找到一个兼容的方法
请注意,由于 {{selecting-method-on-nonpublic-interface}} 测试,更改可能会导致调用与更改之前不同的方法。我认为这是一个可接受的更改,因为它
与参数类型相比较,得到更好的匹配结果的调用方法 使 Clojure 中的方法选择行为更接近 Java