Java中的解释语言和对Java方法的调用

Java中的解释语言和对Java方法的调用,java,inheritance,reflection,interpreted-language,Java,Inheritance,Reflection,Interpreted Language,我用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 当然,这是真的,这是因为

我用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类具有“包”可见性。这意味着,当我调用它的“size()”方法时,我会从代码不可见的类中调用该方法。Java很容易避免这个问题-方法keySet()返回类型Set的值,所以使用的方法size()在公共和抽象类“Set”中声明

我的问题是:有没有人有一个想法,应该如何以通用的方式处理?所谓“一般”病例,我指的不仅仅是这个简单的病例,我可以遍历整个遗传链,找到这个方法的“第一个声明”,还包括如下病理病例:

interface I1 {
    public void foo();
}
interface I2 {
    public void foo();
}
interface I3 {
    public void foo();
}
class C implements I1, I2, I3 {
    public void foo() { .... }
}
我现在的印象是,我可以忽略那些病理病例,选择任何匹配方法,因为如果这样的对象存在,那么它的创建是成功的,所以它的编译是成功的,所以所有这些方法都有相同的签名,因为在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;
}
公共静态方法findMethod(类cls,字符串名,类[]fa){
System.out.println(“检查类”+cls+“方法”+name);
//因为它是递归调用的,所以我们希望有一天,当我们
//传递null(因此大多数getSuperclass是在Object.class或类似的对象上调用的)
如果(cls==null){
返回null;
}
方法m=null;
if((m=findMethod(cls.getSuperclass(),name,fa))!=null){
返回m;
}
//好的,如果我们在这里,那么m是空的。所以检查cls是否是公共的。它必须是公共的,因为
//否则,我们将无法调用它-我们肯定处于不同的包中
//不是公共的,请检查接口。
如果(!Modifier.isPublic(cls.getModifiers())){
System.out.println(“类不是公共的,超类不包含方法”+名称);
System.out.println(“检查所有接口”);
对于(类iface:cls.getInterfaces()){
if((m=findMethod(iface,name,fa))!=null){
返回m;
}
}
}
返回findMethodInClass(cls、名称、fa);
}
私有静态方法findMethodInClass(类cls,字符串名称,类[]fa){
方法m=null;
//扫描所有方法并将可能的候选方法移到数组的开头
方法[]mm=cls.getMethods();
int n=0;
对于(int i=0;i1){
System.out.println(“警告:我们必须执行更具体的测试。n==”+n);
System.out.println(“类:+cls+”\n名称:+name);
对于(int i=0;i0){
m=mm[0];
}
返回m;
}

FindMethodClass中调用的方法checkMethod()只检查名称是否正确,以及调用哪个方法的参数是否与形式参数列表匹配。它的实现留给读者作为一个简单的练习。有什么意见吗?

您可能应该尝试模拟Java方法解析规则,除非您是在运行时而不是编译时进行。基本上,您必须查看继承树中的第一个方法(最接近根的方法),如果有多个方法,请选择来自超类的方法。如果它们都来自接口,你可以任意选择一个。一个相关的问题是所有这些如何与默认方法一起工作。也许我的帖子不清楚,但这正是我目前正在实现的,我只是不确定这是否是解决方案。也许有更好的办法,这就是我为什么问的原因。当然,我可以简单地保持原样,因为动态类型只是这个项目的一个阶段,因为我的目标是静态类型和类型推断,但让它留下这样一个大洞不是我可以问心无愧的事情。我同意,它看起来确实很难看。当要匹配的方法有参数时,它会变得更加丑陋。