#java #generics #constructor #type-parameter
#java #общие #конструктор #тип-параметр
Вопрос:
Я хочу создать наборы данных для использования в тестировании алгоритмов.
У меня есть универсальный класс-оболочка, который содержит данные типа T, а также информацию о произвольном размере / сложности набора данных, чтобы иметь возможность сопоставлять размер ввода с временем выполнения.
Поскольку не все, что я хочу протестировать, будет просто кратным чему-либо, я не хочу ограничивать T.
Однако я хотел бы иметь конструктор, который «распознает» что-то как коллекцию и может затем определить сам размер.
Приведенный ниже код действительно работает, но имеет предупреждение компилятора по уважительной причине или должен выдавать исключение соответственно.
public class DataSet<T> {
private final long size;
private final T data;
public DataSet(T data, long size) {
this.data = data;
this.size = size;
}
public <I extends Collection<?>> DataSet(I input) { //allows for DataSet<String> foo = new DataSet(List.<Integer>of(1, 4, 6);
this.data = (T) input; //compiler warning / ClassCastException: unchecked cast I to T
this.size = input.size();
}
public DataSet (T input) {
if(!(input instanceof Collection)) {
throw new IllegalArgumentException("Input needs to be Collection"); //either this or a ClassCastException later
}
this.data = input;
this.size = ((Collection<?>) input).size();
}
public T getData() {
return data;
}
public long getSize() {
return size;
}
}
Оба работают, если используются правильно, но также допускают ошибки, поскольку я недостаточно способен описать компилятору, что я хочу, чтобы там было разрешено (‘T совпадает с I’ или ‘T нужно расширять коллекцию только в этом конструкторе’).
Итак; Как мне определить конструктор, который может накладывать ограничения на параметры типа своего класса без введения новых параметров типа для себя или класса и с поддержкой компилятора для использования?
Комментарии:
1. Что ж, я пока не торопился и создал подкласс, параметр типа которого должен расширять коллекцию.
Ответ №1:
Я думаю, что лучший способ — разделить вашу реализацию на 2 дочерних элемента, что-то вроде:
public interface DataSet<T>{
T getData();
long getSize();
}
class SimpleDataSet<T> implements DataSet<T>{
private final long size;
private final T data;
public SimpleDataSet(T data, long size) {
this.data = data;
this.size = size;
}
public T getData() {
return data;
}
public long getSize() {
return size;
}
}
class CollectionDataSet<I> implements DataSet<Collection<I>>{
private final Collection<I> data;
public CollectionDataSet(Collection<I> data) {
this.data = data;
}
public Collection<I> getData() {
return data;
}
public long getSize() {
return data.size();
}
}
Но если это невозможно, вы можете попробовать выполнить следующее:
public <I> DataSet (Collection<I> input) {
this.data = (T) input;
this.size = input.size();
}
Или
private final Collection<T> collectionData;
public DataSet (Collection<T> input) {
this.data = null;
this.collectionData = input;
this.size = collectionData.size();
}