2010-03-21 2 views
3

Как определить метод, который может принимать произвольные аргументы в java? Есть демо?Как определить метод, который может принимать произвольные аргументы в java?

+5

Что значит «произвольные аргументы»? Произвольное число аргументов? или произвольные типы? – Roman

ответ

0

Вот простой tutorial о переменных аргументах. Пример кода:

public void foo (ParamType ... name) { 

} 
10

varargs были введены в Java 5.

Например:

public String join(String... parts); 

Это фактически ярлык для:

public String join(String[] parts); 

параметр parts используется в качестве массива в методе, но метод можно вызвать без построения массива (например, obj.join(new String[] {part1, part2, part3}))

Однако будьте очень осторожны с этим, поскольку могут возникнуть неоднозначности. Например:

public void write(String author, String... words); 
public void write(String... words); 

Какой метод будет вызываться, если obj.write("Mike", "jumps")? Компилятор достаточно умен, чтобы обнаружить двусмысленность, но у меня были случаи, когда некоторые компиляторы не обнаружили таких проблем (точно не помню)

Использование varargs практично, когда объекты одного типа или наименее с той же функциональной целью. Если вам нужны разные аргументы. Например:

public String publishBook(String title, [String author], 
     [String isbn], [boolean hardcover]); // [..] would mean optional 

то вам нужно overload your method

+0

Общие сведения Я согласен, кроме одного: «public String join (String ... parts); Это на самом деле ярлык для: public String join (String [] parts);". Это не ярлык, потому что вы не можете вызвать join (String [] parts) как join ("a", "b", "c") в отличие от join (String ... parts) – greendraco

0

Для прохождения переменного числа аргументов, вы можете использовать синтаксис списков параметров (указать тип следует многоточие, а так по имени параметр массив указанного типа, а Java добавит некоторый синтаксический сахар, чтобы вы могли перейти в список любого числа этого типа, и он будет автоматически помещен в массив).

Для передачи произвольных типов можно использовать Java-генераторы для разрешения произвольных типов или использовать объект типа Object. Обычно лучше использовать дженерики, потому что вы получаете больше проверки типов, но оба они будут делать.

Вот пример списков параметров:

 
public static void printAll(String... args){ 
    for (String str : args){ 
     System.out.println(str); 
    } 
} 
// Now can write printAll("Hello", "world", "etc", "etc"); 

Вот пример дженериков:

 
public static <T> void print(T obj){ 
    System.out.println(obj.toString()); 
} 
0

Боюсь, ява с annot делать это из коробки только пока (в отличие от некоторых других языков), даже если вы рассматриваете varargs (поскольку они действительно одного типа). Однако шаблоны OO - ваш друг, и вы можете использовать шаблон Builder, чтобы выполнить то, что вам нужно.Краткий пример (украденные адаптировались и укорачивается от эффективного Java 2nd Edition)

public class NutritionFacts { 
    private final int servingSize; 
    private final int servings; 
    private final int calories; 
    private final int fat; 

    public static class Builder { 
     // Required parameters 
     private final int servingSize; 
     private final int servings; 
     // Optional parameters - initialized to default values 
     private int calories = 0; 
     private int fat = 0; 

     public Builder(int servingSize, int servings) { 
      this.servingSize = servingSize; 
      this.servings = servings; 
     } 

     public Builder calories(int val) { 
      calories = val; 
      return this; 
     } 

     public Builder fat(int val) { 
      fat = val; 
      return this; 
     } 

     public NutritionFacts build() { 
      return new NutritionFacts(this); 
     } 

    } 

    private NutritionFacts(Builder builder) { 
     servingSize = builder.servingSize; 
     servings = builder.servings; 
     calories = builder.calories; 
     fat = builder.fat; 
    } 

} 

При этом вы можете сделать что-то вроде

NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8). 
calories(100).fat(35).build(); 

Теперь действительно крутая вещь об этом, является то, что вы можете добавить методы, на самом деле берут varargs, что делает этот особый узор очень мощным. Этот шаблон также делает объект неизменным и сохраняет вас от написания телескопических конструкторов. То, что он не будет делать, это ваши блюда, но я живу в надежде;)

+0

Object ... делает трюк –

+1

Вы должны отметить, что это выдержка из Effective Java ^^ – helpermethod

+1

Вы должны прочитать мой ответ более внимательно в следующий раз mk? :) «Краткий пример (украденный, адаптированный и сокращенный от Effective Java 2nd Edition)» – Ioannis

1

Это не работает в общем случае. Даже если вы определяете метод, как:

@SafeVarargs 
    public void callMe(Object... args) { ... } 

При вызове callMe(1, "hallo", 3.14159, new Object()), это будет работать. Однако, если вы хотите иметь аналогичный метод для интерфейса, вы не можете использовать @SafeVarargs, так как его можно добавлять только к окончательным методам (чтобы они не были переопределены с помощью небезопасной реализации).

Лучшее, что вы можете сделать в этом случае, чтобы определить в интерфейсе:

@SuppressWarnings("unchecked") 
    public <T> void callMe(T... args); 

Это будет по крайней мере, опускаем предупреждение, когда CallME вызывается с объектами одного и того же типа во время выполнения, например, `callMe (" a "," b "," c "). Тем не менее, появляется предупреждающее сообщение, когда вы вызываете его с различными типами, как в приведенном выше примере:

ArbitraryCallable x = new ArbitraryCallableImplementation(); 
    x.callMe("a", "b"); // no warning 
    x.callMe(1, "x", 3.14159); // warning 

И не забыть, так как Object... не что иное, как синтаксический сахар для Object[], вы не можете просто позвонить `CallME (новый Object [] {"a"}), потому что это создает неоднозначную ситуацию: вы хотите вызвать callMe с одним объектом (который является массивом) или с элементами массива?

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