[英]Cannot call particular java method from Clojure
我正在尝试使用来自 Clojure 的ojAlgo Java 库,但我无法调用表达式class 的权重方法。
为了证明这一点,我有一个具有这种依赖关系的 Leiningen 项目: [org.ojalgo/ojalgo "47.3.1"]
我正在尝试这样做:
(ns ojalgo-test
(:require [clojure.reflect :as r])
(:import [org.ojalgo.optimisation ExpressionsBasedModel
Expression]
CallExpressionWeight))
(def m (ExpressionsBasedModel.))
;; => #'ojalgo-test/m
(def e (.addExpression m))
;; => #'ojalgo-test/e
(.weight e 1.0) ;; ERROR!
但是,最后一行失败并出现错误
- 未处理的 java.lang.IllegalArgumentException 找不到匹配的方法权重,为 class 采用 1 个参数
org.ojalgo.optimisation.Expression
问题:为什么会出现此错误,如何调用weight
方法而不会出现错误?
但有趣的是我可以写一个小Java class来调用这个方法:
import org.ojalgo.optimisation.Expression;
public class CallExpressionWeight {
public static void apply(Expression e, double w) {
e.weight(w);
}
}
这有效:
(CallExpressionWeight/apply e 1.0)
;; => nil
此外,我使用clojure.reflect/reflect
function 来查看我的Expression
实例的方法:
(def member-set (set (map :name (:members (r/reflect e)))))
;; => #'ojalgo-test/member-set
(contains? member-set 'setInfeasible)
;; => true
(contains? member-set 'weight)
;; => false
这种weight
方法有点可疑......
这对我来说也很奇怪。 我认为您可能有一个与 javadoc 不匹配的库版本,或者您可能正在针对与 clojure 代码不同的版本编译 java 垫片,但这些都不是。 我创建了一个 repo 以便于重现您的问题: https://github.com/amalloy/ojalgo 。
但是当我尝试你的代码时(任何人都可以通过
lein run -m clojure.main -- -e \
'(-> (org.ojalgo.optimisation.ExpressionsBasedModel.) (.addExpression) (.weight 0))'
),我没有得到与您完全相同的错误。 相反,我看到
引起:java.lang.IllegalArgumentException:无法调用非公共 class 的公共方法:公共最终 org.ojalgo.optimisation.ModelEntity org.ojalgo.optimisation.ModelEntity.weight(java.lang.Number)
这对我来说很有意义。 你得到的 Expression 实际上是隐藏的 class ModelEntity 的子类,而这个 class 是真正定义权重的那个。 The clojure compiler doesn't know the static types of the values involved in your interop call, and when it tries to find a method named weight
it guesses the one in the class that actually defines weight
...but this class is not public,因此不允许反射性地调用它的方法。
通常,有一个简单的解决方法:使用您要使用的 static 类型对变量进行类型提示:
(.weight ^Expression e 0)
但在这种情况下,即使这样也行不通。 这与clojure.reflect
无法找到此方法具有相同的根本原因。 说这种方法实际上并不存在是一个合理的观点! 此库中的 inheritance 层次结构(您可以使用
javap -cp ~/.m2/repository/org/ojalgo/ojalgo/47.3.1/ojalgo-47.3.1.jar -p org.ojalgo.optimisation.Expression org.ojalgo.optimisation.ModelEntity
) 看起来像这样,删节:
abstract class ModelEntity<ME extends ModelEntity<ME>> {
public final ME weight(Number) {...}
}
public final class Expression extends ModelEntity<Expression> {
}
表达式 class 确实继承了一个名为weight
的成员,但是由于他们对 generics 所做的不寻常的事情,javac 实际上生成了一个合成桥方法,该方法具有一个特殊的名称,该方法与实际weight
方法之间相互委托。 因此,当 clojure 编译器查找名为weight
的东西时,它找到的唯一一个就是这个非公共 class 中不允许操作的那个。
一方面,我认为将其称为 clojure 中的错误是公平的,但另一方面,它似乎不太可能被修复:它很大程度上取决于 javac 的实现细节,这些细节随时可能发生变化。 我认为您无法说服 clojure 调用此方法,因此我认为您编写的 java 垫片是最好的解决方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.