重温《JAVA编程思想》----2017.1.14 集合类/容器类(未完待续)

1.Java SE5之前,有1个很大的问题就是编译器允许向容器中插入不正确的类型,ArrayList里面存放的是Object,里面可以存放Apple,也可以存放Orange。并且在取出元素的时候,必须强制转型,因为你取出来的都是Object类型。错误只能在运行时发现

 

 

2.Java SE5之后,我们可以使用泛型进行预定义,如果插入的类型不对,编译器就能发现。

并且在取出元素的时候,不再需要“强制转型”,因为编译器知道正确的类型信息

 

 

3.ArrayList<Apple>,我们可以向里面放入Apple子类

 

 

4.一般我们都会进行向上转型的方式生成1个具体集合类的对象(为了功能),例如:

List<Apple> list = new LinkedList<Apple>();

  但是,这种方式并非总能够奏效,因为某些具体类拥有额外的功能,比如LinkedListList没有的方法,TreeMap也具有Map接口中未包含的方法。如果你需要使用这些方法,就不能将他们向上转型为更通用的接口

 

 

5.Collection概括了序列的概念--------------一种存放一组对象的方式。(注意,存放的是对象,当你在里面放入基本类型的时候,会进行打包机制,并且用泛型进行预定义的时候,也要使用对象Interger)

 

 

6.添加一组元素的方式:

关键方法:a.)Collection.addAll(Collection collection);

List<Apple> list = new ArrayList<Apple>();

List<Apple> list2= new ArrayList<Apple>();

list2.add(new Apple());

list.addAll(list2);

   集合类的addAll()只能接受另一个Collection

   b.)Collections.addAll();

 

public static <T> boolean addAll(Collection<? super T> c,T... elements)

 

它接受2个参数,第一个参数必须是一个Collection,第二个参数是可变参数,所以第二个参数可以一个数组或者是逗号分割的列表。

 

b.1)加可变列表

Collections.addAll(list, new Apple(),new Apple(),new Apple());

 

b.2)加数组

Apple[] array = new Apple[]{ new Apple(),new Apple(),new Apple()};

      Collections.addAll(list,array);

 

 

 

   两种方式的总结:  

Collections.addAll()运行的更快。并且接受参数更多,有数组和可变参数。

 

 

 

 

7.Arrays.asList(数组或者逗号分割的可变列表):

它接受的参数是数组或是逗号分隔的可变列表,可以转换成List,但是需要注意的是:他的底层实现用的是数组,因此不能调节尺寸,如果你试图add()或者delete()方法在这种列表中添加或删除元素,就有可能引发去改变数组尺寸的尝试,会报错。

       Arrays.asList()方法的限制是他对所产生的list的类型做出了最理想的假设,例如:

class A{}

 

class Aa extends A{}

class Aaa extends A{}

 

class B extends Aa{}

      class C extends Aa{}

List<A> list = Arrays.asList(new B(),new C());

List<A> list1 = Arrays.asList(new B(),new C());

     list.addAll(1, list1);

 

 

Exception in thread "main" java.lang.UnsupportedOperationException

at java.util.AbstractList.add(Unknown Source)

at java.util.AbstractList.addAll(Unknown Source)

at Test.main(Test.java:11)

 

因为这样的时候list中只有Aa类型,它会创建的是List<Aa>而不是List<A>

      

 

 

 8.容器的打印:

CollectionMap类都得到了良好的封装,直接打印就可以得到结果。

不同的是Collectionlist,Set,Queue等)是[x,x,x,x,x,x,x]的形式;

Map{key1=value,key2=value2,key3=value3}的形式。

 

 

 9.对比:

HashSet最快获取元素。

TreeSet比较结果的升序。

LinkedHashSet被添加的顺序。

 

HashMap最快查找技术。

TreeMap比较结果的升序。

LinkedHashMap被添加的顺序。

 

 

 

 

 

 

 

10.关于List:

有两种List:ArrayListLinkedList

ArrayList随机访问比较快,中间的插入和删除比较慢,如果你有很多的插入或者删除操作,避免用ArrayList

LinkedList它通过较低的代价在List中间进行插入和删除操作,但是它不擅长随机访问,如果你有很多随机访问操作,避免用LinkedList并且它的特性集比ArrayList更大。

 

 

方法总结:

 

List.add();

List.add(int index,T t);--------------中间插入

List,addAll(AnotherList);-------------在末端插入另一个list

List.addAll(int index,AnotherList);----------------在中间插入另一个list

List.indexOf(list中某个Object引用,注意是引用,如果你只是新new了个对象,新对象和list中的对象不是equals的,所以会返回falseString类是内容完全相同的时候就equals()返回true)

List.subList(int startIndex,int endIndex);--------------获得子列表

List.contains(某对象引用);

List.cotainsAll(List anotherList);

List.retainAll(AnotherList);--------------------交集

List.remove(引用);

List.remove(int index);-------------通过索引移除

List.removeAll(AnotherList);

List.set(int index,T t);-------------其实用replace描述更准确,是替换元素。

List.isEmpty();

List.clear();

List.toArray();返回的是Object[]数组。

List.toArray(T[] t);返回指定数组类型。

Collections.sort(List list);--------------排序。

Collections.shuffle();-----------乱序。

 

 

 

11.容器生成新容器:

List<A> list = Arrays.asList(new B(), new Aaa());

LinkedList<A> link = new LinkedList<A>(list);

Collection<T> collection = new Collection<T>(AnotherCollection);

这里的Collection可以是ListQueueSet等,也就是可以通过容器生成新的容器。

 

 

 

 

12.迭代器Iterator:

 

a.)Iterator是一种轻量级对象,创建它的代价很小

b.)Iterator有一些限制,比如只能单向移动。

c.)Collection.iterator()返回1Iterator

         hasNext();

         next();

  remove();(它会移除由next()产生的最后一个元素,所以remove()next()之后出现,并且一起出现)

 

 

d.)迭代器可以不管你Collection的类别,无论你是ListSetQueue,如果你的程序代码需要将一份代码同时应用于多种Collection情况,那么你应该做的是用Iterator来实现你的代码。

 

 

 

一句话:Iterator统一了对容器的访问方式。

 

public void play(Iterator<Apple> it){

 

Apple apple = it.next();

Apple.xxxxx(某某方法)

}

 

play(new HashSet<Apple>().Iterator);

play(new TreeSet<Apple>().Iterator);

 

play(new List<Apple>().Iterator);

play(new LinkedList<Apple>().Iterator);

 

 

 

 

e.)ListIterator:

它是一个更强大的Iterator的子类型,

(1)它只能作用于各种List类型的访问。

(2)它可以双向移动。

 

List<A> list = Arrays.asList(new B(), new Aaa());

ListIterator<A> listIterator1=list.listIterator();

ListIterator<A> listIterator2=list.listIterator(2);

System.out.println(listIterator2.hasNext());

listIterator1.next();

listIterator1.previous();

listIterator1.set(new A());

listIterator1.hasPrevious();

 

List.listIterator(n)索引一开始就指向n;

set(T a)方法替换它最后访问的元素。

previous();向前移动

hasPrevious();

 

 

 

 

 

 

 

 

13.LinkedList:

它在中间插入删除操作更优秀,并且添加了可以使其用作栈、队列、 或双端队列的方法。

getFirst();

element();

peek();

上面这3个方法都是返回list头元素,但是当list为空的时候,peek返回nullelement()peek()返回NoSuchElementElementException异常。

removeLast();

 

removeFirst();

remove();

poll();

上面这3个方法都是移除并返回列表的头,列表为空的时候,poll返回nullremoveFirst()remove()返回NoSuchElementElementException异常。

 

addFirst();

add();

offer();

addLast();

 

由此可以看出,LinkedList在插入删除操作更擅长。

 

 

 

 

14.Stack:

class Stack<T>{

private LinkedList<T> storage = new LinkedList<T>();

public void push(T t){

storage.addFirst(t);

}

public T peek(){

return storage.getFirst();

}

public T pop(){

return storage.removeFirst();

}

public boolean empty(){

return storage.isEmpty();

}

public String toString(){

return storage.toString();

}

}

 

 

上述代码才应该是Stack的具体实现,即通过LinkedList实现的。

 

 

 

注意:

Java1.0的时候,设计者没有通过上述组合的方式来形成Stack(组合的好处是可以选定“方法集”,即不需要的方法我们就不声明),java.util.Stack它却是愚蠢继承了Vector类,使得它拥有全部的Vector方法,再附加自己的方法,这样的设计是冗余且幼稚的。

 

 

结论:

当你想要使用Stack的时候,用LinkedList来实现功能。

 

 

 

15.Set:

set也是一个CollectionCollection通用方法它都拥有。

TreeSet将元素存储在-黑树数据结构中。

HashSet使用的是散列函数(以后再探讨)。

Set最重要的功能就是查找和判断归属性。

 

 

 

16.Map

猜你喜欢

转载自blog.csdn.net/mypromise_tfs/article/details/54430353