Java 创建用于复制不同对象的通用函数

Java 创建用于复制不同对象的通用函数,java,object,java-8,copy,Java,Object,Java 8,Copy,因此,我有一个用例,需要复制类es的对象(类可能因工厂中的输入类型而异) 这是我尝试做的一个例子 public interface DataUtil { // the main wrapper static Object copyObject(Object payload){ if(payload instanceof Human)) return copyEntry((Human) payload); if(paylo

因此,我有一个用例,需要复制
es的
对象
(类可能因工厂中的输入类型而异)

这是我尝试做的一个例子

public interface DataUtil {

    // the main wrapper 
    static Object copyObject(Object payload){
        if(payload instanceof Human))
            return copyEntry((Human) payload);
        if(payload instanceof Car))
            return copyEntry((Car) payload);
        if(payload instanceof Planet))
            return copyEntry((Planet) payload);        
        return payload;
    }

    static Human copyEntry(Human human) {
        return Human.builder()
                .name(human.getName())
                .age(human.getAge())
                .build();
    }

    static Car copyEntry(Car car) {
        return Car.builder()
                .model(car.getModel())
                .brand(car.getBrand())
                .build();
    }

    static Planet copyEntry(Planet planet) {
        // return builder like previous
    }
}
如果你看一下
copyObject
函数,它会按预期完成任务,但问题是返回类型。目前,为了使自身兼容,它返回一个
对象
,但我更愿意返回它特定的类对象(例如
人类
汽车


有没有一种方法可以通过泛型(使用
)实现这一点?或者这是一种糟糕的方法吗?

不幸的是,您必须执行一些未经检查的强制类型转换,例如:

static <TPayload> TPayload copyObject(Object payload) {
    if (payload instanceof Human)
        return (TPayload) copyEntry((Human) payload);
    if (payload instanceof Car)
        return (TPayload) copyEntry((Car) payload);
    if (payload instanceof Planet)
        return (TPayload) copyEntry((Planet) payload);
    return (TPayload) payload;
}
有没有一种方法可以通过泛型(使用)来实现这一点 一开始是一个糟糕的方法吗

这是一种不好的方法,因为您将一个
对象作为参数接收
您无法从中推断具体类型:而您使用的是
instanceof
。这不是一个好方法。
这里有两个想法(足够相关)

1)引入可复制界面

您可以引入一个接口,该接口由要复制的对象类实现:

public interface Copyable<T> {
    T copy(T t);
}
2)使用访客模式

作为替代方案,它也是访问者模式的一个好例子:您希望根据参数的具体类型应用处理。
它允许按照实际代码将复制操作分组在一起

常规的
copyObject()
方法可以依赖于将根据参数的具体类型进行复制的
CopyVisitor

@SuppressWarnings("unchecked")
static <T extends Visited> T copyObject(T payload) {
    CopyVisitor visitor = new CopyVisitor();
    payload.accept(visitor);
    return (T) visitor.getCopy();
}
这样:

Human human = new Human();
// set some fields  ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile
public class CopyVisitor implements Visitor {

    private Visited copy;

    @Override
    public void visitHuman(Human human) {
        copy = Human.builder()
                    .name(human.getName())
                    .age(human.getAge())
                    .build();

    }

    @Override
    public void visitCar(Car car) {
        copy = Car.builder()
                  .model(car.getModel())
                  .brand(car.getBrand())
                  .build();
    }

    @Override
    public void visitPlanet(Planet planet) {
        //...
    }

    public Visited getCopy() {
        return copy;
    }

}
Human human = new Human();
// set some fields  ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile
所访问的类(车、人、计划)将实现一个特定的接口来“接受”访问者:

public interface Visited {
    void accept(Visitor visitor);
}
例如:

public class Human implements Copyable<Human> {

   @Override
   public Human copy(Human t) {
       return    Human.builder()
                     .name(human.getName())
                     .age(human.getAge())
                     .build();
   }

}
public class Human implements Visited {

    @Override
    public void accept(Visitor visitor) {
        visitor.visitHuman(this);
    }

}
因此,您可以通过以下方式使用
copy()
方法:

Human human = new Human();
// set some fields  ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile
public class CopyVisitor implements Visitor {

    private Visited copy;

    @Override
    public void visitHuman(Human human) {
        copy = Human.builder()
                    .name(human.getName())
                    .age(human.getAge())
                    .build();

    }

    @Override
    public void visitCar(Car car) {
        copy = Car.builder()
                  .model(car.getModel())
                  .brand(car.getBrand())
                  .build();
    }

    @Override
    public void visitPlanet(Planet planet) {
        //...
    }

    public Visited getCopy() {
        return copy;
    }

}
Human human = new Human();
// set some fields  ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile

如果您了解对象中的类型,可以使用:

static <T> T copyObject(Object payload)
    {
        if (payload instanceof Human)
        {
            return (T) copyEntry((Human) payload);
        }
        if (payload instanceof Car)
        {
            return (T) copyEntry((Car) payload);
        }
        if (payload instanceof Planet)
        {
            return (T) copyEntry((Planet) payload);
        }
        return (T) payload;
    };
即使Java的类型擦除不适用,您的语言也需要运行时知识,即“依赖类型”

<> p>因此,在某些语言中,如C++中返回的重载将不利于运行时类型的切换,如List< /C> > < /P>
但是,不管怎样,为什么需要这样做呢?调用后,您将再次在一个新的异构列表中收集所有对象实例

复制构造函数如何?@MuratK.:我希望
copy
发生在
util
中,所以要避免这种方法!!在当前状态下不需要此类。只需提供一个复制构造函数并调用
新人类(人类)
。实际问题是
人类
/
汽车
等是不在我控制范围内的代码库,它们不具备
复制
常量
的功能,因此这一切都很混乱。这就是为什么我想把它包含在
Util
中的原因:|您应该得到一个库来为您进行克隆,这样您就不必浪费时间编写(糟糕的)代码。它们也是完全通用的!不需要
Copyable
,有
UnaryOperator
这是对的,但是
公共类人类实现可复制{…}
公共类人类实现UnaryOperator{…}
更有意义,只要想想我多么不喜欢/理解访问者模式,这就太棒了!加一@尤金:好的。但是,我也更喜欢
human.copy(human)
而不是human.apply(human)`出于同样的原因:可读性更强:)谢谢:)我对访问者模式也不感兴趣,但在某些情况下可能没那么糟糕:)回答得很好。但我觉得将复制结果存储在实例变量
copy
中,然后调用
getCopy()
似乎很奇怪。。。有什么想法吗?变量的编译时类型可以比实际实例更广泛,就像使用
Object o=“foo”,因此这与类型擦除无关,如果要对实际的对象类型而不是编译时声明作出反应,则无论如何都需要检查
instanceof
。除此之外,您的通用签名承诺返回调用方希望返回的任何内容,而不管他们传入了什么,这当然是根本性的破坏。例如,它允许写入
Number n=copyObject(“someString”)..@Holger right。从答案中删除了类型擦除
Human h1 = new ...
Human h2= copyObject(h1);