请让我知道为什么以下类是不可变的,正如Java并发实践中所讨论的那样 - 作者Brian Goetz
@Immutable
public class Point {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
由于该类不是最终的,任何类都可以扩展它。但为什么它仍然是不可变的?
答案 0 :(得分:6)
它是不可变的,因为一旦构造了它的实例,就无法以任何方式改变其内部状态。那是因为它没有设置器,x和y是最终的,即你不能改变/改变x或y值。
编辑(请查看该示例):
package test;
public class Test002 {
public static void main(String[] args) {
Point1 p1 = new Point1(4, 10);
consume(p1);
}
public static void consume(Point p){
System.out.println("=============");
System.out.println(p.x);
System.out.println(p.y);
if (p instanceof Point1){
System.out.println("=============");
Point1 p1 = (Point1)p;
p1.setX(5);
p1.setY(11);
System.out.println(p.x);
System.out.println(p.y);
System.out.println(p1.getX());
System.out.println(p1.getY());
}
}
}
class Point {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point1 extends Point {
private int x;
private int y;
public Point1(int x, int y) {
super(x, y);
this.x = x;
this.y = y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
答案 1 :(得分:1)
简单来说 - 否,这个类不是不可变的。但事情比这更复杂。
在他的书中,Brian Goetz对不可变类一无所知。他在谈论不可变对象。在以下情况下称为immutable的对象:
this
参考在施工期间没有逃脱。)确实没有提及final
班级要求。但这是因为我们在运行时讨论给定类型的对象(例如Point
)。对象无法在运行时更改其类型,因此不需要final
类要求。如果我们知道对象状态在运行时没有变化,那么它实际上是不可变的。从这个意义上讲,Point
类型的对象确实是不可变的。
但请注意,在代码3.11(章节 3.4 Immutablility )中,不可变对象作为示例提供,其类定义为final
。
我认为这个问题在不可变对象和不可变类型(类)之间存在一些混淆。
实际上,对于正确多线程的应用程序,所有客户端都应根据共享对象使用策略进行调整。这是您需要不可变类型的地方。因为不管Point
对象的不变性,都可能存在可变性,因此,非线程安全的Point
子类型。如果你有,Liskov替代原则就被打破了。 Point
子类型不应因提供的保证而降级。
对于不可变的类型,它必须遵守以下规则:
this
参考在施工期间没有逃脱; final
; 这与Brian Goetz描述的限制基本相同,但是在编译时而不是运行时的上下文中。如果你完成了这个,那些从那些不可变类型创建的对象将是线程安全的。
所以,编写不可变类,是的,Point
类型应为final
。