Java 直接修改对象还是返回对象的修改克隆更好?

Java 直接修改对象还是返回对象的修改克隆更好?,java,object,clone,immutability,Java,Object,Clone,Immutability,问题是我不能修改一个从内部编写的对象,从而生成一个我修改并返回的克隆。但是,在其他函数中,我直接修改调用该方法的对象。我希望,而且人们也建议,保持事情的一致性,这样用户就可以在不修改实际对象的情况下对返回的克隆执行任何他们喜欢的操作 我必须在某些函数中返回一个修改过的对象克隆,因为无法绕过它(我知道)。除了标题中的问题外,是否最好采用一致的方式(即使是最微小的更改,也会导致我返回克隆),或者如果在同一个类中有不同的方式响应用户,是否可以 [编辑]这样做是否更好: public Image fi

问题是我不能修改一个从内部编写的对象,从而生成一个我修改并返回的克隆。但是,在其他函数中,我直接修改调用该方法的对象。我希望,而且人们也建议,保持事情的一致性,这样用户就可以在不修改实际对象的情况下对返回的克隆执行任何他们喜欢的操作

我必须在某些函数中返回一个修改过的对象克隆,因为无法绕过它(我知道)。除了标题中的问题外,是否最好采用一致的方式(即使是最微小的更改,也会导致我返回克隆),或者如果在同一个类中有不同的方式响应用户,是否可以

[编辑]这样做是否更好:

 public Image fillWithColor(Color fillColor) {
    Image newImage = new Image(this.getWidth(), this.getHeight(), this.getType());

    for (int x = 0; x < this.getWidth(); x++) {
        for (int y = 0; y < this.getHeight(); y++) {
            newImage.setPixel(x, y, fillColor.getRGB());
        }
    }

    return newImage;
}
公共图像填充颜色(颜色填充颜色){
Image newImage=新图像(this.getWidth()、this.getHeight()、this.getType());
对于(int x=0;x
或者这个:

public void fillWithColor(Color fillColor) {
    for (int x = 0; x < this.getWidth(); x++) {
        for (int y = 0; y < this.getHeight(); y++) {
            this.setPixel(x, y, fillColor.getRGB());
        }
    }
}
public void fillWithColor(颜色fillColor){
对于(int x=0;x
出于各种重要原因,一个大趋势是将尽可能多的数据视为只读数据。甚至今天的数据库也在这样做

显然,您已经认识到,不加控制地修改数据会给您带来麻烦。很好。尝试将您的数据设计为不可变对象,从长远来看,很多事情都会容易得多。只需注意,Java中的某些数据结构本质上是可变的(数组、哈希表等),它们意味着并且预期会发生变化

在上面的示例中,我将选择第一个变体。为什么?复制映像可能需要几微秒和一些RAM,而不是就地更新。但是,您可以保留旧图像,这可能是有益的,具体取决于您的应用程序。此外,您可以在10个不同的线程中并行使用10种不同的填充颜色为同一图像着色,并且不会出现锁定问题

尽管如此,还是不可能回答你的问题,比如“总是更好……”。这取决于您的问题、您的环境、编程语言、您正在使用的库以及许多其他因素

比如说,不可变数据在大多数情况下是首选的,除非有严重的理由反对它。(节省几微秒的执行时间通常不是一个重要原因。)


换言之,应该有充分的理由使数据类型可变,而不可变性应该是默认值。不幸的是,Java不是支持这种方法的语言,相反,默认情况下,一切都是可变的,需要付出一些努力才能使其与众不同。

唯一正确的答案是:

“视情况而定”

这就是工程的全部内容。做出正确的权衡。假设你是一名为城市工作的工程师,负责为城市中心设计新的垃圾箱。你有一些决定要做。你想把它们弄大,这样它们就可以装很多垃圾,在繁忙的日子里就不会溢出。但是你也要把它们弄小,这样它们就不会在人行道上占据太多的空间。你想让它们变轻,这样在倒空它们的时候可以很容易地处理,而变重,这样它们就不会被风吹倒或被流氓踢倒。所以这不是一个大或小、重或轻的问题,而是多大、多重的问题

在软件工程中,还有许多相互排斥的品质,您必须在项目中做出正确的选择。一些例子:

  • 延迟与吞吐量-您是希望对请求做出快速反应,还是希望完成大量工作
  • 内存vs cpu-您是否可以使用大量内存作为查找表,还是会消耗cpu时间来计算答案
不变与可变

不可变类型的优点是它们是线程安全的。线程A和线程B都可以引用同一个对象,并且仍然可以确保在不使用锁的情况下其值不会意外更改。如果线程A想要更改该值,那么它可以通过更改它对新对象的引用来更改该值;线程B仍然愉快地抓住原始对象

让对象的值意外更改不仅是并发编程中的一个问题,而且在类的用户不期望的情况下也可能发生。这就是为什么会有这样的概念

java中的stock
Date
类是可变的。因此,考虑<代码>人>代码>类,使用<代码> GeGoestDATE()< <代码> GETER和<代码> SETIZATEATEATE() SETTER。作为
Person
类的用户,您希望只能通过使用setter来更改Person的出生日期,但是如果getter没有返回防御副本,则该类的用户也可以通过更改从
getBirthDate()
接收的
date
对象来意外地更改它

因此,不可变类型使程序线程安全(r)且不易出错,因此通常是一个好主意,但您不能总是使用它们。您的
fillWithColor()
函数就是一个实际不可行的例子

Canvas
类是一个可变对象。您将有一个
fillWithColor()
函数,还有
drawLine()
drawlipse()
drawText()
,以及更多功能。使用这些函数构建图形可能需要多次调用。考虑绘制一个“交通标志:

  • 填充背景色
  • 画一个红色的圆圈
  • 在里面画一个白色的圆圈