集合框架

集合框架

简介

集合的由来
  数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少

定义:

  java提供了一种可以存数一组数据的数据结构,其提供了丰富的方法,在实际开发中往往比数组使用的广泛。这种数据结构成为集合:Collection。

  Collection是一个接口,其定义了集合的相关功能方法。

数组和集合的区别

  • 区别1 :
    • 数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值
    • 集合只能存储引用数据类型(对象)集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象
  • 区别2:
    • 数组长度是固定的,不能自动增长
    • 集合的长度的是可变的,可以根据元素的增加而增长

数组和集合什么时候用

  • 如果元素个数是固定的推荐用数组
  • 如果元素个数不是固定的推荐用集合

集合框架图

这里写图片描述

Collection (集合的最大接口)继承关系

  ——List 可以存放重复的内容
  ——Set  不能存放重复的内容,所以的重复内容靠hashCode()和equals()两个方法区分
  ——Queue  队列接口
  ——SortedSet  可以对集合中的数据进行排序

关于list,set,map的我的博客链接java集合(list,set,map)

Collection定义了集合框架的共性功能。

Collection接口常见的方法

(1)单元素添加、删除操作。

方法 描述
boolean add(Object o) 将对象添加给集合。
boolean remove(Object o) 如果集合中有与o相匹配的对象,则删除对象o。

(2)查询操作。

方法 描述
int size() 返回当前集合中元素的数量。
boolean isEmpty() 判断结合中是否有任何元素。
boolean contains(Object o) 查找集合中是否含有元素o。
Iterator iterator() 返回一个迭代器,用来访问集合中的各个元素。

(3)组操作:作用于元素或整个结合。

方法 描述
boolean containsAll(Collection c) 查找集合中是否含有集合c中的所有元素。
boolean addAll(Collectiion c) 将集合c中的所有元素添加给该集合。
void clear() 删除集合中所有的元素。
void removeAll(Collection c) 从集合中删除集合c中的所有元素。
void retainAll(Collection c) 从集合中删除集合c中不包含的元素。

(4)Collection转换为Object数组。

方法 描述
Object[] toArray() 返回一个内含集合所有元素的数组。
Object[] toArray(Object[] a) 返回一个内含集合所有元素的数组。运行期返回的数组和参数a的类型相同。

注:集合中存储的都是对象的引用(地址)

Iterator 迭代器

Collection提供了一个遍历集合的通用方式,迭代器(Iterator)。
获取迭代器的方式是使用Collection定义的方法:

Iterator iterator():迭代器Iterator是一个接口,集合在覆盖Collection的iterator()方法时提供了迭代器的实现。Iterator提供了统一的遍历集合元素的方式。

迭代器原理

迭代器原理:迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么就需要在每一个类中定义hasNext()和next()方法,这样做是可以的,但是会让整个集合体系过于臃肿,迭代器是将这样的方法向上抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做的好处有二:
  第一规定了整个集合体系的遍历方式都是hasNext()和next()方法;
  第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可

hasNext与next方法

迭代器用于遍历集合的两个主要方法:

  • boolean hasNext():判断集合是否还有元素可以遍历。

  • E next():返回迭代的下一个元素

    遍历集合应遵循“先问后取”的方式,也就是说,应当在确定hasNext()方法的返回值为true的情况下再通过next()方法取元素。

    由此可以看出,使用迭代器遍历集合是通过boolean值驱动的,所以它更适合使用while循环来遍历。

	Collection<String> c = new HashSet<String>();
	c.add("java");        
	c.add("cpp");        
	c.add("php");
	c.add("c#");        
	c.add("objective-c");
	Iterator<String> it = c.iterator();
	while (it.hasNext()) {
		String str = it.next();
		System.out.println(str);
	} 

remove方法

  迭代器还提供了一个方法:

  void remove()该方法用于删除迭代器当次从集合中获取的元素。若我们在迭代过程中想删除集合元素时,我们就需要通过该方法来进行。这里需要注意,在使用迭代器遍历集合时是不能通过集合自身提供的remove方法删除元素的,否则迭代器在迭代时会抛出异常。

	Collection<String> c = new HashSet<String>();
	c.add("java");        
	c.add("cpp");        
	c.add("php");
	c.add("c#");        
	c.add("objective-c"); 
	System.out.println(c); // [cpp, php, c#, java, objective-c] 
	Iterator<String> it = c.iterator();
	while (it.hasNext()) {
	    String str = it.next();
	    if (str.indexOf("c") != -1) {
	        it.remove();
	    } 
	} 
	System.out.println(c); // [php, java]  

增强for循环

Java5.0之后推出了一个新的特性,增强for循环,也称为新循环。该循环不通用于传统循环的工作,其只用于便利集合或数组。 语法:

	for(元素类型 e : 集合或数组){
	    循环体 
	}

  新循环并非新的语法,而是在编译过程中,编译器会将新循环转换为迭代器模式。所以新循环本质上是迭代器。
例如:

	Collection<String> c = new HashSet<String>();
	c.add("java");
	c.add("cpp");
	c.add("php");
	c.add("c#");
	c.add("objective-c");
	for (String str : c) {
	    System.out.print(str.toUpperCase() + " ");
	} 
	// CPP PHP C# JAVA OBJECTIVE-C

泛型机制

泛型在集合中的应用

  泛型是Java SE 5.0引入的特性,泛型的本质是参数化类型。在类、接口和方法的定义过程中,所操作的数据类型被传入的参数指定。

  Java泛型机制广泛的应用在集合框架中。所有的集合类型都带有泛型参数,这样在创建集合时可以指定放入集合中的对象类型。Java编译器可以据此进行类型检查,这样可以减少代码在运行时出现错误的可能性。

我们来举个例子,比如ArrayList,其在定义时是这样的:

	public class ArrayList<E> {
	    … … …                
	    public boolean add(E e) {…};
	    public E get(int index) {…};
	} 

由此我们可以看出,再声明ArrayList时,类名的右侧有一个。"<>"表示泛型,而其中可以使用数字字母下划线(数字不能的第一个字符)来表示泛型的名字。(通常我们使用一个大写字母来表示,当然这个不是规定。)这时,在类中声明的方法的参数,返回值类型可以被定义为泛型。这样在创建对象时可以将类型作为参数传递,此时,类定义所有的E将被替换成传入的参数。
例如:

	ArrayList<String> list = new ArrayList<String>();//泛型E在这里被指定为String类型
	list.add("One");//那么add方法的参数就被替换为String类型
	list.add(100);//这里就会出现编译错误,因为这里的参数应为String类型。

集合工具类

 Collections:集合框架的工具类。里面定义的都是静态方法。

  Collections和Collection有什么区别?
    Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
      它有两个常用的子接口,
      List:对元素都有定义索引。有序的。可以重复元素。
      Set:不可以重复元素。无序。

    Collections是集合框架中的一个工具类。该类中的方法都是静态的。
      提供的方法中有可以对list集合进行排序,二分查找等方法。
      通常常用的集合都是线程不安全的。因为要提高效率。
      如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

常用的方法

排序操作(主要针对List接口相关)

方法 描述
reverse(List list) 反转指定List集合中元素的顺序
shuffle(List list) 对List中的元素进行随机排序(洗牌)
sort(List list) 对List里的元素根据自然升序排序
sort(List list, Comparator c) 自定义比较器进行排序
swap(List list, int i, int j) 将指定List集合中i处元素和j出元素进行交换
rotate(List list, int distance) 将所有元素向右移位指定长度,如果distance等于size那么结果不变

例子

	public void testSort() {
        System.out.println("原始顺序:" + list);
        
        Collections.reverse(list);
        System.out.println("reverse后顺序:" + list);

        Collections.shuffle(list);
        System.out.println("shuffle后顺序:" + list);
        
        Collections.swap(list, 1, 3);
        System.out.println("swap后顺序:" + list);

        Collections.sort(list);
        System.out.println("sort后顺序:" + list);

        Collections.rotate(list, 1);
        System.out.println("rotate后顺序:" + list);
    }

输出

原始顺序:[b张三, d孙六, a李四, e钱七, c赵五]
reverse后顺序:[c赵五, e钱七, a李四, d孙六, b张三]
shuffle后顺序:[b张三, c赵五, d孙六, e钱七, a李四]
swap后顺序:[b张三, e钱七, d孙六, c赵五, a李四]
sort后顺序:[a李四, b张三, c赵五, d孙六, e钱七]
rotate后顺序:[e钱七, a李四, b张三, c赵五, d孙六]

查找和替换(主要针对Collection接口相关)

方法 描述
binarySearch(List list, Object key) 使用二分搜索法,以获得指定对象在List中的索引,前提是集合已经排序
max(Collection coll) 返回最大元素
max(Collection coll, Comparator comp) 根据自定义比较器,返回最大元素
min(Collection coll) 返回最小元素
min(Collection coll, Comparator comp) 根据自定义比较器,返回最小元素
fill(List list, Object obj) 使用指定对象填充
frequency(Collection Object o) 返回指定集合中指定对象出现的次数
replaceAll(List list, Object old, Object new) 替换

例子

		public void testSearch() {
        System.out.println("给定的list:" + list);
        System.out.println("max:" + Collections.max(list));
        System.out.println("min:" + Collections.min(list));
        System.out.println("frequency:" + Collections.frequency(list, "a李四"));
        Collections.replaceAll(list, "a李四", "aa李四");
        System.out.println("replaceAll之后:" + list);
        
        // 如果binarySearch的对象没有排序的话,搜索结果是不确定的
        System.out.println("binarySearch在sort之前:" + Collections.binarySearch(list, "c赵五"));
        Collections.sort(list);
        // sort之后,结果出来了
        System.out.println("binarySearch在sort之后:" + Collections.binarySearch(list, "c赵五"));

        Collections.fill(list, "A");
        System.out.println("fill:" + list);
    }

输出

给定的list:[b张三, d孙六, a李四, e钱七, c赵五]
max:e钱七
min:a李四
frequency:1
replaceAll之后:[b张三, d孙六, aa李四, e钱七, c赵五]
binarySearch在sort之前:-4
binarySearch在sort之后:2
fill:[A, A, A, A, A]

同步控制

  Collections工具类中提供了多个synchronizedXxx方法,该方法返回指定集合对象对应的同步对象,从而解决多线程并发访问集合时线程的安全问题。HashSet、ArrayList、HashMap都是线程不安全的,如果需要考虑同步,则使用这些方法。这些方法主要有:synchronizedSet、synchronizedSortedSet、synchronizedList、synchronizedMap、synchronizedSortedMap。

  特别需要指出的是,在使用迭代方法遍历集合时需要手工同步返回的集合。

Map m = Collections.synchronizedMap(new HashMap());
      ...
  Set s = m.keySet();  // Needn't be in synchronized block
      ...
  synchronized (m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
 	}

总结

 List:add/remove/get/set。

    1,ArrayList:其实就是数组,容量一大,频繁增删就是噩梦,适合随机查找;

    2,LinkedList:增加了push/[pop|remove|pull],其实都是removeFirst;

    3,Vector:历史遗留产物,同步版的ArrayList,代码和ArrayList太像;

    4,Stack:继承自Vector。Java里其实没有纯粹的Stack,可以自己实现,用组合的方式,封装一下LinkedList即可;

    5,Queue:本来是单独的一类,不过在SUN的JDK里就是用LinkedList来提供这个功能的,主要方法是offer/pull/peek,因此归到这里呢。

  Set:add/remove。可以用迭代器或者转换成list。

    1,HashSet:内部采用HashMap实现的;

    2,LinkedHashSet:采用LinkedHashMap实现;

    3,TreeSet:TreeMap。

  Map:put/get/remove。

    1,HashMap/HashTable:散列表,和ArrayList一样采用数组实现,超过初始容量会对性能有损耗;

    2,LinkedHashMap:继承自HashMap,但通过重写嵌套类HashMap.Entry实现了链表结构,同样有容量的问题;

    3,Properties:是继承的HashTable。

    顺便说一下Arrays.asList,这个方法的实现依赖一个嵌套类,这个嵌套类也叫ArrayList!

posted @ 2017-09-09 15:17  杨洛平  阅读(236)  评论(0编辑  收藏  举报