黑马程序员:集合类:List(ArrayList、LinkedList、Vector)、Set(HashSet、TreeSet)介绍

时间:2022-08-11 17:55:31

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

集合类


为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式

数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但是长度固定;集合长度是可变的,数组中可以存储基本数据类型,集合只能存储对象

集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象

集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法
接口:即表示集合的抽象数据类型。接口提供了让我们对集合中所表示的内容进行单独操作的可能。
实现:也就是集合框架中接口的具体实现。实际它们就是那些可复用的数据结构。
算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。这些算法通常是多态的,因为相同的方法可以在同一个接口被多个类实现时有不同的表现。事实上,算法是可复用的函数

使用集合框架,需要import java.util.*;

Collection:单列集合
示例:
import java.util.*;
/*
集合类中基本使用方法
*/
class CollectionDemo
{
	public static void main(String[] args) {
		//创建一个集合容器,使用Collection接口的子类:ArrayList
		ArrayList a1 = new ArrayList();
		ArrayList a2 = new ArrayList();
		Object obj = new Object();
		sop(obj.toString());
		//1,添加元素(对象)
		a1.add("java1"); //add(Object obj),add加的是对象的toString()信息
		a1.add("java2");
		a1.add("java3");
		a1.add(obj);
		a2.add(obj);
		a2.add("java2");
		a2.add("java3");
		sop(a1.add("java4")); //true add方法返回的是boolean类型
		a1.addAll(a2); // 在a1容器后加上a2容器中的所有对象,不考虑重复不重复
		
		//打印原集合
		sop(a1);
		
		//2,删除元素
		a1.remove("java2");
		sop(a1); //[java1, java3, java4]
		sop(a2); //[java2, java3]
		//a1.removeAll(a2); //若a1中存在a2容器中有的对象,则删除
		sop(a1); //[java1, java4]
		
		//a1.clear(); //清空集合
		//sop(a1);
		
		//3,判断元素
		sop(a1.contains("java3"));
		sop(a1.containsAll(a2));
		sop(a1.isEmpty()); //判断集合为空,原理:集合size=0则为空
		
		//4,获取元素
		sop(a1.size()); //获取集合长度
		
		//5,取交集
		sop(a1); //[java1, java3, java4]
		sop(a2); //[java2, java3]
		a1.retainAll(a2); //取交集,返回a1和a2的交集赋给a1
		sop(a1); //[java3] ,若a1和a2无交集,则a1 = [] 即a1.size()为0
		sop(a1.size()); // 1
		sop(a2); // [java2, java3]
		
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

import java.util.*;
/*
获取迭代器,用于取出集合中的元素
迭代器:从集合中取出元素的方式
*/
class CollectionDemo
{
	public static void main(String[] args) {
		ArrayList a1 = new ArrayList();
		a1.add("java1");
		a1.add("java2");
		a1.add("java3");
		a1.add("java4");
		
		Iterator it = a1.iterator();
		it.next(); //java1
		it.remove(); //  删除java1 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
		//用while语句结束后,it引用变量还会存在内存中,即引用的对象就会存在内存中
		while(it.hasNext())  // hasNext() 如果仍有元素可以迭代,则返回 true
			sop(it.next()); // next() 返回迭代的下一个元素。
		
		//for里面的forit是局部变量,用完就释放内存,更有利于内存管理
		for(Iterator forit = a1.iterator(); forit.hasNext(); )
			sop(forit.next());
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
/*
Collection
|--List:元素是有序的,元素可以重复,因为该集合体系有索引
|--ArrayList:底层的数据结构使用的是数组结构,这种结构都有索引值,查询速度很快,但增删稍慢(原因:增删引起索引值变化),线程不同步,默认长度10,超过会new新的数组,长度是50%延长,然后把老数组的内容给new数组
|--LinkedList:底层使用的是链表数据结构,依次查询,增删速度很快,查询稍慢 (面试可能会出现)
|--Vector:底层是数组数据结构,线程同步,被ArrayList替代,100%延长
|--Set:元素是无序的,元素不可以重复,该集合体系没有索引
*/
List:
特有方法,凡是可以操作角标的方法都是该体系特有的方法

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



remove(index);


set(index.element)



get(index);
subList(from,to);
listIterator();


import java.util.*;
/*
List方法演示
*/
class CollectionDemo
{
	public static void main(String[] args) {
		ArrayList a1 = new ArrayList();
		a1.add("java1");
		a1.add("java2");
		a1.add("java3");
		a1.add("java4");
		sop("原集合:"+a1);
		//在指定位置插入元素
		a1.add(1,"java007");
		//删除指定位置的元素
		a1.remove(2);
		
		//修改元素
		a1.set(1,"java008");
		
		sop(a1);
		//通过角标获取元素
		sop(a1.get(1));
		
		/*
		获取所有元素的两种方法
		一,通过角标遍历,List不同于Set体系的方法
		二,迭代器
		*/	
		sop("==========遍历方式==========");
		for (int x=0; x<a1.size(); x++)
		{
			sop(a1.get(x));
		}
		sop("==========迭代器方式==========");
		for (Iterator it = a1.iterator(); it.hasNext(); )
		{
			sop(it.next());
		}
		
		//通过indexOf获取对象的位置
		sop(a1.indexOf("java4"));
		sop(a1.subList(1,3)); //含头不含尾
		
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

List集合特有的迭代器
ListIterator是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作集合中的元素
因为会发生ConcurrentModificationException异常(并发修改异常)
所以,在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,
只能对元素进行判断,取出,删除的操作
如果想要其他的操作,如添加,修改等,就需要使用其子接口ListIterator
该接口只能通过List集合的listIterator方法操作
previousIndex(),若是第一个元素,则返回前一个元素索引值为-1
nextIndex(),若是最后一个元素,则返回后一个元素为List的size
import java.util.*;
/*
listIterator方法演示
*/
class ListIteratorDemo
{
	public static void main(String[] args) {
		ArrayList a1 = new ArrayList();
		a1.add("java1");
		a1.add("java2");
		a1.add("java3");
		a1.add("java4");
	for (ListIterator li = a1.listIterator(); li.hasNext(); )
	{	//sop(li.previous()); //因为指针前面没有值,所以返回RuntimeException:NoSuchElementException异常
		sop("previous当前指针前是否有值:"+li.hasPrevious()+"\t前一个元素索引值:"+li.previousIndex());
		Object obj = li.next();
		sop(obj);
		if (obj.equals("java2"))
		{
		   li.set("java007");
		   li.add("java008");
		}
		sop("next当前指针后是否有值:"+li.hasNext()+"\t后一个元素索引值:"+li.nextIndex());
	}
		sop(a1);//[java1, java007, java008, java3, java4]
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

枚举(Enumeration):Vector特有的取出方式
其实枚举和迭代是一样的,因为枚举的名称以及方法的名称都过长,所以被迭代器取代了

import java.util.*;
/*
Vector中elements()方法演示 枚举
*/
class CollectionDemo
{
	public static void main(String[] args) 
	{
		Vector a1 = new Vector();
		a1.add("java1");
		a1.add("java2");
		a1.add("java3");
		a1.add("java4");
		for (Enumeration en = a1.elements(); en.hasMoreElements(); )
			sop(en.nextElement());
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

LinkedList特有方法:
addFirst();
addLast();


getFirst(); 获取元素,但元素不删除,如果此列表为空,会出现NoSuchElementException异常
getLast();


removeFirst(); 获取元素,但是元素被删除,如果此列表为空,会出现NoSuchElementException异常
removeLast();


JDK1.6出现了替代方法
offerFirst()
offerLast()


peekFirst(); 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null(和getFirst的区别)。
peekLast();


pollFirst(); 获取并移除此列表的第一个元素;如果此列表为空,则返回 null(和removeFirst的区别)。
pollLast();


import java.util.*;
/*
LinkedList中的方法演示
*/
class CollectionDemo
{
	public static void main(String[] args) 
	{
		LinkedList link = new LinkedList();
		link.offerFirst("java1");
		link.offerFirst("java2");
		link.offerFirst("java3");
		link.offerFirst("java4");
		sop(link); //[java4, java3, java2, java1]
		sop(link.peekFirst()); //仅获取
		sop(link.peekLast());
		sop(link.pollFirst()); //获取并删除
		sop(link.size());
		
		//循环输出集合中的元素(除用迭代器之外的另一种方式)
		while (!link.isEmpty())
		{
		   sop(link.pollFirst()); 
		}
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

练习题:
/*
使用LinkedList模拟一个堆栈或者队列数据结构
堆栈:先进后出 如同杯子
队列:先进先出 如同水管
以下这种封装方式有利于项目的开发,函数名,对象名都可以改成和项目相关的
*/
import java.util.*;
class DuiLie
{
	private LinkedList link;
	DuiLie()
	{
		link = new LinkedList();
	}
	public void myAdd(Object obj)
	{
		link.offerFirst(obj);
	}
	public Object myGet()
	{
		return link.pollFirst(); //先进后出
		//return link.pollLast(); 先进先出
	}
	public boolean isNull()
	{
		return link.isEmpty();
	}
}
class LinkedListTest
{
	public static void main(String[] args) {
		DuiLie dl = new DuiLie();
		dl.myAdd("java1");
		dl.myAdd("java2");
		dl.myAdd("java3");
		while(!dl.isNull())
			System.out.println(dl.myGet());
	}
}

/*
去除ArrayList集合中的重复元素
获取不重复的元素到新集合
*/
import java.util.*;
class ArrayListTest
{
	public static void main(String[] args) 
	{
		ArrayList al = new ArrayList();
		al.add("java1");
		al.add("java2");
		al.add("java3");
		al.add("java1");
		al.add("java2");
		sop(al);
		sop(singleElements(al));
	}
	public static List singleElements(ArrayList al)
	{
		ArrayList newal = new ArrayList();
		for (Iterator it = al.iterator(); it.hasNext(); )
		{
			Object obj = it.next();
			if (!newal.contains(obj))
			{
			   newal.add(obj);
			}
		}
		return newal;
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
/*
将自定义对象作为元素存储到ArrayList集合中,并去除重复元素
比如:存人对象,同姓名及年龄,视为同一个人,为重复元素
思路:
1.描述人,将数据封装进人对象
2.定义容器,将人存入
3.取出
注意:List集合判断元素是否相同,依据是元素的equals方法,可参阅contains方法API解释
*/
import java.util.*;
//封装人
class Person
{
	private String name;
	private int age;
	Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	//contains原理为调用equals,这里实现equals的覆盖,比较对象中姓名及年龄是否全一样
	public boolean equals(Object obj)
	{
		if (!obj instanceof Person)
			return false;
		Person e = (Person)obj; //向下转型
		return this.name.equals(e.name) && this.age==e.age;
	}
}
class ArrayListTest
{
	public static void main(String[] args) 
	{
		ArrayList al = new ArrayList();
		al.add(new Person("zhangsan",12));
		al.add(new Person("lisi",13));
		al.add(new Person("wangwu",12));
		al.add(new Person("xiaomei",14));
		al.add(new Person("lisi",13));
		al = singleElements(al);
		for (Iterator it = al.iterator(); it.hasNext(); )
		{
			Person p = (Person)it.next(); //向下转型
			sop(p.getName()+"~~"+p.getAge());
		}
		
	}
	//去除重复方法
	public static ArrayList singleElements(ArrayList al)
	{
		ArrayList newal = new ArrayList();
		for (Iterator it = al.iterator(); it.hasNext(); )
		{
			Person p = (Person)it.next();
			if (!newal.contains(p))
			  	newal.add(p);
		}
		return newal;
	}


	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复
|--HashSet:底层数据结构是哈希表
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成
如果元素的HashCode值相同,才会判断equals是否为true
若元素的hashcode值不同,则不会调用equals

注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的HashCode和equals方法
|--TreeSet:可以对Set集合中的元素进行排序,按照字母的ASCII码值,同第一个字母的,按后续不同字母继续排
注意:排序时,当主要条件相同时,一定要判断一下次要条件,TreeSet取值时,是从小到大取的
底层数据结构是二叉树(又称红黑树)
保证元素唯一性的依据:compareTo() return 0;

TreeSet排序的第一种方式:让元素自身具备比较性
元素需要实现Comparable接口,覆盖compareTo方法
这种方式也称为元素的自然顺序,也叫默认顺序

TreeSet排序的第二中方式:
当元素自身不具备比较性时,或者具备的比较性不是所需要的,
这时就需要让集合自身具备比较性
在集合初始化时,就有了比较方式
实现方式:
定义一个类并实现Comparator接口,通过覆盖Comparator结构的int compare(Object obj1, Object obj2)来做比较
再创建集合的时候,使用定义比较器的构造函数  如:TreeSet ts = new TreeSet(new MyComparator()); //MyComparator为实现其接口的类

Set集合的功能和Collection是一致的


/*
往HashSet集合中存入自定义对象
姓名和年龄相同为同一个人,重复元素
*/
import java.util.*;
//封装人
class Person
{
	private String name;
	private int age;
	Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	public int hashCode()
	{
		HashSetTest.sop(this.name+"~hashcode~");
		return name.hashCode()+age*27; //为什么age*27?  因为这里返回的是一个int类型的值,所以只要保证返回值在int取值范围内即可
	}
	public boolean equals(Object obj)
	{
		HashSetTest.sop(this.name+"~equals~");
		Person p = (Person)obj;
		return this.name.equals(p.name) && this.age == p.age;
	}
}
class HashSetTest
{
	public static void main(String[] args) 
	{
		HashSet hs = new HashSet();
		sop(hs.add(new Person("a1",12))); //true
		hs.add(new Person("a2",13));
		hs.add(new Person("a3",13));
		sop(hs.add(new Person("a1",12))); //false 因为HashSet集合中存在相同hashcode&&equals值的元素
		sop(hs);
		//不管是判断是否包含还是删除,都要先匹配hashcode值,再equals匹配内容,都匹配上,才算是相同的一个对象
		sop("========contains=========");
		sop(hs.contains(new Person("a1",12)));
		sop("=======remove==========");
		sop(hs.remove(new Person("a2",13)));
		for (Iterator it = hs.iterator(); it.hasNext(); )
		{
			Person p = (Person)it.next();
			sop(p.getName()+"--"+p.getAge());
		}
	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

/*
TreeSet排序的第一种方式:让元素自身具备比较性
注意点:
1.当元素自身具备的比较性无法比较时,元素要实现Comparable接口,并覆盖其compareTo()方法,自定义其排序方式
2.比较元素中主要排序条件后,要比较次要排序条件,不然会因为主要条件相同导致整个对象相同,而违背了真实情况
*/
import java.util.*;
class Person implements Comparable
{
	private String name;
	private int age;
	public void setAge(int age)
	{
		this.age = age;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public int getAge()
	{
		return age;
	}
	public String getName()
	{
		return name;
	}
	//覆盖TreeSet自然排序底层调用的方法
	public int compareTo(Object obj) //这里不能声明异常,因为该类实现了Comparable接口,该接口并未声明异常
	{
		if(!(obj instanceof Person))
			throw new RuntimeException("这不是一个人");
		Person p = (Person)obj;
		if (this.age == p.age)
			//判断完主条件,判断次条件
		   return this.name.compareTo(p.name); //String类中compareTo()已经做了覆盖处理
		return this.age-p.age;
	}
}


class TreeSetDemo
{
	public static void main(String[] args)
	{
		TreeSet ts = new TreeSet();
		ts.add(setInfo("lisi001",13));
		ts.add(setInfo("lisi002",14));
		ts.add(setInfo("lisi003",15));
		ts.add(setInfo("lisi002",13));
		ts.add(setInfo("lisi002",14)); //这条不会被存入,Set集合不存在重复元素
		for (Iterator it = ts.iterator(); it.hasNext(); )
		{
			Person p = (Person)it.next();
			sop(p.getName()+"~~"+p.getAge());
		}
		
	}
	//打印功能
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	//对元素存储信息操作封装
	private static Person setInfo(String name, int age)
	{
		Person p = new Person();
		p.setAge(age);
		p.setName(name);
		return p;
	}
}

/*
TreeSet元素存储先进先出方法演示
*/
import java.util.*;
class Person implements Comparable
{
	private String name;
	private int age;
	public void setAge(int age)
	{
		this.age = age;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public int getAge()
	{
		return age;
	}
	public String getName()
	{
		return name;
	}
	//覆盖TreeSet自然排序底层调用的方法
	public int compareTo(Object obj) //这里不能声明异常,因为该类实现了Comparable接口,该接口并未声明异常
	{
		return 1; //先进先出  TreeSet按从小到大排序,return 1就会导致后存入的数据比前一个数据大,即往后排
		//return 0; //只有第一个数据存入,其他数据当重复对象处理
		//return -1; //先进后出
	}
}


class TreeSetDemo
{
	public static void main(String[] args)
	{
		TreeSet ts = new TreeSet();
		ts.add(setInfo("lisi001",13));
		ts.add(setInfo("lisi002",14));
		ts.add(setInfo("lisi003",15));
		ts.add(setInfo("lisi002",13));
		ts.add(setInfo("lisi002",14)); //这条不会被存入,Set集合不存在重复元素
		for (Iterator it = ts.iterator(); it.hasNext(); )
		{
			Person p = (Person)it.next();
			sop(p.getName()+"~~"+p.getAge());
		}
		
	}
	//打印功能
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	//对元素存储信息操作封装
	private static Person setInfo(String name, int age)
	{
		Person p = new Person();
		p.setAge(age);
		p.setName(name);
		return p;
	}
}

/*
TreeSet排序的第二中方式:使用自定义的比较器,这种方式比较常用
当元素自身不具备比较性,或者具备的比较性不是所需要的,这时需要让容器自身具备比较性
定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数
当两种排序都存在时,以比较器为主
自定义比较器的方法:
定义一个类,实现Comparator结构,覆盖compare(object o1, object o2).

*/
import java.util.*;
class Person implements Comparable
{
	private String name;
	private int age;
	public void setAge(int age)
	{
		this.age = age;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public int getAge()
	{
		return age;
	}
	public String getName()
	{
		return name;
	}
	//覆盖TreeSet自然排序底层调用的方法
	public int compareTo(Object obj) //这里不能声明异常,因为该类实现了Comparable接口,该接口并未声明异常
	{
		if(!(obj instanceof Person))
			throw new RuntimeException("这不是一个人");
		Person p = (Person)obj;
		if (this.age == p.age)
			//判断完主条件,判断次条件
		   return this.name.compareTo(p.name); //String类中compareTo()已经做了覆盖处理
		return this.age-p.age;
	}
}


class TreeSetDemo
{
	public static void main(String[] args)
	{
		//TreeSet ts = new TreeSet(); 
		TreeSet ts = new TreeSet(new MyCompare()); //使用自身比较器
		ts.add(setInfo("lisi001",15));
		ts.add(setInfo("lisi002",14));
		ts.add(setInfo("lisi003",18));
		ts.add(setInfo("lisi002",13));
		ts.add(setInfo("lisi002",13));
		ts.add(setInfo("lisi002",14)); //这条不会被存入,Set集合不存在重复元素
		for (Iterator it = ts.iterator(); it.hasNext(); )
		{
			Person p = (Person)it.next();
			sop(p.getName()+"~~"+p.getAge());
		}
		
	}
	//打印功能
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	//对元素存储信息操作封装
	private static Person setInfo(String name, int age)
	{
		Person p = new Person();
		p.setAge(age);
		p.setName(name);
		return p;
	}
}
class MyCompare implements Comparator
{
	public int compare(Object o1, Object o2)
	{
		if (!(o1 instanceof Person) || !(o2 instanceof Person))
			throw new RuntimeException();
		Person p1 = (Person)o1;
		Person p2 = (Person)o2;
		int num = p1.getName().compareTo(p2.getName());
		if (num==0)
			//return p1.getAge()-p2.getAge();
			return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
		return num;
	}
}

/*
练习题:
两个字符串按长度长短存入TreeSet集合中
要求:
1.使用自定义比较器
2.使用匿名内部类
*/

import java.util.*;
class TreeSetStringTest
{
	public static void main(String[] args)
	{
		TreeSet ts = new TreeSet(new Comparator(){
			public int compare(Object o1, Object o2)
			{
				if (!(o1 instanceof String) || !(o2 instanceof String))
					throw new RuntimeException("不是一个字符串");
				String str1 = (String)o1;
				String str2 = (String)o2;
				int num = new Integer(str1.length()).compareTo(str2.length());
				if (num==0)
					return str1.compareTo(str2);
				return num;
			}
		});
		
		ts.add("a");
		ts.add("abc");
		ts.add("ab");
		ts.add("aa");
		for (Iterator it = ts.iterator(); it.hasNext(); )
			sop(it.next());
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------详细请查看: http://edu.csdn.net