Создание конструктора универсального класса с дополнительными ограничениями типа

#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();
    }