带有泛型的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> { /* ... */ }
}

由于FooBarcopy方法除了变量类型之外是相同的,所以我希望能够将代码移动到超类中的具体方法中。但我不知道(a)如果在Foo上调用具体的public Superclass<? extends T> copy方法,则如何返回Foo实例,如果在Bar上调用Bar实例,以及(b)根据需要用FooVariables或BarVariables填充vars集合。

有人能帮我告诉我缺了什么吗?谢谢

这种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> { /* ... */ }
}

引入第二个泛型类型参数来表示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> { /* ... */ }
}

测试了这个代码,它有几个警告,但它做了你想要的:

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;
}

有一句话:这不是一个复制构造函数。这只是一种复制方法。构造函数没有返回类型,并且其名称等于类名。

最新更新