在 Java 中解释语言并调用 Java 方法
Interpreted language in Java and calls to Java methods
我在 Java 中实现了带有动态类型的简单解释型语言。不幸的是我 运行 遇到了以下问题。测试以下代码时:
def main() {
def ks = Map[[1, 2]].keySet();
return ks.size();
}
我偶然发现了以下异常:
java.lang.IllegalAccessException: class is not public: java.util.HashMap$KeySet.size()int/invokeSpecial
当然这是真的,这是由于 HashMap$KeySet class 具有 "package" 可见性这一事实造成的。这意味着当我调用它的 "size()" 方法时,我从 class 调用了我的代码不可见的方法。 Java 轻松避免了这个问题 - 方法 keySet() returns 类型 Set 的值,因此使用的方法 size() 在 public 和抽象 class "Set" 中声明.
我的问题是:有没有人知道应该如何以通用方式处理? "general" 案例我的意思不仅是这个简单的案例,我可以遍历整个继承链并找到这个方法的 "first declaration",而且还有像下面这样的病态案例:
interface I1 {
public void foo();
}
interface I2 {
public void foo();
}
interface I3 {
public void foo();
}
class C implements I1, I2, I3 {
public void foo() { .... }
}
我目前的印象是,我可以忽略那些病态的情况和select任何匹配方法,理由是如果存在这样的对象,那么它就创建成功了,所以它编译成功了,所以所有这些方法具有相同的签名,并且由于在 Java 中无法根据对象的查看方式(如 I1、I2 或 I3)指定这些方法的不同实现,因此结果将始终相同。
我们将不胜感激。
好的,这是我的解决方案。这不是很好,但是嘿,不管怎样:
public static Method findMethod(Class<?> cls, String name, Class<?>[] fa) {
System.out.println("Checking class " + cls + " for method " + name);
// since it is called recursively, we want to stop some day, and when we are
// passed null (so most getSuperclass was called on Object.class or something similar)
if (cls == null) {
return null;
}
Method m = null;
if ((m = findMethod(cls.getSuperclass(), name, fa)) != null) {
return m;
}
// ok, if we're here, then m is null. so check if cls is public. it must be public, because
// otherwise we won't be able to call it - we are definitely in different package. if class
// isn't public, then check interfaces.
if (!Modifier.isPublic(cls.getModifiers())) {
System.out.println("Class is not public, and superclasses do not contain method " + name);
System.out.println("Checking all interfaces");
for (Class<?> iface: cls.getInterfaces()) {
if ((m = findMethod(iface, name, fa)) != null) {
return m;
}
}
}
return findMethodInClass(cls, name, fa);
}
private static Method findMethodInClass(Class<?> cls, String name, Class<?>[] fa) {
Method m = null;
// scan all methods and move plausible candidates to the start of an array
Method[] mm = cls.getMethods();
int n = 0;
for (int i = 0 ; i < mm.length ; ++i) {
if (checkMethod(mm[i], name, fa)) {
mm[n++] = mm[i];
}
}
if (n > 1) {
System.out.println("Caveat: we have to perform more specific test. n == " + n);
System.out.println("class: " + cls + "\nname: " + name);
for (int i = 0 ; i < n ; ++i) {
System.out.println(mm[i]);
}
}
if (n > 0) {
m = mm[0];
}
return m;
}
在 findMethodInClass 中调用的方法 checkMethod() 只是检查名称是否正确以及调用方法的参数是否或多或少与正式参数列表匹配。它的实现留作 reader 的简单练习。有什么意见吗?
我在 Java 中实现了带有动态类型的简单解释型语言。不幸的是我 运行 遇到了以下问题。测试以下代码时:
def main() {
def ks = Map[[1, 2]].keySet();
return ks.size();
}
我偶然发现了以下异常:
java.lang.IllegalAccessException: class is not public: java.util.HashMap$KeySet.size()int/invokeSpecial
当然这是真的,这是由于 HashMap$KeySet class 具有 "package" 可见性这一事实造成的。这意味着当我调用它的 "size()" 方法时,我从 class 调用了我的代码不可见的方法。 Java 轻松避免了这个问题 - 方法 keySet() returns 类型 Set 的值,因此使用的方法 size() 在 public 和抽象 class "Set" 中声明.
我的问题是:有没有人知道应该如何以通用方式处理? "general" 案例我的意思不仅是这个简单的案例,我可以遍历整个继承链并找到这个方法的 "first declaration",而且还有像下面这样的病态案例:
interface I1 {
public void foo();
}
interface I2 {
public void foo();
}
interface I3 {
public void foo();
}
class C implements I1, I2, I3 {
public void foo() { .... }
}
我目前的印象是,我可以忽略那些病态的情况和select任何匹配方法,理由是如果存在这样的对象,那么它就创建成功了,所以它编译成功了,所以所有这些方法具有相同的签名,并且由于在 Java 中无法根据对象的查看方式(如 I1、I2 或 I3)指定这些方法的不同实现,因此结果将始终相同。
我们将不胜感激。
好的,这是我的解决方案。这不是很好,但是嘿,不管怎样:
public static Method findMethod(Class<?> cls, String name, Class<?>[] fa) {
System.out.println("Checking class " + cls + " for method " + name);
// since it is called recursively, we want to stop some day, and when we are
// passed null (so most getSuperclass was called on Object.class or something similar)
if (cls == null) {
return null;
}
Method m = null;
if ((m = findMethod(cls.getSuperclass(), name, fa)) != null) {
return m;
}
// ok, if we're here, then m is null. so check if cls is public. it must be public, because
// otherwise we won't be able to call it - we are definitely in different package. if class
// isn't public, then check interfaces.
if (!Modifier.isPublic(cls.getModifiers())) {
System.out.println("Class is not public, and superclasses do not contain method " + name);
System.out.println("Checking all interfaces");
for (Class<?> iface: cls.getInterfaces()) {
if ((m = findMethod(iface, name, fa)) != null) {
return m;
}
}
}
return findMethodInClass(cls, name, fa);
}
private static Method findMethodInClass(Class<?> cls, String name, Class<?>[] fa) {
Method m = null;
// scan all methods and move plausible candidates to the start of an array
Method[] mm = cls.getMethods();
int n = 0;
for (int i = 0 ; i < mm.length ; ++i) {
if (checkMethod(mm[i], name, fa)) {
mm[n++] = mm[i];
}
}
if (n > 1) {
System.out.println("Caveat: we have to perform more specific test. n == " + n);
System.out.println("class: " + cls + "\nname: " + name);
for (int i = 0 ; i < n ; ++i) {
System.out.println(mm[i]);
}
}
if (n > 0) {
m = mm[0];
}
return m;
}
在 findMethodInClass 中调用的方法 checkMethod() 只是检查名称是否正确以及调用方法的参数是否或多或少与正式参数列表匹配。它的实现留作 reader 的简单练习。有什么意见吗?