В Java должен там так или иначе иметь одного конструктора, который примет массив или набор? Я играл с этим некоторое время, но я не думаю, что это возможно.
Я хотел бы смочь инициализировать MyClass
, как это:
MyClass c = new MyClass({"rat", "Dog", "Cat"});
И как это:
LinkedList <String> l = new <String> LinkedList();
l.add("dog");
l.add("cat");
l.add("rat");
MyClass c = new MyClass(l);
Это - то, на что похож MyClass. Чем я могу заставить XXX быть так, чтобы это работало? Я знаю, что мог перегрузить конструктора, но если бы я могу минимизировать код, который был бы потрясающим правом?
public class MyClass{
private LinkedHashSet <String> myList;
public MyClass(XXX <String> input){
myList = new LinkedHashSet <String> ();
for(String s : input){
myList.put(s);
}
}
}
Вы можете объявить два конструктора и вызвать второй с первого:
class MyClass {
public MyClass(String... x) {
// for arrays
// this constructor delegate call to the second one
this(Arrays.asList(x));
}
public MyClass(List<String> x) {
// for lists
// all logic here
}
}
Вызовы будут выглядеть как
new MyClass(new ArrayList<String>());
new MyClass("dog", "cat", "rat");
new MyClass(new String[] {"rat", "Dog", "Cat"});
Поскольку в первом конструкторе только одна строка кода, это довольно минималистично.
Похоже, что массивы не являются итерируемыми, поэтому нет никакого способа сделать это. Невозможно иметь один конструктор, который принимает массивы И другие итерации. Это особенно раздражает, поскольку мы можем сделать следующее:
Foo[] foos = ...
for (Foo foo : foos)
См. этот пост для получения более подробной информации: Почему массив не назначается Iterable?
public class MyClass1 {
public MyClass1(final String... animals) {
for (final String animal : animals) {
System.out.println("eat " + animal);
}
}
public static void main(final String[] args) {
new MyClass1();
new MyClass1("dog", "cat", "rat");
new MyClass1(new String[] { "dog", "cat", "rat" });
}
}
или
public class MyClass2 {
public MyClass2(final Iterable<String> animals) {
for (final String animal : animals) {
System.out.println("eat " + animal);
}
}
public static void main(final String[] args) {
new MyClass2(Arrays.asList("cat", "rat", "dog", "horse"));
final LinkedList<String> animals = new LinkedList<String>();
animals.add("dog");
animals.add("house");
animals.addAll(Arrays.asList("cat", "rat"));
new MyClass2(animals);
}
}
Теоретически вы можете объявить конструктор примерно так:
MyClass(Object args) {
if (args instanceof List) {
...
} else if (args instanceof Set) {
...
} else if (args.getClass().isArray()) {
...
} else {
thrown new IllegalArgumentException("arg's type is wrong");
}
}
но ИМО, это было бы плохим дизайном API, поскольку он переводит всю проверку типов во время выполнения. (Другого способа сделать это с помощью одного конструктора нет. Единственный общий супертип типов массивов и интерфейса Collection
- это Object
.)
Намного лучше использовать перегрузка конструктора, как описано в других ответах.
Между прочим, следующее (из вашего примера) является синтаксической ошибкой Java, независимо от типов аргументов, объявленных конструктором:
MyClass c = new MyClass({"rat", "Dog", "Cat"});
Эта форма инициализатора массива может использоваться только в объявлении переменной; например
String[] foo = {"rat", "Dog", "Cat"};
или как часть выражения создания массива; например
String[] foo = new String[]{"rat", "Dog", "Cat"};
String[][] bar = new String[][]{{"rat", "Dog", "Cat"}, /* ... */};
Если вам действительно нужен один конструктор, вы можете использовать Arrays.asList, а затем поставить конструктора на коллекцию, которая охватывает List и Set.
У меня лично было бы два конструктора.