集合框架之一 List-Set

 -------android培训java培训、期待与您交流! ----------  

 

集合:

集合的特点:

     1,用于存储对象的容器。
     2,该容器的长度是可变的。

集合的功能:

    面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行(存储,遍历,修改),集合就是存储对象最常用的一种方式。

集合框架的由来:
      集合就是一个容器,而容器有很多,因为每个容器中的数据结构是不同的。但是都具备着共性,可以向上不断的抽取,这样就形成了集合框架。


集合和数组的区别:
 1,集合的长度是可变的。
    数组的长度是固定的。
 2,集合只能存储对象。
    数组既可以存储对象,又可以存储基本类型数值。
 3,集合中存储的对象可以使任意类型的。
    数组中只能存储同一类型的对象。

 集合框架的构成与分类:

 

Collection:

    Collection中常见方法:

 1,添加方法。 
     boolean add(object e):一次添加一个元素。
    boolean addAll(Collection):将一个参数容器中的元素添加到当前容器中。
     
   2,删除方法。
     boolean remove(object):删除一个指定对象。 
     boolean removeAll(Collection):删除指定collection中和本Collection中相同的元素。 
     void clear():直接将集合中的元素清空。
   3,判断方法:
     boolean contains(object):是否包含指定元素。
     boolean containsAll(Collection):是否包含指定容器中的元素。 
     boolean isEmpty():是否有元素。
   4,获取元素个数:
     int size():获取元素有几个。
   5,取交集。
     boolean retainAll(collection):保留和指定collection集合中相同的元素,不相同的元素会被删除。
   6,将集合转成数组。
     Object[] toArray():
   7,取出元素的方法:
     Iterator iterator():

  迭代器的好处:将容器的取出方式和容器的数据结构相分离,降低了耦合性。
  而取出方式因为直接在访问容器中的元素,并依赖具体的数据结构所以被定义在了容器中。
  通过内部类来实现Iterator接口。

 代码演示:

public static void collDemo(){
	Collection coll = new ArrayList();
	//添加元素
	coll.add("java");
	coll.add("csdn");
	coll.add("itcast");
	coll.add(".net");
	
	//删除元素
	coll.remove(".net");
	
	//判断是否包含
	coll.contains("csdn");
	
	//获取元素个数
	int count = coll.size();
	
	//将集合转数组
	Object[] arr = coll.toArray();
}


取出元素:

Iterator it = coll.iterator();
while(it.hasNext())
{
	System.out.println(it.next());
}
//实际开发中建议建议将while循环改为for循环,因为for循环创建的对象it在循环结束会被释放可以节省空间
for(Iterator it = coll.iterator();it.hasNext(); ){
	System.out.println(it.next());
}

 

迭代器注意事项:

    迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
    迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
    迭代器的next方法返回值类型是Object,所以要记得类型转换。


List集合:

|--List:元素是有序的,元素可以重复,因为该集合体系有索引。
     |--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快,但增删稍慢。注意:此线程是不同步的
        它的初始容量为10,当数组超过10时,它会new一个新的数组,其长度增加50%。
     |--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,但查询稍慢。
     |--Vector:底层是数组数据结构。 从JDK1.0开始出现,当升级到JDK1.2之后开始用List接口。注意:此线程是

 同步的。  被ArrayList替代了。
  它的初始容量为10,当数组超过10时,它会new一个新的数组,其长度增加100%。
 可变长度数组原理:一旦原数组长度不够,会创建新数组,将原数组的元素复制到新数组中,并将新元素添加到新数组中。
        枚举就是Vector特有的取出方式
 
List集合特有方法,凡是可以操作角标的方法都是该体系特有的方法。

   add(index,element);
   addAll(index,Collection);

   remove(index);


  set(index,element);

   get(index);
   subList(from,to);
   listIterator();
  
  
  List集合特有的迭代器:ListIterator是Iterator的子接口
  在迭代时不可以通过集合的方法操作集合中的元素。因为会发生ConcurrentModificationException异常。
  所以在迭代时只能用迭代器的方法操作元素,可是Iterator方法是有局限性的,只能对元素
  进行判断,取出,删除的操作。如果想要其他的操作,如,添加,修改等就需要使用其子接口ListIterator,
  该接口只能通过List集合的ListIterator方法获取

 往List集合中存储自定义对象

  1,对自定义对象进行描述。  
  2,存储时,都被提升为了Object。
  3, 取出时如果要使用自定义对象的特有方法,一定要进行向下转型。 
  4,注意事项:在迭代时,循环中只要有一个next()即可。

例如:

public static void listDemo {
	
	Collection coll = new ArrayList();
	coll.add(new Person("lisi1",21));
	coll.add(new Person("lisi2",22));
	coll.add(new Person("lisi3",23));
	coll.add(new Person("lisi4",24));
	coll.add(new Person("lisi5",25));
	
	Iterator it = coll.iterator();
	while(it.hasNext()){
		Person p = (Person)it.next();//向下转型
		
		//只获取姓名或年龄
		System.out.println(p.getName());
		
		//同时获取姓名和年龄
		System.out.println(p.getName()+":"+p.getAge());//注意在迭代时循环中只要有一个next即可
	}
}

注意:ArrayList判断是否相同使用的是equals方法。
 比如contains就是依赖于equals方法,或者remove方法也是依赖于equals方法。

尤其是在存储自定义对象时,因为默认比较的是地址值,所以该对象一定要覆盖equals方法,建立根据对象自身特点的判断相同的依据。
equals方法就是用于比较对象内容的。

 

LinkedList特点:可以在集合开始或者结尾处添加或删除元素,

    用到方法:addFirst(E e);从开头添加元素

                      addLast(E e);

                     removeFirst();从开头删除元素

                     removeLast();

例如:

public static void LinkedListDemo(){
	LinkedList link = new LinkedList();
	link.addFirst("abc1");
	link.addFirst("abc2");
	link.addFirst("abc3");
	
	link.removeLast();
	Iterator it = link.iterator();
	while(it.hasNext){
		System.out.println(it.next());
	}
}


 

 

 集合一些小细节。
   创建一个集合容器。其实也是一个对象。
  这个对象中存储着特定结构可以对对象进行存储。
  
  Collection coll = new ArrayList();
   1,存储时,add可以接收任意类型的对象因为参数类型是Object。
   所以对象元素存入时都被提升为了Object。
   
   2,其实在集合中真正存储都是对象的引用。
   
  coll.add(new Object());
  coll.add("abc");
  用迭代器取出时,其实取出的也是引用。
  
  coll.add(5);//这样写可以。因为jdk1.5后,有了自动装箱机制。相当于new Integer(5).装箱Integer.valueOf(5);
  //等同于coll.add(Integer.valueOf(5));//拆箱 intValue();

 

Set集合:

    |--Set:

        |--HashSet
        |--TreeSet

Set集合特点:

    1,不包含重复元素。(最大的特点)
    2,这个集合存入元素的顺序和取出元素的顺序不一定一致。(具体的容器对象数据结构不同,顺序也有不同)

 

HashSet:底层数据结构式哈希表。不保证顺序,是不同步的。

    哈希表:提供数组的查询效率而出现的。
    将要存储的元素先通过哈希算法算出一个哈希值来标识存储的位置,代表着元素。
    要找元素时,先将该元素通过哈希算法算出哈希值,在通过哈希值到哈希表中去查找。

HashSet特点

    1,不关心元素的顺序。
    2,提高了查询效率。
    3,不可能出现重复元素,因为哈希值都不同。即使相同,会再次判断两个元素的equals,内容是否相同。
如果内容也相同,不存,如果内容不同,存储。
所以保证唯一性的依据就是:通过equals方法和hashCode方法来保证元素的唯一性。
    首先判断hashCode()的值是否相同:如果不相同就直接添加到集合中,如果相同会继续用equals方法进行判断。如果equals判断后返回的是true说明元素重复,不添加,如果返回值是false则直接添加到集合中。

所以往哈希表中存储自定义对象必须要覆盖hashCode方法和equals方法

代码演示:

import java.util.HashSet;
import java.util.Iterator;
/*
 * 存储自定义对象
 */
public class HashSetTest {
	public static void main(String[] args) {
		HashSet<Person> hs = new HashSet<Person>();
		hs.add(new Person("lisi1",21));
		hs.add(new Person("lisi2",22));
		hs.add(new Person("lisi3",23));
		hs.add(new Person("lisi1",21));
		hs.add(new Person("lisi2",22));
		Iterator<Person> it = hs.iterator();
		while(it.hasNext()){
			System.out.println(it.next());//为了去除重复元素,所以必须要覆盖hashCode方法,和equals方法。
		}
	}
}
public class Person {
	private String name ;
	private int age ;
	public Person() {
		super();
		
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	/**
	 * 覆盖HashCode方法,建立Person对象自身的哈希算法
	 */
	public int hashCode(){
		return name.hashCode()+age*31;
	}	
	/**
	 * 覆盖Object类中的equals方法,建立Person对象
	 * 判断是否相同的依据。根据Person自身特点来判断
	 */
	public boolean equals(Object obj){
		if(!(obj instanceof Person))
			return false;
		Person p = (Person)obj;
		return this.name.equals(p.name)&&this.age==p.age;
	}
	public String toString() {
		return name+":"+age;
	}	
}


注意:对于判断元素是否存在以及删除等操作,依赖的方法是元素的hashcode和equals方法

TreeSet特点:

     1,可以给Set集合中的元素进行指定顺序的排序。默认情况下,是通过元素的自然顺序排的序。

     2,通过compareTo或者compare方法中的来保证元素的唯一 性。

TreeSet排序方式:

    1,让元素自身具备比较性,需要实现Comparable接口,覆盖compareTo方法。这种比较方式成为自然顺序排序。

    2,让容器自身具备比较性。容器一初始化就具备了比较功能。 因为容器时在对象构造时完成的。通过查阅API,有一个构造方法TreeSet(Comparator)。在容器初始化时可以指定一个比较器。 需要实现Comparator接口,覆盖compare方法即可。所以这种方式成为比较器排序。

TreeSet中如果要想输出结果的顺序和添加的一致只要实现Comparable接口,并将其中的comparaTo覆盖返回1即可,如,

public int compareTo(Object o){
	return 1;
}

TreeSet两种排序方式演示:

方式一:

import java.util.HashSet;
import java.util.Iterator;

import 集合框架.been.Person;
/*
 * 存储自定义对象
 */
public class HashSetTest {
	public static void main(String[] args) {
		HashSet<Person> hs = new HashSet<Person>();
		hs.add(new Person("lisi1",21));
		hs.add(new Person("lisi2",22));
		hs.add(new Person("lisi3",23));
		hs.add(new Person("lisi1",21));
		hs.add(new Person("lisi2",22));
		Iterator<Person> it = hs.iterator();
		while(it.hasNext()){
			System.out.println(it.next());//为了去除重复元素,所以必须要覆盖hashCode方法,和equals方法。
		}
	}
}
/**
 * 想要Person具备比较大小功能,
 * 就需要对Person对象的功能进行扩展,
 * 让Person去实现Comparable接口。让Person具备自然顺序。 覆盖compareTo方法。 
 */
public class Person implements Comparable<Person>{
	private String name ;
	private int age ;
	public Person() {
		super();
		
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	/**
	 * 覆盖HashCode方法,建立Person对象自身的哈希算法
	 */
	public int hashCode(){
		return name.hashCode()+age*31;
	}	
	/**
	 * 覆盖Object类中的equals方法,建立Person对象
	 * 判断是否相同的依据。根据Person自身特点来判断
	 */
	public boolean equals(Object obj){
		if(!(obj instanceof Person))
			return false;
		Person p = (Person)obj;
		return this.name.equals(p.name)&&this.age==p.age;
	}
	public String toString() {
		return name+":"+age;
	}	
	public int compareTo(Person o) {
		int temp = this.age - o.age ;
		return temp==0?this.name.compareTo(o.name):temp ;
	}
}

方式二:

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

/*
 * 对字符串的长度进行排序
 */
public class TreeSetTest2 {
	public static void main(String[] args) {
		TreeSet<String> ts = new TreeSet<String>(new comparatorByLength());
		ts.add("abcd");
		ts.add("cba");
		ts.add("adbe");
		ts.add("nba");
		ts.add("qq");
		Iterator<String> it = ts.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}
public class comparatorByLength implements Comparator<String> {
	public int compare(String o1, String o2) {
		int temp = o1.length() - o2.length();
		return temp==0?o1.compareTo(o2):temp;
	}
}


其实Set中有一种有序的集合就是HashSet的子类LinkedHashSet,它可以实现怎么存就怎么取。

LinkedHashSet特点:

     1,底层数据结构是链表和哈希表。是有序的,元素唯一,线程不安全,效率高。它是通过链表结构保证有序,通过哈希表结构保证唯一。
     2,此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。

注意:插入顺序 受在 set 中重新插入的 元素的影响。


集合的技巧掌握:
     明确具体集合对象名称的后缀:
     如果后缀是List,都所属于List体系。通常都是非同步的。
     如果后缀是Set,都属于Set体系,通常也是非同步的。
     这些体系中的其他子类对象,后缀不是所属接口名的,一般都是同步的。比如Vector。这在常用子类对象中通用。

明确数据结构:
     对于jdk1.2版本的子类对象。
     后缀名是所属的体系。
     前缀名是就是数据结构的名称。
比如:
     ArrayList: 看到Array,就要明确是数组结构。查询快。
     LinkedList:看到Link,就要明确链表结构,就要想到 add get remove 和first last结合的方法.增删快。,
     HashSet:看到hash,就要明确是哈希表。查询巨快,而且唯一性。就要想到元素必须覆盖 hashCode方法和equals方法。
     TreeSet:看到Tree,就要明确是二叉树,可以对元素排序。就要想到两种排序方式:
                      自然顺序:Comparable接口,覆盖compareTo(一个参数 )java.lang
                      比较器:Comparator接口,覆盖compare(两个参数);java.util
                      判断元素唯一性的依据就是比较方法的返回结果return 0;

 

                                ------- android培训java培训、期待与您交流! ---------- 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值