Несколько типов объектов для varargs в прототипе метода? - PullRequest
12 голосов
/ 12 июня 2011

Я пытаюсь написать прототип функции Java, которую можно вызывать с любым количеством целых чисел и строк:

myMethod(1, 2, 3, "Hello", "World"); // Valid call
myMethod(4, "foo", "bar", "foobar"); // Valid call

В идеале, я бы хотел, чтобы целые числа и строки задавались в любомпорядок (и, возможно, смешанный):

myMethod(1, "Hello", 2, "World", 3); // Valid call

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

public void myMethod(Object ... objs) { [...] }

... но я чувствую, что должна быть ошибка компиляции в случае, если она вызывается с чем-то отличным от ожидаемых типов.Конечно, можно выполнить проверку во время выполнения (instanceof), но это было бы не слишком элегантным решением, не так ли?

Как бы вы это сделали?

Ответы [ 6 ]

9 голосов
/ 12 июня 2011

Если вы хотите, чтобы это было безопасно для типов, я бы сказал:

public myMethod(Thing<?>... thing) { ... }

А затем создайте ваши классы Thing:

public interface Thing<T> {
    public T value();
}

public class IntThing implements Thing<Integer> {
    private final int value;

    public IntThing(int value) {
        this.value = value;
    }

    public Integer value() {
        return value;
    }
}

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

Затем вы делаете два статических метода:

public static Thing<Integer> thing(int value) {
    return new IntThing(value);
}

public static Thing<String> thing(String value) {
    return new StringThing(value);
}

Затем вы оборачиваете каждый объектвызов thing:

myMethod(thing(1), thing(2), thing(3), thing("Hello"), thing("World"));

Грязно?Ага.К сожалению, Java не имеет возможности скрывать эти вещи, как другие языки.Здесь вам помогут неявные определения Scala, но это связано с целым рядом других проблем.Лично я бы пошел с проверками instanceof, но эта проверка обеспечит безопасность вашего кода во время компиляции.

7 голосов
/ 12 июня 2011

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

3 голосов
/ 12 июня 2011

Невозможно использовать универсальные шаблоны для сопоставления двух типов, например

public <T extends String | Integer> void myMethod(T... objs); // You can't do this
1 голос
/ 12 июня 2011

Единственное возможное решение проблемы, которую вы описали, - это уже заявленное, где функция принимает аргумент varargs типа Object. Это связано с ограничением в Java, когда в сигнатуре метода может быть только один vararg, и это должен быть последний параметр.

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

0 голосов
/ 24 июня 2017

Синтаксис разрешен

public class Foo<T extends Number & List> {
  ...
}

Переменная типа T допускает типы, которые являются подтипами Number и List для одного типа (например, типы, реализующие несколько интерфейсов).

0 голосов
/ 11 июля 2013

(Обход)

Добавить в свою библиотеку:

package mylib;

public class Lang {
    public static <T> T[] varargs (T...ts) {
        return ts;
    }
}

В вашей программе:

package myprog;

import static mylib.Lang.*;

public class MyProg {

    public static void testfunc (Integer[] ints, String[] strs) {

        for (int i : ints)
            System.out.println(i);

        for (String s : strs)
            System.out.println(s);
    }

    public static void main (String[] args) {
        testfunc(
            varargs(1,2,3),
            varargs("Sophia", "Jacob")
        );
    }
}

(нарушение многих правил стиля кодирования)

...