在Brian Goetz的Java Concurrency in Practice中,为什么point class是Immutable,由DelegatingVehicleTracker使用

时间:2015-10-12 12:53:09

标签: java concurrency immutability

请让我知道为什么以下类是不可变的,正如Java并发实践中所讨论的那样 - 作者Brian Goetz

@Immutable
public class Point {
    public final int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

由于该类不是最终的,任何类都可以扩展它。但为什么它仍然是不可变的?

2 个答案:

答案 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