Как в целом указать Сериализуемый список

У меня есть следующий интерфейс:

public interface Result<T extends Serializable> extends Serializable{
    T getResult();
}

С этим интерфейсом я не могу определить переменную типа

Result<List<Integer>>

потому что List не является сериализуемым.

Однако, если я изменил интерфейс на это:

public interface Result<T> extends Serializable{
    T getResult();
}

Теперь становится невозможным реализовать с проверкой времени компиляции, потому что нет гарантии, что T сериализуется, а вся точка класса - сохранить результат, чтобы я мог вернуть его позже, возможно, после передачи через Интернет.

Мой вопрос в том, есть ли способ объявить переменную так, чтобы она была двух типов, или есть какой-то другой способ сделать это, чего я не вижу? Итак, возможно, что-то вроде:

(List<Integer> extends Serializable) value = new ArrayList();

Я пытаюсь поставить столько бремени этой проблемы на реализацию, чтобы будущие потребители этого интерфейса не знали о проблеме.

Спасибо за вашу помощь!

Вот более подробный пример того, что я пытаюсь сделать: Я вызываю сервер, результат которого я хочу сохранить в объекте результата, но я не хочу иметь дело с кастингом. Таким образом, каждый метод, который может быть вызван на сервере, будет определять тип результата с помощью дженериков. Этот объект результата также сохранит другие метаданные о результате, например, может быть, слишком много информации для возврата. Во многих случаях я хочу использовать список, но интерфейс List не сериализуем, хотя многие из реализаций.

Итак, как я могу указать, что используемый тип должен быть Serializable, но все же допускать использование List (а не конкретной реализации List)?

Ответ 1

Вам нужно объявить свой тип переменной как Result<? extends List<Integer>>.

Проверка типа знает, что List не serializable, но подтип List может быть serializable.

Вот пример кода. Реализация интерфейса была выполнена только с анонимными внутренними классами. Вы можете видеть, что getResult вернет a List<Integer> для второго объекта

   Result<Integer> res = new Result<Integer>() {

        Integer myInteger;

        private static final long serialVersionUID = 1L;

        @Override
        public Integer getResult() {
            return myInteger;
        }

        @Override
        public void addResult(Integer input) {
            this.myInteger = input;
        }
    };

    Integer check = res.getResult();


    Result<? extends List<Integer>> res2 = new Result<ArrayList<Integer>>() {

        ArrayList<Integer> myList;

        private static final long serialVersionUID = 1L;

        @Override
        public ArrayList<Integer> getResult() {
            return myList;
        }

        @Override 
        public void addResult(ArrayList<Integer> input) {
            this.myList = input;
        }

    };

    List<Integer> check2 = res2.getResult();

Изменить: сделанный пример более полным, реализуя метод void addResult(T input) интерфейса

Ответ 2

Хотя интерфейс List не реализует Serializable, все встроенные реализации Collection делают. Это обсуждается в справочнике "Реализации" .

Часто задаваемые вопросы о дизайне коллекций задают вопрос "Почему коллекция не расширяется для Cloneable и Serializable?" , в которой говорится о том, почему Sun разработала ее без расширение Serializable.

Ответ 3

Вы можете просто объявить переменную как Result<ArrayList<Integer>>. Пока вы все еще программируете интерфейс List, вы действительно не пожертвовали заменой.

Я собирался также предложить создать новый интерфейс ListResult:

public interface ListResult<T extends Serializable & List<E extends Serializable>>
        implements Result<T> {
    T getResult();
}

но тогда вам все равно придется объявлять переменную как ListResult<ArrayList<Integer>>. Поэтому я бы пошел по более простому маршруту.

Ответ 4

Если вы намерены использовать тип результата для списков в целом и хотите, чтобы элементы списка были сериализованы, вы можете определить его следующим образом:

public interface Result<T extends List<? extends Serializable>> {}

Таким образом, вы можете определить что-то вроде:

Result<List<Integer>> r;

Но что-то вроде этого не будет компилироваться:

Result<List<List>> r;

Теперь, если вы хотите использовать результат как для, скажем, для Integer, так и для List, то тип не требуется для сериализации, верно? В этом случае я не совсем понимаю, какова ваша цель.

Ответ 5

Ты вроде как можешь, я думаю:

public class Thing<T extends Serializable> implements Serializable {
    private static class Holder<V extends Serializable> {
        private final V value;
        private Holder(V value) {
            this.value = value;
        }
    }
    private Holder<? extends List<T>> holder;
    private <V extends List<T> & Serializable> void set(V value) {
        holder = new Holder<V>(value);
    }
}

Вам это кажется уродливым?

Могу ли я предположить, что вы не пытаетесь внедрить реализацию Serializable с использованием системы статического типа Java? Это только интерфейс, потому что аннотации тогда не были. Это просто нецелесообразно применять. OTOH, вы можете применить его с помощью проверки типа, которая выполняет статический анализ в закрытой системе.

Ответ 6

Как я решил решить эту проблему, это использовать это как интерфейс:

public interface Result<T> extends Serializable{
    T getResult();
}

Затем создайте реализацию для каждого из разных типов коллекций, а также для любого объекта.

Итак, например, будет выглядеть класс ListResult:

public class ListResult<T> implements Result<List<T>>{
    public List<T> getResult(){
        //return result
    }

    public <V extends List<T> & Serializable> void setResult(V result){
        //store result
    }
}

Ответ 7

Первоначальная мысль. Если вы планируете использовать сериализацию для любого долгосрочного хранения данных, не делайте этого. Сериализация не гарантируется для работы между вызовами JVM.

Вероятно, вам не следует расширять Serializable, если вы не добавляете функциональность, связанную с сериализацией Object. Вместо этого ваш класс, который реализует Result, должен также реализовать Serializable.