2017-02-20 11 views
1

値がインスタンスメソッドであるstaticマップが必要です。次のようになります。静的コンテキストのインスタンスメソッドへの参照を格納する

public class MyClass { 
    static Map<MyEnum, Consumer<String>> methodMapping; 
    static { 
     methodMapping = new EnumMap<>(MyEnum.class); 

     methodMapping.put(MyEnum.FIRST, MyClass::firstMethod); 
     methodMapping.put(MyEnum.SECOND, MyClass::secondMethod); 
    } 
    void firstMethod(String param) { 
     ... 
    } 
    void secondMethod(String param) { 
     ... 
    } 
} 

これは、「非静的メソッドは静的コンテキストから参照できません」というエラーが表示されます。私は静的コンテキストからメソッドを呼び出そうとすると、なぜこれが問題になるのか理解していますが、インスタンスメソッドからメソッドをマップから取得してそれを渡すことはできませんthis?同様:

MyClass.methodMapping.get(MyEnum.FIRST).accept(this, "string");

+0

設計ビットファンキー見えること。このenum-to-methodマッピングの背後にある考え方を説明するのに気をつけますか? – Kayaman

+0

@Kayamanリファクタリングの目的で、インスタンスメソッドに長いスイッチがあり、各ブランチから異なるメソッドを呼び出すことができました。私はそれぞれの中でただ一つのメソッドのために多くのサブクラスを作成したくありませんでした。 – Levi

答えて

2

これは、関数のパラメータにMyClassの受信インスタンスを回し、BiConsumerConsumerを変更するように簡単に解決可能である:

public class MyClass { 
    static Map<MyEnum, BiConsumer<MyClass,String>> methodMapping; 
    static { 
     methodMapping = new EnumMap<>(MyEnum.class); 

     methodMapping.put(MyEnum.FIRST, MyClass::firstMethod); 
     methodMapping.put(MyEnum.SECOND, MyClass::secondMethod); 
    } 
    void firstMethod(String param) { 
     ... 
    } 
    void secondMethod(String param) { 
     ... 
    } 
    void callTheMethod(MyEnum e, String s) { 
     methodMapping.get(e).accept(this, s); 
    } 
} 
+0

まさに私が探していたもの、ありがとう! – Levi

2

あなたは静的初期化ブロックmethodMappingを初期化します。その時点で、あなたのインスタンスのメソッドは、new MyClass()まだ呼び出されていないため、まだ参照できません。

メソッドを静的にするか、メソッドの初期化をスタティックブロックからコンストラクタに移動して、これを修正できます。

PS:キーワード静的は、あなたが

static Map<MyEnum, Consumer<String>> methodMapping; 
    static { 

は、静的からメソッドを呼び出そうと、まさにそのことを理解していないと思われる初期化ブロック

+0

申し訳ありませんが、@ Holgerのソリューションはまさに私が探していたものなので、代わりに彼の答えを受け入れました – Levi

1

から省略することができます彼らが存在しない文脈。

ここで理解しておくべき重要なことは、メソッドリファレンスを作成することです。メソッド参照はそのメソッドを呼び出すために何らかのオブジェクトを必要とします。したがって、「遅延」はありません。 javaには「thisが意味を持つのを待つ」という表現はありません。言い換えれば、静的コンテキストでは、「静的ではないコンテキストで後で使用され、そこから対応するthisを選択する」という表現はありません。

+0

あなたはおそらく正しいでしょう。私が知り得ないことは、すべてのインスタンスがこれらのメソッドを持つことをすでに知っていることです。 static初期化ブロック中にメソッドを実行させたくないので、なぜ 'this'が後であるのかを指定できないのはなぜですか? – Levi

+2

しかし、その時点で**オブジェクト**が必要です。 **特定の**オブジェクトのメソッドへの "参照"を作成したいからです。 – GhostCat

+0

あなたは行く、私は議論がどこに行くのかを見て待っていた – Levi

1

それがマップからメソッドを取得してthis

号A Consumerは単一のパラメータaccept()方法を有している、ようなものはありません、それを渡すために、インスタンスメソッドからは不可能です"呼び出し時にthisを渡す"。

メソッド参照を作成するときにインスタンスが必要なので、この質問は「静的コンテキストからインスタンスメソッドを呼び出すことはできません」ということになります。

+0

私はすべてのインスタンスがこれらのメソッドを持つことをすでに知っていることです。静的な初期化ブロック中にメソッドを実行したくないので、なぜこれが後であるのかを指定できません。 – Levi

+1

メソッド参照には、インスタンスとメソッド(または静的メソッドのクラスとメソッド)の両方に関する情報が含まれているためです。 「これを後で記入する」オプションはありません。 – Kayaman

+0

あなたの答えをありがとう – Levi

1

鍵はthisの指定を延期するか、より具体的には次のとおりです。メソッドが呼び出される特定のインスタンス。したがって、メソッド参照を直接格納する代わりに、インスタンスを受け入れ、そのインスタンスのメソッド参照を返す関数を格納します。

MyClass.java

public class MyClass { 
    static Map<MyEnum, Function<MyClass, Consumer<String>>> methodMapping; 
    static { 
     methodMapping = new EnumMap<>(MyEnum.class); 
     methodMapping.put(MyEnum.FIRST, t -> t::firstMethod); 
     methodMapping.put(MyEnum.SECOND, t -> t::secondMethod); 
    } 
    private String id; 
    public MyClass(String id) { 
     this.id = id; 
    } 
    void firstMethod(String param) { 
     System.out.println(id + ", 1st method, " + param); 
    } 
    void secondMethod(String param) { 
     System.out.println(id + ", 2nd method, " + param); 
    } 
    void dispatchMethod(MyEnum myEnum, String param) { 
     methodMapping.get(myEnum).apply(this).accept(param); 
    } 
} 

メイン。私はdispatchMethodアプローチを取り、methodMappingはプライベートと不変作ることをお勧めしたいので、javaの

public class Main { 

    public static void main(String[] args) { 
     MyClass instance = new MyClass("MyInstance"); 
     MyClass.methodMapping.get(MyEnum.FIRST).apply(instance).accept("Using mapping directly"); 
     instance.dispatchMethod(MyEnum.SECOND, "Using dispatch method"); 
    } 

} 

理想的methodMappingは、他のクラスから直接アクセスに対して遮蔽されなければなりません。

関連する問題