第一个例子:
 public class BetterAddressBook {
private final List names;  public BetterAddressBook(List names) {
this.names = Collections.unmodifiableList(names);
 }
  public List getNames() {
return names;
 }
}
BetterAddressBook book = new BetterAddressBook(Arrays.asList("Landau", "Weinberg", "Hawking"));
book.getNames().add(0, "Montana");
//BetterAddressBook是不可变的。Collections类库中的封装类可以确保一旦设置了names的值,就不能对它再有任何更新。
这个Collections.unmodifiableList到底做了什么事让names不能再被改变呢???第二个例子:
 public class BetterAddressBook {
private final List names;  public BetterAddressBook(List names) {
this.names = Collections.unmodifiableList(names);
 }
  public List getNames() {
return names;
 }
}
List physicists = new ArrayList();
physicists.addAll(Arrays.asList("Landau", "Weinberg", "Hawking"));
BetterAddressBook book = new BetterAddressBook(physicists);
physicists.add("Einstein");
for (String name : book.getNames())
System.out.println(name);
为什么names可以被修改呢??请大家解释一下!!!

解决方案 »

  1.   

    private final List names;
    可以往里面增加数据啊 ,但是 你不能吧 names 重新指向即比如  List list = new ArrayList() ;
    names = list ;//这样是会报错de但是 names.add((object)o) ;
    没有改变 names执行的对象引用 ,即他还是原来的对象
      

  2.   

    private final List names;如果 names是基本类型,它是不能重新赋值的 ,如果是引用类型,即 它的类型 是 类或者数组的话 ,一经赋值,则不能修改 ,而对象的属性当然是可以修改啦 
      

  3.   

    API
    返回指定列表的不可修改视图。此方法允许模块为用户提供对内部列表的“只读”访问。在返回的列表上执行的查询操作将“读完”指定的列表。试图修改返回的列表(不管是直接修改还是通过其迭代器进行修改)将导致抛出 UnsupportedOperationException。
    第一个报错是因为,返回传入参数列表的一个不可以修改的视图。所以直接修改names报错。
    第二个是对physicists修改,physicists是源数据,所以可以修改。大家都知道视图是根据源数据变化的。如果源数据更新,视图也会更新。
      

  4.   

    那为什么这样确实可以的呢?
    public class Book {
    private String title;
    public String getTitle() {
    return title;
    }
    public void setTitle(String title) {
    this.title = title;
    }
    }public class Library {
    private final List books; public Library(List books) {
    this.books = Collections.unmodifiableList(new ArrayList(books));
    }
    public List getBooks() {
    return books;
    }
    }
    Book book = new Book();
    book.setTitle("Dependency Injection")
    Library library = new Library(Arrays.asList(book));
    library.getBooks().get(0).setTitle("The Tempest"); //mutates Library
      

  5.   

    虽然返回的视图是不可变的,虽然this.books = Collections.unmodifiableList(new ArrayList(books))返回的视图虽然是不可变了,但是book的成员变量title是可变的。所以:library.getBooks().get(0).setTitle("The Tempest"); 也是可变的。。所以一个应该说:
    每一个被依赖的对象也必须是不可变的
      

  6.   

    看了源码,UnmodifiableList也只是把一个final List赋给他,感觉楼主用这个有点多余了。    static class UnmodifiableList<E> extends UnmodifiableCollection<E>
                          implements List<E> {
            static final long serialVersionUID = -283967356065247728L;
        final List<? extends E> list;    UnmodifiableList(List<? extends E> list) {//看构造器
            super(list);//这个父类只是判断 传进来的list是否为空
            this.list = list;
        }    public boolean equals(Object o) {return o == this || list.equals(o);}
        public int hashCode()       {return list.hashCode();}    public E get(int index) {return list.get(index);}
        public E set(int index, E element) {
            throw new UnsupportedOperationException();
            }
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
            }
        public E remove(int index) {
            throw new UnsupportedOperationException();
            }
        public int indexOf(Object o)            {return list.indexOf(o);}
        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
        public boolean addAll(int index, Collection<? extends E> c) {
            throw new UnsupportedOperationException();
            }
        public ListIterator<E> listIterator()   {return listIterator(0);}    public ListIterator<E> listIterator(final int index) {
            return new ListIterator<E>() {
            ListIterator<? extends E> i = list.listIterator(index);        public boolean hasNext()     {return i.hasNext();}
            public E next()          {return i.next();}
            public boolean hasPrevious() {return i.hasPrevious();}
            public E previous()      {return i.previous();}
            public int nextIndex()       {return i.nextIndex();}
            public int previousIndex()   {return i.previousIndex();}        public void remove() {
                throw new UnsupportedOperationException();
                    }
            public void set(E e) {
                throw new UnsupportedOperationException();
                    }
            public void add(E e) {
                throw new UnsupportedOperationException();
                    }
            };
        }
      

  7.   

    使用final修饰的对象 他的指向的地址不能改变 但是里面的内容是可以改变的
      

  8.   

    非也,我是看到这篇文章的http://www.infoq.com/cn/articles/dhanji-prasanna-concurrency
    感觉对并发有一定的启示!
      

  9.   

    里面的内容一定可变,不太严谨吧,那外一它里面的内容也是final的话呢?呵呵呵....
      

  10.   

    虽然UnmodifiableList(List<? extends E> list) {//看构造器
            super(list);//这个父类只是判断 传进来的list是否为空
            this.list = list;
        }
    把外面传进来的list赋值给了不可变的final List<? extends E> list;
    这时确保了fianl list里面的对象不可变,但是不能确保对象里面的内容不可变呀!
      

  11.   

    源码中list跟util的list不一样,方法被他重写了,所以还是不能省啊,终于看明白了一点。UnmodifiableList实现了list接口,所以UnmodifiableList也是个List。
      

  12.   

    源码中list跟util的list不一样,方法被他重写了,所以还是不能省啊...
    什么不能省呢?请详说!
      

  13.   

    UnmodifiableList 重写了list的add,set,remove方法
    所以让 List names不能修改,应该方法被改了,执行下面三个方法就报异常。所以说names为什么不能添加,删除,还有set方法。
    我开始以为UnmodifiableList 只是把系统的util包下的list 赋给names,导致理解错误,以为那一步是多余的,既然自己设置了final,为什么还要final list 赋给他,其实他是在list里面做了手脚。public E set(int index, E element) {
            throw new UnsupportedOperationException();
            }
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
            }
        public E remove(int index) {
            throw new UnsupportedOperationException();
            }
      

  14.   

    你说的是这样的!!!!
    但是我们讨论的重点不是在那,而是:
    public class Book {
    private String title;
    public String getTitle() {
    return title;
    }
    public void setTitle(String title) {
    this.title = title;
    }
    }public class Library {
    private final List books;public Library(List books) {
    this.books = Collections.unmodifiableList(new ArrayList(books));
    }
    public List getBooks() {
    return books;
    }
    }
    Book book = new Book();
    book.setTitle("Dependency Injection")
    Library library = new Library(Arrays.asList(book));
    library.getBooks().get(0).setTitle("The Tempest"); //mutates Library
    既然UnmodifiableList重写了util.list,把我们传入的list修改成不能修改的视图了。但是后面
    library.getBooks().get(0).setTitle("The Tempest"); //mutates Library却可以重新取得不可修改的视图重新修改里面的内容,原因是视图里面的内容是可以修改的!不知我理解是否有误,请指出。。
      

  15.   

    指教不敢当,共同学习。api是那么解释的,不过也是别人翻译过的,可能不准确。一般我们要修改list里面的内容要用到set,remove,add方法,现在该list不提供这些修改方法,只提供get方法,但是还有一种是可能更改的就是list里面放的是是一个对象的引用,更改对像属性,理论是list引用的对象的地址没有变,变的是对象里面属性的引用的更改。你的理解基本是正确的,如果是List<Integer>,那么能不能被修改呢?
      

  16.   

    如果是站在上面那个例子的话是可以修改的,因为Book是可变的类
    但是如果是脱离那个例子的话Integer本身跟String是不可修改的类了,所以就不能被修改了!
      

  17.   

    public class BetterAddressBook {
    private final List names; public BetterAddressBook(List names) {

    this.names=names;
    }
    public  List getNames() {
    return names;
    }
    public static void main(String s[]){
      BetterAddressBook book = new BetterAddressBook(Arrays.asList("Landau", "Weinberg", "Hawking"));
      
      List list1=book.getNames();
      
      list1.add("asf");
     
      System.out.print("over");
     //如果
      
      }
    }路人看了也有个问题!为什么这个时候   不是返回不可变的视图了,但是依然不可以添加呢??
      

  18.   

    同意八楼
    final修饰的内存地址不可改变   但是他的值是可以改变的
      

  19.   

    实际上这样写都出错了:
    import java.util.*;
    public class test{
            private static List names = Arrays.asList("dfs","sdfs","sad");
            public static void main(String[] args){
                    names.add("adf");
            }
    }那么原因有可能就在于Arrays.asList这里了,查看API,发现
    public static <T> List<T> asList(T... a)    返回一个受指定数组支持的固定大小的列表。(对返回列表的更改会“直接写”到数组。)是不是设定了列表的大小了,不能再修改了所以应该问题是在Arrays.asList这里。。
    所以
    physicists.addAll(Arrays.asList("Landau", "Weinberg", "Hawking"));
    BetterAddressBook book = new BetterAddressBook(physicists);
    physicists.add("Einstein");
    再用一个List包这一个不可修改的list,然后修改外面那个List,不知理解有误,请指出!
      

  20.   

    Arrays.asList("Landau", "Weinberg", "Hawking")
    这个还回是一个ArrayList,不过不是java.util.ArrayList,是Arrays的一个内部内ArrayList,里面木有add方法,而且数据是存在一个final的数组中,我们知道ArrayList的存储本来就是数组存储,而且该数组可以改变引用。但是这里是final,不能改变引用,所以数组长度就得到了限制。
    而且该ArrayList也没提供add,remove方法。只提供set,get方法。所以你那段代码会报错。UnsupportedOperationException