Используя возвращенную строку для вызова метода? - PullRequest
4 голосов
/ 26 ноября 2009

У меня есть ArrayList и я хочу иметь возможность вызывать индекс и использовать возвращенную строку для вызова метода.

, например

stringList.get(2)();

Могу ли я пойти по этому поводу?

Ответы [ 9 ]

11 голосов
/ 26 ноября 2009

То есть вы хотите, чтобы возвращаемая строка использовалась в качестве имени вызываемого метода?

Вы можете сделать это, используя отражение , но я бы настоятельно не рекомендовал это.

Вместо этого вы захотите, например, рассмотреть реализацию стратегии .

2 голосов
/ 26 ноября 2009

Да , есть способ использовать возвращенную строку из списка для вызова метода.

Как уже отмечали другие пользователи, вам необходимо использовать Reflection API . Может быть сложно справиться с этим, зависит от конкретного сценария, с которым вы столкнулись.

Просто чтобы показать вам базовый подход в конкретном, но упрощенном примере , я создаю этот код. Скопируйте его и поиграйте в изменение индекса и создание новых методов с параметрами после изучения основ API.

import java.lang.reflect.*;
import java.util.*;

public class DemoReflection {

    public static void main(String[] args) {

        List<String> myStringList = new ArrayList<String>();
        myStringList.add(0, "foo");
        myStringList.add(1, "printStr");
        myStringList.add(2, "otherMethod");
        myStringList.add(3, "stackoverflow");

        int index = 3;
        String methodName = myStringList.get(index);

        try {
            Class<?> c = Class.forName("DemoReflection");
            Object obj = c.newInstance();

            Method method = c.getDeclaredMethod(methodName, null);
            method.invoke(obj, null);

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

      }

    public void stackoverflow() {
         System.out.println("Stackoverflow rules!");
    }

    public void printStr() {
         System.out.println("Method printStr invoked...");
    }

}
1 голос
/ 26 ноября 2009

Во-первых, вы не можете вызвать метод в Java без объекта для его вызова. Это тоже в списке.

Было бы лучше иметь список Runnable ...

List<Runnable> runnables = ...
runnables.get(2).call();

Если у вас есть объект, который вам нужно вызвать, и вы хотите использовать отражение (может быть медленным), тогда commons-bean может помочь сделать его простым Смотри http://commons.apache.org/beanutils

import org.apache.commons.beanutils.MethodUtils;

Object target = ...
List<String> methodNames = ...
MethodUtils.invokeMethod(target, methodNames.get(2), /*args*/ null);

Чтобы дать лучше, я бы посоветовал мне узнать больше о проблеме, которую вы пытаетесь решить.

1 голос
/ 26 ноября 2009

Если я понимаю ваши потребности, вот пример на основе интерфейса; затем список содержит реализации интерфейса, а не имена методов:

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) throws Exception {

        List<Action> actions = new ArrayList<Action>();
        actions.add(new Action(){
            public void execute() {
                System.out.println("Action 0");
            }});
        actions.add(new Action(){
            public void execute() {
                System.out.println("Action 1");
            }});

        actions.get(0).execute();
        actions.get(1).execute();

    }


    static interface Action{ 
        void execute(); 
    }

}
1 голос
/ 26 ноября 2009

Имеет ли ArrayList для хранения строк? В противном случае вы можете заполнить его экземплярами java.lang.reflect.Method и вызвать Method.invoke () для возвращенного экземпляра.

1 голос
/ 26 ноября 2009

Нужно было бы использовать отражение. Смотри http://tutorials.jenkov.com/java-reflection/methods.html.

0 голосов
/ 26 ноября 2009

В Java - ни за что. Это не особенность языка Java. Вы надеетесь на что-то вроде

// NOT VALID JAVA
String myColoring = paintBlackOrWhite() ? "black" : "white";
myColoring(myBathroomWall);
// NOT VALID JAVA

Как и предполагали другие, чисто техническое решение будет использовать отражения: взять строку результата, найти соответствующий метод и вызвать его. Техническим решением может быть даже карта типа

Map<String, java.lang.reflect.Method> myMethods;

и сделай что-то вроде

get("black").invoke(myObject, myParams);

но все это приятно знать, и вы не должны использовать его, если не по принуждению или у вас нет конкретной проблемы, где даже у SO нет решения;)

0 голосов
/ 26 ноября 2009

Или, если вы настаиваете на том, чтобы идея работала независимо от каких-либо препятствий, вы могли бы обратиться к динамическому языку, такому как JRuby или Clojure, оба из которых готовы eval() String.

Или Jython или Groovy или ...

0 голосов
/ 26 ноября 2009

Или, может быть, лучше полиморфизм и фабричный метод. Вам нужно будет описать методы, которые вы сможете вызывать, но это не будет плохой идеей.

Если вам нужен полный Monty и вы используете Java 6, возможно, вы сможете создать объект функции JavaScript и вызвать его с помощью Rhino.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...