【问题标题】:How to avoid instanceof in copy constructor for inherited java clasess如何在继承的java类的复制构造函数中避免instanceof
【发布时间】:2013-02-16 01:39:10
【问题描述】:

我正在编写一个用于克隆对象的复制构造函数。当一个类引用了一个被少数其他类进一步继承的对象时。

class Person
{
    String name;
    Address address;
 }

class HomeAdress extends Address
{
}
class OfficeAdress extends Address
{
}

现在在 Person 的复制构造函数中,要决定要启动哪个 Address 对象,我必须使用 instanceof。

public Person(Person p)
{
    name = p.name;
    if(p.address instanceof HomeAddress)
    {
        address = new HomeAddress((HomeAddress) address);
    }else if(p.address instanceof OfficeAddress)
    {
        address = new OfficeAddress((OfficeAddress) address);
    }
}

因此,当将新类型的地址添加到模型中时,此问题的基本问题。我将不得不在 Person 复制构造函数中添加一个相同的检查。有没有办法避免 instanceof 检查实例化正确的地址对象。我可以使用refelction来避免代码中的instanceof吗?

【问题讨论】:

  • 不是您实际问题的答案,但您应该使用address = new HomeAddress((HomeAddress) p.address);(您忘记了两次p.)。
  • 我有类似的情况,并在链接中解决。 stackoverflow.com/questions/13450953/… 。希望对您有所帮助 public class Derived extends Base { public static void main(String ... args) { System.out.println(new Derived().createInstance()); } } abstract class Base { public Base createInstance() { //使用反射 try { return getClass().asSubclass(Base.class).newInstance(); } catch (Exception e) { throw new AssertionError(e); } } }
  • 最好的方法是避免使用复制构造函数。我在 Java 的 16 年中从未写过一篇。为什么你认为你需要一个?

标签: java inheritance copy-constructor cloning


【解决方案1】:

您应该将复制地址的责任委托给Address 类。无论你是否实现Cloneable,在Address 中放置一个clone() 方法,然后你可以(如果你需要自定义处理)在每个特定的Address 子类中覆盖它。然后在您的 Person 复制构造函数中,您只需要:

this.address = p.address.clone();

【讨论】:

  • stackoverflow.com/questions/5092540/… stackoverflow.com/questions/2427883/… 也很少有其他地方不推荐克隆。所以我决定复制 cosntructor。这就是为什么我在寻找克隆以外的解决方案。感谢您的帮助。
  • @kunal:你可以只为Person 使用复制构造函数,但仍然可以使Address 可克隆。看起来您已经了解了克隆的缺点,但没有考虑任何优点,或减轻缺点的方法。
  • @kunal:当您不同意我的回答时,我很想知道为什么您接受了与我实际上相同的答案。 (可克隆的概念与您是否实际实现Cloneable 接口并使用java.lang.Object 中的clone() 是分开的。)
  • 正确实施clone 没有任何问题。您与复制构造函数的斗争是您应该使用 clone 的确切原因。
  • @kunal:但“手动”版本正是我所说的。从根本上说,您仍在克隆 Address 对象,而负责这样做的是 Address 对象。我个人使用默认实现,除非我有理由不这样做,但该实现部分是一个单独的决定。请注意,接受的答案会造成不必要的(且无益的)字符串副本 - 我会敦促您不要这样做。
【解决方案2】:

首先,我猜这是一个错字:

address = new HomeAddress((HomeAddress) p.address);

其次,您可以在 Address 类中定义一个 copy() 方法,而不是强制转换对象,(可能是)抽象:

abstract class Address {
    abstract Address copy ();
}

并且你在Address的每个子类中实现了方法,然后你可以在Person的构造函数中调用它:

public Person(Person p)
{
    name = new String(p.name);
    address = p.address.copy();
}

【讨论】:

  • 你为什么打电话给new String(p.name)?为什么不直接复制字符串引用?毕竟,字符串是不可变的。
  • @JonSkeet Kunal 想要复制 Person,但他只克隆了 Person 本身和 address,但 name 没有被克隆。当然使用相同的name 不会有任何区别,但我只是想制作一个“真实”的副本,仅此而已。你是对的,通常不需要复制字符串。
  • 不仅没有必要,而且还非常有害,因为它需要处理器和 CPU。在 no 解释的答案中这样做很容易导致 OP 盲目地复制它并养成坏习惯。重要的是要了解,在克隆某些东西时,可以为不可变类型执行简单的引用副本。
猜你喜欢
  • 2013-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多