java集合(上)_Collection集合

本文总结java单列集合,单列集合顶层接口是Collection。刚接触java集合时知道java集合可以装载任意类型的对象,是一种功能强大的容器,逐渐学习后发现java集合框架层次明确,每个容器都有自己的特殊用途,学习时要掌握并理清集合的共性方法和每种容器的特殊方法。

集合
集合用于存储对象,长度可变,存储的对象元素类型可不一致。集合只能存储对象,不能存储基本数据类型。
java集合框架有2个顶层接口,Collection是单列集合的顶层接口,Map是双列集合的顶层接口。


图解:
1. 虚线框内的都是接口,实线框内的是类。
2. Map指向Collection的虚线代表Map双列集合可以通过keySet()和entrySet()方法获得键值和映射关系的单列集合。
3. Collection指向Iterator接口的虚线表示,Collection子类对象都可以通过iterator()方法获取迭代器对象。
4. 集合框架有2个常用工具类,Collections和Arrays,里面封装了若干实用的静态方法。
5. 集合体系是存储对象的容器,之所以会出现图中这么多的容器,是因为每一个容器对数据的存储方式(也就是数据结构)都有不同。

Collection类中集合共性方法

1. 添加元素
void add(Object obj), 参数类型是Object, 以便于接收任意类型。
boolean addAll(Collection <? extends E> c), 将集合对象c整个添加到调用此方法的Collection对象中,如果调用此方法的Collection对象存储的元素类型是E,那c可以是存储E的任意子类对象的集合;如果调用此方法后,集合内容发生变更,返回true.
集合中存储的是对象的引用地址。

2. 获取集合长度
int size()

3.  打印集合
System.out.println(c).

4. 删除元素
boolean remove(Object obj), 如果删除了一个元素,返回true.
boolean removeAll(Collection<?> c), 集合中删除指定集合c中的所有元素,如果调用此方法后集合内容变更,返回true.
boolean retain(Collection<?> c),  保留此集合与指定集合c的交集,无交集时,此集合变为空,如果调用方法后此集合内容发生改变,返回true.

5. 清空集合
void clear()

6. 判断元素
boolean contains(Object obj), 判断集合中是否包含obj对象
boolean isEmpty(), 判断集合是否为空.

7. 遍历集合
java将集合元素的共性取出方式(都是先判断再取出),抽象为Iterator接口。
每一个容器的数据结构不同,取出动作的细节也不一样,所以将取出方式定义在集合内部,这样可以直接访问集合内部的元素。
每个集合子类中都有一个实现Iterator接口的内部类(非匿名),集合对外提供iterator()方法,iterator()方法返回一个此内部类的对象,也就是此集合的迭代器。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo1 {

	private static ArrayList al2;
	public static void main(String[] args) {
		baseMethod();
	}
	public static void baseMethod(){
		Collection al=new ArrayList();
		//添加元素
		al.add("day01");
		al.add("day02");
		al.add("day03");
		al.add("day04");
		//打印集合
		sop("原集合:"+al);
		//打印集合长度
		sop("原集合长度:"+al.size());
		//删除元素
		sop("是否删除了day01元素:"+al.remove("day01"));//删除了"day01",返回true
		sop("是否删除了day111元素:"+al.remove("day111"));//集合中没有此元素,没法删除,原集合不变,返回false
		//清空集合
		//al.clear();
		//判断元素
		sop("是否存在day02元素"+al.contains("day01"));
		sop("集合是否为空:"+al.isEmpty());
		
		//获取2个集合的交集元素
		al2 = new ArrayList();
		al2.add("day02");
		al2.add("day03");
		al2.add("day05");
		al2.add("day06");
		sop("原集合与a12是否有交集:"+al.retainAll(al2));
		sop("原集合与a12的交集元素:"+al);
		
		//集合元素迭代
		for(Iterator it=al.iterator();it.hasNext();){
			sop(it.next());
		}
	}
	public static void sop(Object obj){
		System.out.println(obj);
	}
}
运行结果:
原集合:[day01, day02, day03, day04]
原集合长度:4
是否删除了day01元素:true
是否删除了day111元素:false
是否存在day02元素false
集合是否为空:false
原集合与a12是否有交集:true
取交集后,al集合变为:[day02, day03]
day02
day03
注:jdk1.5版本起,引入了泛型机制,编译上述程序时会报“ 注意:CollectionDemo1.java使用了未经检查或不安全的操作。注意:要了解详细信息,请使得-xlint:unchecked重新编译。”,是因为上面程序中使用ArrayList集合时未指定泛型,存在安全隐患

Collection接口有2个子接口:List, Set.
List: 元素是有序的,元素可以重复,该集合体系有索引。
Set; 元素无序,元素不可重复。

List集合
与Collection接口相比,凡是可以操作角标的方法都是该体系的特有的方法,元素角标从0开始。

1. 增加元素
boolean add(index,element),  boolean addAll(index,collection)

2. 删除元素
boolean remove(index)

3. 修改
E set(int index, E e), 用指定元素替换列表中指定位置的元素,返回替换前的元素。

4. 查询
E get(int index)
List<E> subList(int from, int to)

5. 迭代器
Iterator iterator()和ListIterator listIterator():
ListIteratror对象是List集合特有的迭代器,只能通过listIterator()方法获取,List集合中也还有iterator()方法,但调用此方法返回的是Iterator接口的直接内部子类对象。
Iterator迭代器的局限性:在迭代时,不可以通过集合对象的方法操作集合中的元素,因为迭代器与对象本身同时操作集合时会发生异常CurrentModificatonException, 所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断、取出和删除。
ListIterator解决了这个问题,ListIterator是Iterator的子接口,该迭代器中可以对元素进行添加、修改。
ListIterator迭代器中还可以逆向遍历集合元素,使用方法hasPrevious()和previous()方法。

List有3个子类:ArrayList, LinkedList, Vector

ArrayList: 从jdk 1.2版本开始的,底层数据结构是数组,非线程同步的,特点是查询速度快,但是增删稍慢(元素多时影响大)。默认长度是10,超过时,先copy原数组,再创建新数组,50%扩展空间。

LinkedList: 从jdk1.2版本开始的,底层使用的是链表数据结构,非线程同步,特点是增删速度快,查询稍慢。
LinkedList的特有方法
addFirst(), addLast(), 在链表头或尾添加元素;
getFirst(), getLast(), 获取元素,但不删除元素;
removeFirst(), removeLast(), 获取元素,并删除元素,可用来遍历删链表;
---上面的get和remove方法,如果集合中没有元素会抛出NoSuchElementException异常
offerFirst(), offerLast(), 在表头或表尾插入元素;
peekFirst(), peekLast(), 获取表头或表尾元素,但不删除元素;
pollFirst(), pollLast(), 获取表头或表尾元素,并删除元素。
---上面几个是jdk1.6版本才有的方法,如果集合中没有元素不会抛出异常,返回null.

Vector: 从jdk1.0版本开始的,先与集合框架存在, 底层是数组结构,线程同步,与ArrayList功能重复,被ArrayList替代了,需要判断锁,效率慢。默认长度是10,超过时100%扩展空间。 

Set集合
元素是无序的,存入和取出的顺序不一定一致,元素不可以重复。

Set集合常见子类-HashSet
HashSet底层数据结构是Hash表,非线程同步。
往HashSet集合中存储元素时,是先调用元素的hashCode()判断哈希值大小,哈希值一样时,再调用元素的equals()方法判断元素内容。如果2个对象哈希值一样,内容不一样,会在一连续地址值中顺沿存放2个元素。如果哈希值不一样,不会再调用equals()方法。
hashCode()是Object类的方法,返回对象的哈希值,可被复写;Object类对象的哈希值就是地址值,子类复写后就不一定是地址值了。

HashSet具体存储原理-哈希表
     想查找一个集合中是否包含有某个对象,通常想到的是逐一取出集合中每个元素与要查找的元素使用equals()方法进行比较, 如果集合中有一万个元素,这种方法效率很低。
     哈希算法可以大大提高在集合中查找元素的效率。这种算法采用对某个数字n进行取余的方式将元素哈希值进行划分,将集合分成若干存储区域,根据一个对象的哈希值就可以确定该对象应该存储在哪个区域,确定存储区域后,只需取出该区域的各个元素与要查找的对象使用equals方法进行比较即可,不用遍历集合中所有元素,从而提高了效率。

对象要存储在HashSet集合中,最好是复写hashCode()方法和equals()方法。HashSet集合的方法contains()和remove(),执行原理也是依赖这2个方法(List集合只依赖equals()方法)。
注:当一个对象被存储进HashSet集合以后,就不能修改这个对象中那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了,这样,使用contains方法在HashSet中检索该对象时,就会找不到这个对象,也就无法单独删除此对象,造成内存泄露(java虽然的内存回收机制,但仍有内存泄露,这就是一个例子)。

Set集合常见子类-TreeSet
TreeSet可以对集合中元素按照元素自然顺序(默认顺序)进行排序,或者根据创建 TreeSet 时提供的Comparator比较器进行排序,底层数据结构是二叉树。TreeSet集合中的add(),contains()和remove()方法依据元素的自然顺序或TreeSet集合自身的Comparator比较器。
TreeSet排序的第1种方式:让元素自身具备比较性,元素需要实现Compareable接口,并覆盖compareTo()方法。
TreeSet排序的第2种方式:让集合自身具备比较性,当元素不具备比较性,或具备的比较性不是所需要的,可以使用此方式,集合的比较性会覆盖元素的比较性。

具体是定义比较器类,将该比较器类对象作为参数传递给TreeSet()的构造函数,比较器类需实现Comparator()接口,并覆盖compare(obj1,obj2)方法。

下面是一个用第一种方式解决IP地址排序的例子:

/*
需求:用TreeSet实现IP地址排序,用第1种方式实现,IP地址封装成IPAdress类,让IPAdress本身具有比较性
*/
import java.util.Iterator;
import java.util.TreeSet;
 public class IpTest {
         public static void main(String[] args) {
                 TreeSet ts=new TreeSet();
                 ts.add(new IpAdress("61.54.231.245"));
                 ts.add(new IpAdress("61.54.231.9"));
                 ts.add(new IpAdress("61.54.231.246"));
                 ts.add(new IpAdress("61.54.231.48"));
                 ts.add(new IpAdress("61.53.231.249"));                
                 Iterator it=ts.iterator();
                 while(it.hasNext()){
                         IpAdress ip=(IpAdress)it.next();
                         ip.Show();        
                 }
         }
 }
 class IpAdress implements Comparable{        
         private String adress;
         public IpAdress(String adress){
                 this.adress=adress;
         }
         public int compareTo(Object obj) {
                 if(!(obj instanceof IpAdress)){
                         throw new RuntimeException("不是IP地址");
                 }
                 IpAdress p=(IpAdress)obj;
                 String[] sp1=this.adress.split("\\.");
                 String[] sp2=p.adress.split("\\.");
                 for(int i=0;i<sp1.length;i++){
                         int x=Integer.parseInt(sp1[i])-Integer.parseInt(sp2[i]);
                         if(x!=0){
                                 return x;
                         }
                 }
                 return 0;                
         }
         public void Show(){
                 System.out.println(adress);
         }         
 }
运行结果就是:
61.53.231.249
61.54.231.9
61.54.231.48
61.54.231.245
61.54.231.246





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值