[关闭]
@w1024020103 2017-03-27T10:21:11.000000Z 字数 3941 阅读 645

Discussion 6 Immutable Rocks

CS61B


第一题,判断哪些classes是immutable的,我第一次选的是Pebble和MommaRock, 结果全错,说明我完全不懂Immutable:

4.JPG-64.2kB

解析:

5.JPG-71.7kB

第一个Pebble,只需要一个简单的setter就可以改变weight了,肯定是mutable的, 如下:

  1. public class Pebble{
  2. public int weight
  3. public Pebble() {
  4. weight = 1
  5. }
  6. public void setWeight(int weight){
  7. this.weight = weight
  8. }

第三个,仔细阅读一下以下结论:

If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.

就是说,一个final变量是一个对象的引用,而这个变量永远都是指向这个对象,不能够变成指向别的对象,即这个引用无法改变。但是,这个对象使可以改变的。

'final' simply makes the object reference unchangeable. The object it points to is not immutable by doing this. INSTANCE can never refer to another object, but the object it refers to may change state.

例子:

  1. /*Java中很多class都是immutable,像String,Integer等,它们通常用来作为Map的key.
  2. 那么在实现自定义的Immutable的Class的时候,应该注意哪些要点呢?
  3. a)Class 应该定义成final,避免被继承。
  4. b)所有的成员变量应该被定义成final。
  5. c)不要提供可以改变类状态(成员变量)的方法。【get 方法不要把类里的成员变量让外部客服端引用,当需要访问成员变量时,返回成员变量的copy】
  6. d)构造函数不要引用外部可变对象。如果需要引用可以在外部改变值的变量,应该在构造函数里进行defensive copy。*/
  7. //Wrong way to write a constructor:
  8. public final class MyImmutable {
  9. private final int[] myArray;
  10. public MyImmutable(int[] anArray) {
  11. this.myArray = anArray; // wrong
  12. }
  13. public String toString() {
  14. StringBuffer sb = new StringBuffer("Numbers are: ");
  15. for (int i = 0; i < myArray.length; i++) {
  16. sb.append(myArray[i] + " ");
  17. }
  18. return sb.toString();
  19. }
  20. }
  21. // the caller could change the array after calling the
  22. //constructor.
  23. int[] array = {1,2};
  24. MyImmutable myImmutableRef = new MyImmutable(array) ;
  25. System.out.println("Before constructing " + myImmutableRef);
  26. array[1] = 5; // change (i.e. mutate) the element
  27. System.out.println("After constructing " + myImmutableRef);

Out put:
Before constructing Numbers are: 1 2
After constructing Numbers are: 1 5

  1. //Right way to write an immutable class
  2. //Right way is to copy the array before assigning in the constructor.
  3. public final class MyImmutable {
  4. private final int[] myArray;
  5. public MyImmutable(int[] anArray) {
  6. this.myArray = anArray.clone(); // defensive copy
  7. }
  8. public String toString() {
  9. StringBuffer sb = new StringBuffer("Numbers are: ");
  10. for (int i = 0; i < myArray.length; i++) {
  11. sb.append(myArray[i] + " ");
  12. }
  13. return sb.toString();
  14. }
  15. }
  16. // the caller cannot change the array after calling the constructor.
  17. int[] array = {1,2};
  18. MyImmutable myImmutableRef = new MyImmutable(array) ;
  19. System.out.println("Before constructing " + myImmutableRef);
  20. array[1] = 5; // change (i.e. mutate) the element
  21. System.out.println("After constructing " + myImmutableRef);

Out put:
Before constructing Numbers are: 1 2
After constructing Numbers are: 1 2

参考:
Java实现Immutable Class要点
Immutable class
How to Create immutable Class in java?
Java之不可变对象
Immutable Object and Types of Immutable Objects | Java Tutorial

那么回到我们的题目:

  1. public class Rocks {
  2. public final Rock[] rocks;
  3. public Rocks (Rock[] rox) {
  4. rocks = rox;
  5. }
  6. }

如果我们改变rox的内容,那么rocks虽然是final, 也会发生改变:

  1. public class Rocks {
  2. public final Rock[] rocks;
  3. public Rocks (Rock[] rox) {
  4. rocks = rox;
  5. }
  6. Rock a = new Rock(8);
  7. Rock b = new Rock(9);
  8. Rock[] rox = {a,b};
  9. public String toString() {
  10. StringBuffer sb = new StringBuffer("The weight of the rock is: ");
  11. for (int i = 0; i < rocks.length; i++) {
  12. sb.append(rocks[i].weight + " ");
  13. }
  14. return sb.toString();
  15. }
  16. Rocks newRocks = new Rocks(rox) ;
  17. System.out.println("Before constructing The weight of the rock is: " + newRocks);
  18. rox[0] = new Rock(16); // change (i.e. mutate) the element
  19. System.out.println("After constructing The weight of the rock is: " + newRocks);
  20. }

output:
Before constructing The weight of the rock is: 8 9
After constructing The weight of the rock is: 16 9

所以第三个也是mutable的.

6.JPG-102.6kB

第四个跟第三个类似;
第五个要特别注意:

  1. public class PunkRock{
  2. private final Rock[] band;
  3. public PunkRock (Rock yRoad) {
  4. band = {yRoad};
  5. }
  6. public Rock[] myBand() {
  7. return band;
  8. }
  9. }

The problem with the above code is, that the ArrayL can be obtained through myBand() and be manipulated, leading to the state of the object itself to be altered, therefore, not immutable.

比如下面这样:

  1. public class PunkRock{
  2. private final Rock[] band;
  3. public PunkRock (Rock yRoad) {
  4. band = {yRoad};
  5. }
  6. public Rock[] myBand() {
  7. return band;
  8. }
  9. //newPunkRock contains : Rock which weight is 8;
  10. PunkRock newPunkRock = new PunkRock(new Rock(8));
  11. //now the array contains Rock which weight is 9 -- this array is mutable.
  12. newPunkRock.myBand().weight = 9;
  13. }

One way to get around this problem is to return a copy of an array or collection when called from a getter:

  1. public Rock[] myBand() {
  2. // return a copy of the list so the internal state cannot be altered
  3. return new Rock [] {yRoad};
  4. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注