2016-03-30 8 views
3

私は、Javaで動的な型定義を持つ簡単な解釈言語を実装しました。残念ながら私は以下の問題に遭遇しました。次のコードをテストする場合:Javaでの言語の解釈と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 $キーセットクラスは、「パッケージ」の可視性を持っているという事実によって引き起こされます。つまり、私が "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のように)表示されるかに依存して、これらのメソッドの実装が異なると、結果は常に同じになります。

ご協力いただければ幸いです。

+0

コンパイル時ではなく実行時に実行することを除いて、おそらくJavaメソッド解決規則をエミュレートしてください。基本的には、継承ツリー(ルートに最も近いメソッド)の最初のメソッドを調べ、複数のメソッドがある場合は、スーパークラスから来るものを選択する必要があります。それらがすべてインターフェイスから来た場合は、任意に選択できます。 – biziclop

+0

関連する質問は、これがデフォルトのメソッドでどのように動作するかです。 – biziclop

+0

私のポストからは明らかではないかもしれませんが、これは私が現在実装しているものです。これが解決策であるかどうかはわかりません。多分もっと良い方法があるかもしれません。それが私が尋ねた理由です。ダイナミックな型定義はタイプ控除を使った静的型付けを目指していますが、このような大きな穴を残すことは私が明確な良心をもってできることではありませんので、このままでそのまま残すことができます。 –

答えて

0

これは私のソリューションです。それはとても素敵ではありませんが、ちょっと、何が動作します:findMethodInClassで呼び出さ

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; 
} 

方法checkMethod()名前が正しいとあれば、単純にチェックする方法は、多かれ少なかれ一致仮引数リストと呼ばされると、引数の場合。それは読者のための簡単な練習として実装されています。コメントはありますか?