Непроверенное предупреждение о преобразовании с генериками - PullRequest
1 голос
/ 03 июля 2019

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

Я реализую неизменяемые объекты с шаблоном построителя, для которого я реализовал интерфейс "Неизменяемый"с внутренним интерфейсом "Builder".

Каждый неизменяемый класс реализует интерфейс Immutable и реализует внутренний статический класс Builder, который реализует интерфейс Builder.

Все это прекрасно работает.

Теперь я реализую набор очень простых классов, которым на самом деле не нужен компоновщик, но я все же хочу реализовать интерфейс Immutable, поэтому объекты этих классов являются экземплярами «Immutable», но я нехочу реализовать пустые компоновщики без какой-либо функциональности для каждого класса.Я бы предпочел иметь абстрактный класс для реализации одного простого компоновщика для всех простых классов.Строитель просто сохранит исходный объект и вернет его через метод build (), поэтому интерфейс Immutable реализован полностью

Метод build () построителя должен возвращать объект реализующего класса, хотя,Поэтому я добавил generics.

public interface Immutable {
    public interface Builder<T> {
        public T build();
    }
    public <T> Builder<T> builder();
}


public interface Interface extends Immutable {

    public interface BuilderInterface<T> extends Immutable.Builder<T> {

    }
}


public abstract class AbstractClass implements Interface {

    public static class AbstractBuilder<T> implements Interface.BuilderInterface<T> {

        private final T object;

        public AbstractBuilder(T object) {

            this.object = object;
        }

        @Override
        public T build() {

            return this.object;
        }
    }

    protected AbstractClass() {

        super();
    }
}

public class ConcreteClass extends AbstractClass {

    public ConcreteClass() {

    }

    @Override
    public AbstractBuilder<ConcreteClass> builder() {

        return new AbstractClass.AbstractBuilder<ConcreteClass>(this);
    }
}

Я ожидал, что универсальный тип T интерфейса Immutable будет принимать тип реализующего класса, но вместо этого он выглядит как Object, что приводит к следующему предупреждению:

Тип безопасности: возвращаемый тип AbstractClass.AbstractBuilder для builder () из типа ConcreteClass нуждается в непроверенном преобразовании для соответствия Immutable.Builder из типа Immutable

EDIT: Theпредупреждение выдается методом builder () класса ConcreteClass.

1 Ответ

1 голос
/ 03 июля 2019

Все довольно просто - сигнатура метода Immutable#builder ожидает параметр типа T, установленный "на лету" для фактического вызова метода и не привязанный к классу.Чтобы соответствующим образом переопределить этот метод, сигнатура в ConcreteClass будет иметь значение

public <T> Builder<T> builder() {

, что явно противоречит определению вашего компоновщика

return new AbstractClass.AbstractBuilder<ConcreteClass>(this);

Чтобы сделать все это компилируемым, вы должны сделать вывод T для Immutable#builder из класса, а не из вызывающего метода, т. Е. Что у вас наконец есть

public interface Immutable<T> {

    public interface Builder<T> {
        public T build();
    }

    public Builder<T> builder(); 
}

, и все наследующие классы изменились соответственно, чтобы передать T его предшественникам.

public interface Interface<T> extends Immutable<T> {

    public interface BuilderInterface<T> extends Immutable.Builder<T> {
    }
}


public abstract class AbstractClass<T> implements Interface<T> {

    public static class AbstractBuilder<T> implements Interface.BuilderInterface<T> {

        private final T object;

        public AbstractBuilder(T object) {

            this.object = object;
        }

        @Override
        public T build() {

            return this.object;
        }
    }

    protected AbstractClass() {

        super();
    }
}


public class ConcreteClass extends AbstractClass<ConcreteClass> {

    public ConcreteClass() {

    }

    @Override
    public Builder<ConcreteClass> builder() {
        return new AbstractClass.AbstractBuilder<ConcreteClass>(this);
    }
}
...