2012-02-16 4 views
5

Следующая Python отрезала делает именно то, что я имею в виду:Как я могу расширить аргументы в Java?

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

def function(a, b, c): 
    print("%i :: %s :: %f" % (a,b,c)) 

a = 1 
b = "abc" 
c = 1.0 

function(a, b, c) 

list = [a, b, c] 

# This is what I am searching for in Java 
function(*(list)) 

Так у меня есть один список-структура, и я не знаю, сколько аргументов у него есть, но я знаю, что он имеет правильное число аргументов с правильным типом и форматом. И я хочу передать их методу. Поэтому я должен «расширить» эти аргументы. Кто-нибудь знает, как это сделать на Java?

+0

Возможно, вы ищете [для] (http://stackoverflow.com/questions/766559/when-do-you-use-varargs-in-java) [varargs] (http://docs.oracle.com /javase/1.5.0/docs/guide/language/varargs.html)? –

+0

Определить "expand"? Из вашего примера неясно, что это значит. – Tudor

+0

Если вы просто хотите использовать что-то вроде оператора '%', вы можете использовать класс «Formatter», как в моем ответе ниже. –

ответ

5

Java не имеет этого средства, поскольку в качестве статически, строго типизированного языка редко используется метод для сбора коллекции значений однородного типа, которые могут быть сохранены в каком-либо составном объекте (массив, список и т. Д.). .). У Python нет этой проблемы, потому что все динамически типизировано. Вы можете сделать это в Java, указав вспомогательный метод, который принимает один объект в сохранении всех параметров, а затем расширяет их при вызове реального метода.

Надеюсь, это поможет!

1

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

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

2

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

public void method1(String p1, Integer p2) { 
} 

public void method2(Object... params) { 
    method1((String)params[0], (Integer)params[1]; 
} 

Вы можете позвонить method2 как:

method2("abc", 1); 

Конечно, этот пример немного избыточен, потому что вы можете напрямую позвонить method1, но это не то, что я хотел проиллюстрировать. :)

0

Вы можете сделать это:

import java.util.Formatter; 

// ... 

StringBuilder target = new StringBuilder(); 
Formatter formatter = new Formatter(target); 

List<Integer> integers = new ArrayList<Integer>(); 
integers.add(1); 
integers.add(2); 
integers.add(3); 

formatter.format("%d %d %d", integers.toArray()); 
System.out.println(target.toString()); 

Edit:Javadoc for java.util.Formatter

0

Я думаю, что это делает то же самое, как ваш исходный код с аналогичным синтаксисом ...

public class MultiArgs { 

    public static void main(String[] args) { 
     int a = 1; 
     String b = "abc"; 
     double c = 1.0; 
     List<?> list = Arrays.asList(a, b, c); 

     System.out.println(function(a, b, c)); // 1 :: abc :: 1.000000 
     System.out.println(function(list.toArray())); // 1 :: abc :: 1.000000 
    } 

    private static <T extends Object> String function(T... objects) { 
     return String.format("%d :: %s :: %f", objects); 
    } 
} 
0

Это не рекомендуется (как отмечает templatetypedef, это очень необычный образец для строго типизированного языка), но вы ку ld делать то, что вы хотите, используя отражение.

SomeType foo = //obtained from elsewhere 
List<?> args = //obtained from somewhere else 

//this bit obtains the method handle 
Method theMethod = null; 
for (Method m : foo.getClass().getMethods()) { 
    if (m.getName().equals("theMethodIWant") { 
     theMethod = m; 
     break; 
    } 
} 

theMethod.invoke(foo, args.toArray()); //this is the line that does the magic 

Некоторые довольно серьезные предостережения:

  • Отражение может оказать существенное влияние на производительность по сравнению с прямым вызовом - гораздо больше, чем в динамическом языке, как питон. Это может быть или не иметь значения. Когда сомневаетесь, измерьте.

  • блок, который получает дескриптор методы приведет к нулевому указателю, если метод с таким именем не найден

  • Список аргументов должен иметь точно правильное количество аргументов, с правильным типом , Вы несете ответственность за проверку этого в другом месте. Это сложнее, чем в динамическом языке, так как среда выполнения сделает намного меньше (если есть) принуждение типа для вас.

  • Метод.invoke() может вызывать множество исключений (IllegalAccessException, IllegalArgumentException, InvocationTargetException и т. Д.), Которые этот пример игнорирует. Вам придется поймать и обработать эти ошибки соответственно

  • Если вызываемый метод не является общедоступным, вам нужно будет сделать еще больше работы, чем это, чтобы вызвать его.

  • Этот пример даже не пытается разобраться с случаем, когда у вас есть перегруженный метод. Два метода с именем «TheMethodIWant» с разными списками аргументов потребуют другого подхода для получения дескриптора метода.

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

Смежные вопросы