Подтвердить что ты не робот

Конструкторы Java Copy с дженериками

Это, вероятно, задавали миллионы раз раньше, но у меня возникают проблемы с записью конструктора копий в абстрактном классе с параметром ограниченного типа. У меня есть код, который выглядит так:

public abstract class Superclass<T> {
    Set<? extends Variable<T>> vars;

    public abstract Superclass<? extends T> copy();

    class Variable<T> {
        T value;
    }
}

class Foo extends Superclass<Integer> {
    public Foo copy() {
        Foo _newFoo = Foo();
        Set<FooVariable> _newVars = new HashSet<FooVariable>();
        _newVars.addAll(this.vars);
        _newFoo.vars = _newVars;
    }

    class FooVariable extends Variable<Integer> { /* ... */ }
}

class Bar extends Superclass<String> {
    public Bar copy() {
        Bar _newBar = Bar();
        Set<BarVariable> _newVars = new HashSet<BarVariable>();
        _newVars.addAll(this.vars);
        _newBar.vars = _newVars;
    }

    class BarVariable extends Variable<String> { /* ... */ }
}

Так как метод copy для Foo и Bar является тем же, за исключением типов переменных, я хотел бы иметь возможность переместить этот код в конкретный метод в суперклассе. Но я не могу понять (а), как иметь конкретный метод public Superclass<? extends T> copy, возвращать экземпляр Foo, если он вызван в экземпляре Foo и Bar, если вызывается в Bar и (b) vars установить с FooVariable или BarVariable, если это необходимо.

Может ли кто-нибудь помочь и рассказать мне, что мне не хватает? Спасибо.

4b9b3361

Ответ 1

Как насчет этого типа Superclass?

public abstract class Superclass<T> {

    Set<? extends Variable<T>> vars;

    public Superclass<? extends T> copy() {
        Superclass<T> _newSuperclass = this.getNewInstance();
        Set<Variable<T>> _newVars = new HashSet<Variable<T>>();
        _newVars.addAll(this.vars);
        _newSuperclass.vars = _newVars;
        return _newSuperclass;
    }

    public abstract Superclass<T> getNewInstance();

    class Variable<T> {

        T value;
    }
}

Дело в том, что вам просто нужно реализовать getNewInstance() в подклассах вместо конструктора.

Итак, Foo будет выглядеть так:

class Foo extends Superclass<Integer> {

    @Override
    public Superclass<Integer> getNewInstance() {
        return new Foo();
    }

    class FooVariable extends Variable<Integer> { /* ... */ }
}

Ответ 2

Ввести второй тип типичного типа для представления Variable<T>, U.

Тогда Foo.FooVariable<T> и Bar.BarVariable<T> удовлетворяют границам U и могут быть возвращены из метода copy.

ИЗМЕНИТЬ

Я изменил код, чтобы переместить реализацию copy в суперкласс. Он опирается на метод newInstance (введенный уже @OndrejBozek).

public abstract class Superclass<T, U extends Variable<T>> {
    Set<U> vars;

    class Variable<T> {
        T value;
    }

    public Superclass<T, U> copy() {
        Superclass<T, U> _newSuperclass = newInstance();
        Set<U> _newVars = new HashSet<U>();
        _newVars.addAll(vars);
        _newSuperclass.vars = _newVars;
       return _newSuperclass;
    }

    public abstract Superclass<T, U> newInstance();
}

class Foo extends Superclass<Integer, Foo.FooVariable> {
    public Foo newInstance() { return new Foo(); }

    class FooVariable extends Variable<Integer> { /* ... */ }
}

class Bar extends Superclass<String, Bar.BarVariable> {
    public Bar newInstance() { return new Bar(); }

    class BarVariable extends Variable<String> { /* ... */ }
}

Ответ 3

Протестировав этот код, у него есть несколько предупреждений, но он делает то, что вы хотите:

public <C extends Superclass<? extends T>> C copy() throws InstantiationException, IllegalAccessException {
    C result= (C) this.getClass().newInstance();
    HashSet newVars= new HashSet();
    newVars.addAll(this.vars);
    result.vars= newVars;
    return result;
}

Одно замечание: это не конструктор копирования. Это всего лишь метод копирования. Конструктор не имеет типа возврата и его имя равно имени класса.