Java распаковывает списки аргументов - PullRequest
9 голосов
/ 19 мая 2011

Вот еще один вопрос "Как бы я сделал это на Java?"В Python я могу использовать символ '*' для распаковки аргументов следующим образом:

>>> range(3, 6)             # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args)            # call with arguments unpacked from a list
[3, 4, 5]

Java поддерживает получение списка аргументов с синтаксисом ...args, но есть ли способ (возможно, с использованием библиотек Reflection?) распаковать их для какой-то другой функции?

Ответы [ 2 ]

7 голосов
/ 19 мая 2011
public void printStrings(String... strings)
{
   // the strings parameter is really a String[].
   // You could do anything to it that you normally
   // do with an array.
   for(String s : strings){
      System.out.println(s);
   }
}

Можно назвать так:

String[] stringArray = new String[10];
for(int i=0; i < stringArray.length; i++){
   stringArray[i] = "String number " + (i+1);
}

printStrings(stringArray);

Синтаксис ... является действительно синтаксическим сахаром для массивов.

В Java нет описанного вами средства, но вы можете подделать его несколькими способами.

Я думаю, что самое близкое приближение означает перегрузку любой функции, которую вы хотите использовать таким образом, с помощью varargs.

Если у вас есть какой-то метод:

public void foo(int a, String b, Widget c) { ... }

Вы можете перегрузить его:

public void foo(Object... args) {
    foo((Integer)args[0], (String)args[1], (Widget)args[2]);
}

Но это действительно неуклюже и подвержено ошибкам, и его трудно поддерживать.

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

public void call(Object targetInstance, String methodName, Object... args) {
    Class<?>[] pTypes = new Class<?>[args.length];
    for(int i=0; i < args.length; i++) {
        pTypes[i] = args[i].getClass();
    }
    Method targetMethod = targetInstance.getClass()
              .getMethod(methodName, pTypes);
    targetMethod.invoke(targetInstance, args);
}
1 голос
/ 19 мая 2011

Если функция, которую вы вызываете, не является функцией varargs (объявленной с ...), тогда вам нужно использовать рефлексию. Method.invoke() принимает массив Object[] аргументов.

С помощью рефлексии трудным является поиск правильного метода (ну, это легко, если есть только один метод с тем же именем, иначе это очень сложно).

Стоимость - это дополнительное время для поиска / вызова метода.


Конечно, если вы знаете конкретный метод во время компиляции, то вы можете справиться с этим вручную, например, здесь для функции с тремя аргументами:

Object[] args = /* get args from somewhere */
callSomeNonVarargsFunction((Cast1)args[0], (Cast1)args[1], (Cast1)args[2]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...