java基础之集合

java基础之集合

 (一) 概述
	对于数据结构,我想大家并不陌生。而在本质上,java的集合框架就是对数据结构的一个大体上的封装,从jdk1.2推出集合框架的概念以后,我们就没有必要再像以前自己来编写一个链表等数据结构。这个集合框架的概念和c++中的stl一样,可是并没有那么复杂,并且在jdk1.5推出泛型设计后,更是极大的方便了用户,框架也日趋完善。接下来就仔细研究下框架的相关知识,接口主要是谈及设计理念,而具体实现类更多的是使用代码示例完成。
 (二)初识集合
	1.这是集合的框架图,从框架图中就可以看出集合类的层次结构,更加有助于学习集合框架。
 (二)4个接口
	(1)Collection接口
		Collection接口是集合框架的基础,也是单值保存的最大父接口。由于所有单值集合都实现了这个接口,所以熟悉它的方法是必要的。其中方法有:
	增加:boolean addAll(Collection<? extends E> c);加入c所含的所有元素。只要加了元素,就返回true
	     boolean add(E e);保容器能持有你传给它的那个参数。如果没有把它加进去,就返回false
	删除:void clear();删除所有元素
	     boolean removeAll(Collection<?> c);
 	     boolean remove(Object o);
        查找:int size();
	     boolean isEmpty();
	     boolean contains(Object o);
	     boolean containsAll(Collection<?> c);
	     Iterator<E> iterator();
	     Object[] toArray();
	     <T> T[] toArray(T[] a);
	     boolean retainAll(Collection<?> c);
	(2)list接口
		list接口继承于Collection接口,并且对其进行了大量的扩充。使用了基于0的下标,即可以通过位置来访问其中的元素,就像数组一样。它所存储的元素允许重复,并且有序。除了继承的方法之外,它还新添加了基于下标的方法,可是lis本身还是一个接口,所以要想使用,就必须知道这个接口的子类。而最常用的是ArrayList和vector。vector是线程安全的,可是在同步实现上会花费大量时间。所以在线程不同步情况下可以使用ArrayList类,下面会讲解ArrayList类。由下面这些方法也可以看出List接口主要是增加了支持下标的操作方法。
	增加:boolean addAll(int index, Collection<? extends E> c);
             void add(int index, E element);
	删除:E remove(int index);
	改变:E set(int index, E element);
	查找:int indexOf(Object o);
	     int lastIndexOf(Object o);
             ListIterator<E> listIterator();
	     ListIterator<E> listIterator(int index);
             List<E> subList(int fromIndex, int toIndex);	     	     
	(3)set接口
		set接口就是集合接口。这里所说的集合与数学中的集合相似。既元素之间互异且无序,简单的说就是元素不能重复。set并不像List那样对Collection进行了大量的扩充,而是完整的继承了下来。并没有新添加方法。它的主要实现类是HashSet和TreeSet。以不同数据结构实现接口正是体现了java中接口与实现相分离的设计。下面将具体阐述HashSet和TreeSet类。
	(4)map接口
		map接口描述的是映射。映射就是一个元素与另一个元素相互关联,可类比数学中的映射概念。或者说是“键/值对“,键或者值都可以是对象,键必须唯一,键本身就是利用hastSet来实现,而值可以重复。key主要是用于检索关联的值。map接口中的方法如下:
	增加:V put(K key, V value);
	     void putAll(Map<? extends K, ? extends V> m);
	删除:void clear();
	     V remove(Object key);
	查找:int size();
	     boolean isEmpty();
	     V get(Object key);
	     boolean containsKey(Object key);
	     boolean containsValue(Object value);
	     Collection<V> values();
	     Set<K> keySet();
	     Collection<V> values();
	     Set<Map.Entry<K, V>> entrySet();
 (二)具体实现
       1. Lisy接口具体实现类
	(1)ArrayList类
		ArrayList类封装了一个动态再分配的对象数组,动态以为着可根据需要动态的增加数组长度,当超过原始大小时,会动态的增加数组长度,当元素被删除时,可以缩小数组。而ArrayList类的数组默认大小是10,当然可以在构建ArrayList类时指定默认大小,也可以通过ensureCapacity方法来人工增加ArrayList的容量。但是在分配也有自己的问题,因为再分配会话较多的时间,所以会影响性能,所以在事先知道会存储大量数据时,一次性就扩大它的容量是较好的做法。接下来就举例:
	
		//三种构造方法
		ArrayList<String> list1=new ArrayList<>();//默认构造方法
		ArrayList<String> list2=new ArrayList<>(list1);//用list1的数据来初始化list2
		ArrayList<String> list3=new ArrayList<>(15);//指定初始化时的容量
		//增加:
		
		list1.ensureCapacity(15);
		list3.add(0, "A");
		list3.add("B");//Colection的add方法语义已经改变,在末尾增加数组
		list3.add(2,"C");
		list3.add("D");
		System.out.println("list3-->"+list3);//addAll也同样的方法
		//结果:list3-->[A, B, C, D]
		
		//删除
		list3.trimToSize();//把ArrayList的大小和实际所含元素的大小设置一致
		list3.remove("A");
		list3.remove(0);
		System.out.println("list3-->"+list3);
		System.out.println("list3-->"+list3.size());
		//结果:list3-->[C, D]
		//改:
		list3.set(0, "C1");
		System.out.println(list3);
		//结果:[C1, D]
		//查:
		System.out.println(list3.get(0));
		System.out.println(list3.contains("C1"));
		ListIterator<String> lst=list3.listIterator();
		while(lst.hasNext()){
			System.out.println(lst.nextIndex()+"-->"+lst.next());
		}
		//结果:C1 true 0-->C1 1-->D
	(2)LinkedList类
		LinkedList类是与ArrayList类相互补的类,底层采用双向循环链表结构,适用于频繁的增加或者删除数据的类,而像快速检索数据则需要使用ArrayList类。
	
   LinkedList<Integer> list = new LinkedList<Integer>();  
		        System.out.println(list.size());  
		  
		        /* 向list中添加元素 */  
		        list.add(1);  
		        list.add(2);  
		        list.add(3);  
		        list.add(5);  
		        list.add(4);  
		          
		        System.out.println(list.size());  
		  
		        /* 遍历list */  
		        for (Integer integer : list) {  
		            System.out.println(integer);  
		        }  
		  
		        /* 获取第一个元素 ,即header的next域*/  
		        System.out.println("第一个元素是:" + list.getFirst());  
		          
		        /*获取最后一个元素,即header的previous域*/  
		        System.out.println("最后一个元素是:"+list.getLast());  
		    }  

       2 Set接口具体实现类
	(1)HashSet类
		HashSet类是set接口的子类,该容器所包含的元素不能重复且无序,实际上HashSet是基于HashMap来实现的,通过查看源代码可以知道,HasetSet方法大部分是通过调用hashMap的方法来实现,HashSet 中的包含元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。 
	
	// 使用 HashMap 的 key 保存 HashSet 中所有元素  
 	private transient HashMap<E,Object> map;   
 	// 定义一个虚拟的 Object 对象作为 HashMap 的 value   
 	private static final Object PRESENT = new Object();  
		HashSet采用散列法,散列优点在于即使存在一个非常大集合数据,它的的基本操作如add,remove,contains,size等方法,它们的运行时间可以保持不变。所以如果不关心元素的顺序,并且想要快速的查找元素,就可以使用HashSet类。还有一点需要注意的是当我们试图把某个类的对象放入 HashSet 中保存时,重写该类的 equals(Object obj) 方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致。因为HashSet在比较是不仅比较了equals,而且还比较了hashcode方法。
	在构造hashSet类时,其中个构造方法是public HashSet(int initialCapacity, float loadFactor),第一个参数是初始容量,如果事先知道容量,这样会比较好,但是我们并不是总能知道需要装多少个元素,当元素太多,散列太满,为避免散列冲突,这时就需要再散列,如果要对散列表再散列,就需要创建一个容量更多的表,并将所有元素插入到这个新表中,然后丢弃原米的表。装填因子(第二个参数)决定何时对散列表进行离散。例如,如果装填回子为0 .75 (默认值),而表中超过75% 的位置已经填人元素,这个表就会用双倍的容量自动地迸行再散列。接下来我将一一举例如何使用:
	
class Person{
	private String name;
	private int age;
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

public class HashSetTest {

	public static void main(String[] args) {
		HashSet<Person> set=new HashSet<>();
		//增加:
		set.add(new Person("lkx3",15) );
		set.add(new Person("lkx2", 16));
		set.add(new Person("lkx1",17));
		Iterator<Person> it=set.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
		
		//删除:
		set.remove(new Person("lkx1",17));
		
		//查找
		System.out.println(set.isEmpty());
		System.out.println(set.contains(new Person("lkx1",17)));
		
	}

}
	(2)TreeSet类
		TreeSet是数集,与散列集十分相似,但是又有改进,那就是数集是一个有序集合,以任意顺序插入元素,数集将自动或者按照指定的比较器来对插入元素进行排序,然后在遍历时将按照顺序输出。数集的底层数据结构采用的是红黑树,在添加一个元素的事情上,数集所花费的时间要比散列集多。
		前面已经讲过数集里的元素有序,当传入一个对象时,为了排序,插入的类需要实现comparable接口,以便按照指定的顺序排序。在java内置的类里,String 类就实现了 Comparable接口,这个类的compareTo方法依据字典序( 有时称为词典序)对字符串进行比较。而采用实现Comparable接口来排序也有一定的局限,如果在这个数集里用这种排序规则,而在另一个树集中采用那个规则,就有了局限。所以数集里有个构造方法,其参数就是一个Comparator接口。所以可以实现这个接口里的compare方法,数集将按照这个方法进行排序。示例如下:
//实现比较接口,进行排序
class Order implements Comparable<Order>{
	private String name;
	private int orderCount;
	
	public Order(String name, int orderCount) {
		this.name = name;
		this.orderCount = orderCount;
	}
	public int compareTo(Order order) {
		if(orderCount<order.orderCount){
			return -1;
		}else if(orderCount==order.orderCount){
			return 0;
		}else {
			return 1;			
		}
	}
	public String toString() {
		return "Order [name=" + name + ", orderCount=" + orderCount + "]";
	}
	
}
public class TreeSetTest {
	public static void main(String[] args) {
		TreeSet<Order> set=new TreeSet<>();
		set.add(new Order("col",10));
		set.add(new Order("lkx",5));
		set.add(new Order("ccc",15));
		Iterator<Order> it=set.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}	
	}
       3 map接口具体实现类
	(1)HashMap类
		HashMap类使用散列表实现Map接口,与上述HashSet类似,它允许使用 null 值和 null 键。他也有与hashSet类似的构造函数,初始容量和加载因子,意思也差不多。注意它不是线程同步的。
public class HashMapTest {

	public static void main(String[] args) {
		HashMap<String,Double> hm=new HashMap<>();
		hm.put("lkx1", new Double(323.4));
		hm.put("lkx2", new Double(123.22));
		hm.put("lkx3", new Double(1245.2));
		//返回键值集视图,当然还有映射中键集的视图(public Set<K> keySet())
		//值集视图(public Collection<V> values() )
		Set<Entry<String,Double>> set=hm.entrySet();
		Iterator<Entry<String,Double>> it=set.iterator();
		//显示
		while(it.hasNext()){
			Entry<String,Double> em=(Map.Entry<String,Double>) it.next();
			System.out.println(em.getKey()+"-->"+em.getValue());
		}
	}
}

	(2)TreeMap类
		TreeMap类是基于红黑树实现的。TreeMap提供了按排序顺序存储键/值的有效手段,同时允许快速检索,应该注意的是,不想散列映射,树映射保证了它的元素按照关键在升序排序。其中也有一个构造方法与TreeSet一样。TreeMap(Cpmparator comp 提供比较器。
public class TreeMapTest {

	public static void main(String[] args) {
		TreeMap<Integer, String> tm=new TreeMap<>();
		tm.put(new Integer(3200), "kk");
		tm.put(new Integer(5000), "sss");
		tm.put(new Integer(1500),"sws");
		
		Collection<String> col=tm.values();
		Iterator<String> it=col.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}

}

参考资料:
《java 核心技术卷一》
《java 从入门到精通》

	



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值