【问题标题】:Java Copy constructors with generics具有泛型的 Java 复制构造函数
【发布时间】:2013-06-25 18:09:32
【问题描述】:

这可能已经被问过一百万次了,但是我很难在一个带有有界类型参数的抽象类上编写一个复制构造函数。我有一些看起来像这样的代码:

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&lt;? extends T&gt; copy 方法,如何返回Foo 实例,如果在Bar 上调用Bar 实例,以及(b)填充vars 设置为 FooVariables 或 BarVariables 视情况而定。

有人可以帮忙告诉我我缺少什么吗?谢谢。

【问题讨论】:

  • 复制构造函数是一个实际的构造函数,它接受类的实例作为参数。这更像是一种复制方法。
  • 不会在这些Foo _newFoo = Foo(); 上给出编译错误,那么缺少的返回类型呢?或者我完全误读了一些概念

标签: java generics


【解决方案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> { /* ... */ }
}

【讨论】:

  • 是的,它可以编译。刚用Java 1.7编译它。该代码应该有什么问题?
  • 我认为你错过了_newSuperClass.vars = _newVars;
  • 在我看来,复制构造函数应该创建一个新的、不同的对象实例,即 a.equals(b) 应该为真,a == b 应该为假。仅复制引用的构造函数将无法满足该要求。
  • 我不确定你对原始对象 a 和新创建的对象 b 的含义是什么,肯定是 a!=b。也许您的意思是“克隆”。 en.wikipedia.org/wiki/Cloning_(programming)
【解决方案2】:

引入第二个泛型类型参数来表示Variable&lt;T&gt;U

那么,Foo.FooVariable&lt;T&gt;Bar.BarVariable&lt;T&gt; 满足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> { /* ... */ }
}

【讨论】:

  • 感谢您的帮助。尽管这个解决方案确实强制了我感兴趣的类型安全,但我仍然在Foo.copyBar.copy 方法中重复了很多代码。你能想出一种将所有代码移到超类中的方法吗?
  • @jay,我已经修改了我的答案,试图将 copy 移动到超类中。
【解决方案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;
}

备注:这不是复制构造函数。这只是一种复制方法。构造函数没有返回类型,它的名字和类名一样。

【讨论】:

    猜你喜欢
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多