这是一个不可变的类吗?
我不知道不可变类应该是什么样子,但我很确定这个是这样的。我说得对吗?如果我不这样做,请指定应添加/删除的内容。
import java.io.Serializable;
public class Triangle implements IShape, Serializable {
private static final long serialVersionUID = 0x100;
private Point[] points;
public Triangle(Point a, Point b, Point c) {
this.points = new Point[]{a, b, c};
}
@Override
public Point[] getPoints() {
return this.points;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (this == obj) return true;
if (getClass() != obj.getClass()) return false;
Point[] trianglePoints = ((Triangle) obj).getPoints();
for (int i = 0; i < points.length; i++){
if (!points[i].equals(trianglePoints[i])) return false;
}
return true;
}
}
这能起到作用吗?
@Override
public Point[] getPoints() {
Point[] copyPoint = {
new Point(points[0]),
new Point(points[1]),
new Point(points[2]),};
return copyPoint;
}
点类:
import java.io.Serializable;
public class Point implements Serializable {
private static final long serialVersionUID = 0x100;
public int x;
public int y;
public int z;
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Point(Point that) {
this.x = that.x;
this.y = that.y;
this.z = that.z;
}
public boolean equals(Object obj) {
// assume this is a typical, safe .equals implementation
// that compares the coordinates in this instance to the
// other instance
return true;
}
}
I have no idea what immutable class should look like but am pretty sure this one is. Am I right? If I'm not please specify what should be added/removed.
import java.io.Serializable;
public class Triangle implements IShape, Serializable {
private static final long serialVersionUID = 0x100;
private Point[] points;
public Triangle(Point a, Point b, Point c) {
this.points = new Point[]{a, b, c};
}
@Override
public Point[] getPoints() {
return this.points;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (this == obj) return true;
if (getClass() != obj.getClass()) return false;
Point[] trianglePoints = ((Triangle) obj).getPoints();
for (int i = 0; i < points.length; i++){
if (!points[i].equals(trianglePoints[i])) return false;
}
return true;
}
}
Will this do the trick?
@Override
public Point[] getPoints() {
Point[] copyPoint = {
new Point(points[0]),
new Point(points[1]),
new Point(points[2]),};
return copyPoint;
}
Point class:
import java.io.Serializable;
public class Point implements Serializable {
private static final long serialVersionUID = 0x100;
public int x;
public int y;
public int z;
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Point(Point that) {
this.x = that.x;
this.y = that.y;
this.z = that.z;
}
public boolean equals(Object obj) {
// assume this is a typical, safe .equals implementation
// that compares the coordinates in this instance to the
// other instance
return true;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
不,您可以更改 Points 数组中的内容。如果要使其不可变,请让 getter 分发 Points 数组的副本,而不是原始数组。
试试这个:
Point 也需要是不可变的(正如 Nikita Rybak 指出的那样)。有关如何复制数组,请参阅如何在 Java 中复制数组。
No, you can change what's in the Points array. If you want to make it immutable, have the getter hand out a copy of the Points array, not the original.
try this:
Also Point needs to be immutable (as Nikita Rybak points out). For how to copy arrays see how to copy an array in Java.
不,不是。您公开 Point[],调用者可以修改其内容。另外,你的类不是最终的,所以有人可以通过子类化它来破坏它。
No, it's not. You expose the Point[] and a caller could modify its contents. Also, your class is not final, so someone could subvert it by subclassing it.
不,它绝对是可变的。
您不仅公开了实际的 Point[] 数组,而且不进行防御性复制(Bloch 2nd ed.,第 39 项)通过构造函数获取 Point 对象本身。
删除或添加到它,所以它是
可变的。
b 和 c,然后调用 setX() 或 setY()
让他们在之后更改数据
建造。
No, it's definitely mutable.
Not only do you expose the actual Point[] array, you don't defensive-copy (Bloch 2nd ed., Item 39) the Point objects themselves when taking them in via the constructor.
removed or added to it, so it's
mutable.
b, and c, then call setX() or setY()
on them to change their data after
construction.
关闭。一方面,不可变类应该将其字段设为final,但这不是必需的。
但是,您通过 getter 公开了一个数组,并且它不是不可变的。使用 Arrays.copyOf(数组,长度):
Close. For one thing, an immutable class should make it's fields final, but that's not a requirement.
However, you are exposing an array through the getter, and that is not immutable. Make a defensive copy using Arrays.copyOf(array, length):
在 Guava 的帮助下,我要做的就是使此类不可变。我从您发布的代码中的
@Override
中看到IShape
似乎需要来自getPoints()< 的
Point[]
/code> 方法,但为了示例,我忽略了它,因为使用对象数组是一个相当糟糕的主意,特别是如果您想要不可变性(因为它们不能是不可变的)。Point
也应该更像:Here's what I'd do to make this class immutable, with the help of Guava. I see from the
@Override
in the code you posted thatIShape
seems to require aPoint[]
from thegetPoints()
method, but I'm ignoring that for the sake of example since the use of object arrays is a rather poor idea, especially if you want immutability (since they cannot be immutable and all).Point
should also be more like:为了成为一个不可变的类,仅仅保证你的方法不改变对象是不够的。除了让所有字段都是私有的并且方法不允许更改之外,您还必须保证子类具有相同的不变性承诺。这包括使类本身成为最终类,并确保不会返回对字段的引用。
这篇文章对此进行了简短但出色的处理:
http:// www.javaranch.com/journal/2003/04/immutable.htm
In order to be an immutable class, it is not enough that your methods promise not to change the object. In addition to having all fields be private and the methods not allow changing, you must also guarantee that the subclasses have the same promise of immutability. This includes making the class itself final, and ensuring that no references to the fields are ever returned.
A short, but excellent treatment of this can be found in this article:
http://www.javaranch.com/journal/2003/04/immutable.htm
您不仅需要提供内部化数组的不可变副本,还需要确保 Point 对象是不可变的。
考虑标准 Java API 中 Point 类的以下用法:
Not only do you need to provide an immutable copy of the internalised array, you also need to make sure that the Point object is immutable.
Consider the following use of the Point class in the standard Java API:
它不是不可变的,因为......
因此,该类不是不可变的,因为您可以更改实例的状态(公开的内部
Point[]
),这也会更改状态对同一实例的引用。为了使其成为真正的不可变类,您需要方法来分别从每个点获取 X 和 Y,例如:
或者
返回
点
的副本,就像您在编辑中建议的那样。It is not immutable because ...
Thus the class is not immutable because you can change the state of an instance (internal
Point[]
exposed) and this also changes the state of a reference to the same instance.To make it a true immutable class, you would need methods to separately get X and Y from each point, for example:
or
or return a copy of the
points
like you suggested in your edit.除了其他人已经指出的内容之外,您还应该:
final
以防止子类创建可变的 Triangle。在《Effective Java》中,Joshua Bloch 在第 15 项:最小化可变性中提供了不可变类的一般规则列表。
In addition to what others have already noted, you should:
final
to prevent the creation of mutable Triangles by subclasses.In "Effective Java," Joshua Bloch provides a list of rules for immutable classes in general, in Item 15: Minimize Mutability.
1)使成员成为私有和最终的 - 所以
2)使类成为最终的,这样它就不能被子类化
3)对可变成员(数组)的独占访问 - 意味着返回可变成员的副本而不是对可变成员的引用
为了最好地处理这个主题请参阅 Joshua Bloch,《Effective Java》- 第 15 条
1) Make members private and final - so
2) Make class final so it cannot be sub-classed
3) Exclusive access to mutable members (array) - meaning return copy of and not the reference to mutable members
For the best treatment of this subject refer to Joshua Bloch, Effective Java- item 15
这可能是一个更好的
Point
实现。导入 java.io.Serialized;
This could be a better
Point
implementation.import java.io.Serializable;
除了暴露数组(正如 getter 习惯做的那样)并且不是最终的之外,可序列化是“有问题的”。
作为一个非常讨厌的人,当反序列化时,我可以获得对内部数组的另一个引用。对此的明显解决方法是:
仍然存在
points
不是final
的问题,并且在未初始化point
的情况下暴露对象(或更糟,但是有点理论上,部分初始化)。你真正想要的是一个“串行代理”,你可以在互联网上找到它......注意:如果你实现
equals
,你也应该实现hashCode
,可能toString
和可能的Comparable
。Other than exposing the array (as getters are wont to do) and not being
final
, being serialisable is "problematic".As a very nasty man, when deserialising, I can get another reference to the internal array. The obvious fix for this is:
That still leaves the problem of
points
not beingfinal
and exposing the object withoutpoints
initialised (or worse, but a bit thoeretical, partially initialised). What you really want is a "serial proxy", which you can find out about on the internets...Note: If you implement
equals
you should also implementhashCode
, probablytoString
and possibleComparable
.点本身不一定是不可变的,三角形也是不可变的。您只需要进行大量的防御性复制,这样就没有人可以引用存储在三角形中的点对象。
另外,三角形 abc 不应该等于三角形 bca (以及其他 4 个排列)
Point itself doesn't have to be immutable for Triangle to be immutable. You just have to do a lot of defensive copies so that nobody has a reference to the Point objects stored in the Triangle.
Also, shouldn't triangle a-b-c equal triange b-c-a (and 4 other permutations)
具有可变字段的不可变类示例:
A immutable class example with mutable field: