Как определить метод, который может принимать произвольные аргументы в Java? - PullRequest
3 голосов
/ 21 марта 2010

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

Ответы [ 6 ]

10 голосов
/ 21 марта 2010

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

тогда вам нужно перегрузить ваш метод

3 голосов
/ 21 марта 2010
2 голосов
/ 12 февраля 2014

Не работает в общем случае. Даже если вы определите свой метод как:

    @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 (new Object [] {" a "}), потому что это создает неоднозначную ситуацию: вы хотели вызвать callMe с одним объектом (который является массивом) или с элементами массива?

0 голосов
/ 21 марта 2010

Боюсь, что java не может сделать это прямо из коробки (в отличие от некоторых других языков), даже если вы рассматриваете varargs (поскольку они действительно относятся только к одному типу). Однако шаблоны OO - ваш друг, и вы можете использовать шаблон Builder, чтобы выполнить то, что вам требуется. Короткий пример (украденный адаптированный и сокращенный из Effective 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 голосов
/ 21 марта 2010

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

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

Вот пример varargs:

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 голосов
/ 21 марта 2010

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

public void foo (ParamType ... name) { 

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