天天看点

Lesson_for_java_day13--java中的集合——Collection、List、ArrayList、LinkedList、Set、HashSet、TreeSet

一、Collection

数据多了用对象存,对象多了用集合存。

集合和数组一样,存储的都是地址。

集合类
	为什么出现集合类?
		面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对
			对象进行存储,集合就是存储对象最常用的一种方式。
			
	数组和集合类同是容器,有何不同?
		数组虽然也可以存储对象,但长度的固定的;集合长度是可变的。
		数组中可以存储基本数据类型,集合只能存储对象。
		
	集合类的特点?
		集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
		
	为什么会出现这么多容器(集合)呢?
		因为每个容器对数据的存储方式都不同。这个存储方式称之为:数据结构。
		
集合内数据获取:
	把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素。
		那么取出方式就定义成内部类。而每一个容器的数据结构不同,所以取出的动作
		细节也不一样,但是都有共性内容:判断和取出。那么可以将共性抽取。
		那么这些内部类都符合一个规则,该规则是Iterator。如何获取集合的取出对象呢:
		通过一个对外提供的方法:interator();
		
什么的类集框架?
	1、类集框架是一组类和接口;
	2、位于java.util包中;
	3、主要用于用户存储和管理对象;
	4、主要分为三大类:集合、列表和映射
	
什么是集合(Set):集合中的对象不按特定的方式排序,并且没有重复对象。

什么是列表(List):集合中对象按照索引位置排序,可以有重复的对象。

什么是映射(Map):集合中的每一个元素包含一个键对象和一个值对象,键不可以重复,值可以重复。
	
           

代码:

package collection;
/*
1、add方法的参数类型是object,以便接收任意类型的对象。
2、集合中存储的都是对象的引用(地址)

什么是迭代器:
	其实就是集合的取出元素的方式。
	
collection:
	--List:元素是有序的,元素是可以重复的。因为该集合体系有索引。
		--ArrayList:底层的数据结构使用的是数组结构。
			特点:查询、修改速度很快,但是增加、删除稍慢。
				线程不同步。java1.2版本出现。
		--LinkedList:底层使用的是链表数据结构。
			特点:增加、删除速度很快,但是查询、修改稍慢。
		--Vector:底层使用的是数组数据结构。线程同步,增删改查速度慢。
			java1.0版本出现。被ArrayList替代。
		
	--Set:元素是无序的,元素是不可以重复的,集合中没有索引。
*/

import java.util.ArrayList;
import java.util.Iterator;

class CollectionDemo{
	public static void main(String[] args){
		//method_1();
		//method_2();
		method_get();	
	}
	
	public static void method_get(){
		ArrayList<Object> al = new ArrayList<Object>();
		al.add("java01");//add(obj);
		al.add("java02");
		al.add("java03");
		al.add("java04");
		
		//sop(al);
		
		/*//获取迭代器,用于取出集合中的元素
		Iterator it = al.iterator();
		while(it.hasNext()){
			sop(it.next());
		}
		*/
		for(Iterator<Object> it = al.iterator(); it.hasNext();){
			sop(it.next());
		}
	}
	
	public static void method_2(){
		//创建一个集合容器,使用collection接口的子类。ArrayList
		ArrayList<String> al1 = new ArrayList<String>();
		al1.add("java01");//add(obj);
		al1.add("java02");
		al1.add("java03");
		al1.add("java04");
		
		ArrayList<String> al2 = new ArrayList<String>();
		al2.add("java01");//add(obj);
		al2.add("java02");
		al2.add("java05");
		al2.add("java06");
		
		//取交集,al1中只会保留和al2中相同的元素
		al1.retainAll(al2);
		sop("al1:" + al1);
		sop("al2:" + al2);

		//al1.removeAll(al2);
	}
	
	public static void method_1(){
		//创建一个集合容器,使用collection接口的子类。ArrayList
		ArrayList<String> al = new ArrayList<String>();
		
		//1、添加元素
		al.add("java01");//add(obj);
		al.add("java02");
		al.add("java03");
		al.add("java04");
		
		//打印原集合
		sop(al);
		
		//3、删除元素
		al.remove("java02");
		
		//2、获取个数。集合长度
		sop("size:" + al.size());
		
		//打印移除后集合
		sop(al);
			
		//4、判断元素
		sop("java03是否存在:" + al.contains("java03"));
		sop("集合是否为空:" + al.isEmpty());
		
		//清空集合
		al.clear();
	}
	
	//输出对象
	public static void sop(Object obj){
		System.out.println(obj);
	}
}
           

二、List

package collection.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/*
collection:
	--List:元素是有序的,元素是可以重复的。因为该集合体系有索引。
		--ArrayList:底层的数据结构使用的是数组结构。
			特点:查询、修改速度很快,但是增加、删除稍慢。
				线程不同步。java1.2版本出现。
		--LinkedList:底层使用的是链表数据结构。
			特点:增加、删除速度很快,但是查询、修改稍慢。
		--Vector:底层使用的是数组数据结构。线程同步,增删改查速度慢。
			java1.0版本出现。被ArrayList替代。
		
	--Set:元素是无序的,元素是不可以重复的,集合中没有索引。
	
List:
	特有方法:凡是可以操作角标的方法都是改体系特有的方法。
	
	增:add(index,element);
		assAll(index,collection);
	删:remove(index);
	改:set(index,element);
	查:get(index);
		subList(from,to);
		listItetator();
	
List集合特有的迭代器。ListIterator是Iterator的子接口。

在迭代时。不可以通过集合对象的方法操作集合中的元素。因为会发生
	ConcurrentModificationException异常。
	所以,在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,
	只能对元素进行判断、取出和删除操作,如果想要其他操作如添加、修改等,就需要
	使用其子接口ListIterator
	
	该接口只能通过List集合的Iterator方法获取。
*/

class ListDemo{
	public static void main(String[] args){
		//演示列表迭代器
		ArrayList<String> al = new ArrayList<String>();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		
		//在迭代过程中,准备添加后删除元素
		ListIterator<String> li = al.listIterator();
		while(li.hasNext()){
			Object obj = li.next();
			if(obj.equals("java02"))
				//li.add("java009");//添加
				li.set("java006");//替换
		}
		sop("hasNext:" + li.hasNext());//正向判断
		sop("hasPrevious:" + li.hasPrevious());//逆向判断

		sop(al);	
	}
	
	public static void method_1(){
		ArrayList<String> al = new ArrayList<String>();
		
		//添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");
		
		sop("原集合是:" + al);
		//在指定位置添加元素
		al.add(1,"java09");
		sop("添加元素后集合:" + al);
		
		//删除指定位置的元素
		al.remove(2);
		sop("删除元素后集合:" + al);
		
		//修改元素
		al.set(2,"java007");
		sop("修改元素后集合:" + al);

		//通过角标获取元素
		sop("get(1):" + al.get(1));
		
		//获取所有元素
		for(int x = 0; x < al.size(); x++){
			System.out.println("al(" + x + ")=" + al.get(x) );
		}
		
		//用迭代器获取元素
		for(Iterator<String> it = al.iterator(); it.hasNext();){
			sop("next:" + it.next());
		}
		
		//通过index获取对象的位置
		sop("index" + al.indexOf("java02"));
		
		//获取子串
		List<String> sub = al.subList(1,3);
		sop("sub=" + sub);	
	}
	
	//封装打印对象
	public static void sop(Object obj){
		System.out.println(obj);
	}
}
           

====ArrayList===

练习一:

package collection.list;
import java.util.ArrayList;
import java.util.Iterator;

/*
练习:
	去除ArrayList集合中的重复元素
*/

class ArrayListTest{
	public static void main(String[] args){
		ArrayList<Object> al = new ArrayList<Object>();
		al.add("java01");
		al.add("java02");
		al.add("java01");
		al.add("java03");
		al.add("java02");
		al.add("java04");
		
		/*
		在迭代时,循环中的next调用一次,就要hasNext判断一次。
		Iterator it = al.iterator();
		while(it.hasNext()){// 判断一次hasNext,使用两次next,可能出现元素不存在异常。
			sop(it.next() + "......." + it.next());
		}
		*/
		sop(al);
		al = singleElement(al);
		sop(al);
	}
	
	public static ArrayList<Object> singleElement(ArrayList<Object> al){//去除重复元素
		//定义一个临时容器
		ArrayList<Object> newAl = new ArrayList<Object>();
		Iterator<Object> it = al.iterator();
		while(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);
	}
}
           

练习二:

package collection.list;

/*
练习:(重要)
	将自定义对象作为元素存到ArrayList集合中,并去除重复元素
		比如:存人对象。同姓名同年龄的视为同一个人,为重复对象。
		
思路:
	1、对人描述,将数据封装进人对象。
	2、定义容器,将人存入。
	3、取出。
	4、去除重复对象。
	
*******List集合判断元素是否相同,依据的是元素的equals方法。**********
*/


import java.util.*;

class ArrayListTest2{
	public static void main(String[] args){
		ArrayList<Object> al = new ArrayList<Object>();//创建一个集合
		al.add(new Person("lisi01",30));//集合中添加对象
		al.add(new Person("lisi02",30));
		al.add(new Person("lisi03",30));
		al.add(new Person("lisi01",30));
		al.add(new Person("lisi02",35));
		al.add(new Person("lisi04",30));
		
		System.out.println("---------去除重复对象前--------------");
		sopArrayList(al);
		
		System.out.println("---------去除重复对象后--------------");
		al = singleElement(al);
		sopArrayList(al);
		
		System.out.println("---------移除一个元素--------------");
		//调用Person的equals方法,判断移除元素是否与集合内元素相同
		al.remove(new Person("lisi04",30));
		sopArrayList(al);
	}
	
	//打印集合中对象的内容
	public static void sopArrayList(ArrayList<Object> al){
		Iterator<Object> it = al.iterator();
		while(it.hasNext()){
			Person p = (Person)it.next();//向下转型
			sop(p.getName() + "......" + p.getAge());
		}
	}
	
	//打印对象
	public static void sop(Object obj){
		System.out.println(obj);
	}
	
	//去除集合内重复的对象元素
	public static ArrayList<Object> singleElement(ArrayList<Object> al){
		//定义一个临时容器
		ArrayList<Object> newAl = new ArrayList<Object>();
		Iterator<Object> it = al.iterator();
		while(it.hasNext()){//遍历集合中的对象。
			Object obj = it.next();
			if(!newAl.contains(obj))//依据对象的equals方法进行判断
				newAl.add(obj);
		}
		return newAl;
	}
}

//创建一个Person类
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;
	}
	
	//覆写equals方法,判断对象是否相同
	public boolean equals(Object obj){
		if(!(obj instanceof Person))//判断对象是否是Person类对象
			return false;
		Person p = (Person)obj;//向下转型
		return this.name.equals(p.name) && this.age == p.age;
	}
}
           

===LinkedList===

package collection.list;

import java.util.LinkedList;


/*
LinkedList特有方法:
	addFirst();
	addLast();
		作为第一个(最后一个)元素,添加到集合中
		
	getFirst();
	getLast();
		获取元素,但不删除元素。会出现NoSuchElementException
		
	removeFirst();
	removeLast();
		获取元素,并删除元素。如果集合中没有元素,会出现NoSuchElementException
		
在JDK1.6出现了替换方法:
	offerFirst();
	offerLast();
		作为第一个(最后一个)元素,添加到集合中
		
	peekFirst();
	peekLast();
		获取元素,但不删除元素。如果集合中没有元素,会返回null
		
	pollFirst();
	pollLast();
		获取元素,并删除元素。如果集合中没有元素,会返回null
	
*/
class LinkedListDemo{
	public static void main(String[] args){
		LinkedList<Object> link = new LinkedList<Object>();
		link.addFirst("java01");
		link.addFirst("java02");
		link.addFirst("java03");
		link.addFirst("java04");		
		sop(link);
	
		
		
	}
	
	public static void sop(Object obj){
		System.out.println(obj);
	}
}
           

练习:

package collection.list;

import java.util.LinkedList;

/*

---------------------必须掌握(重要)-----------------------------

练习:使用LinkedList模拟一个堆栈或者队列数据结构

堆栈:先进后出   如同一个杯子
队列:先进先出   First in, First out FIFO如同一个水管
*/


class LinkedListTest{
	public static void main(String[] args){
		Queue dl = new Queue();
		dl.myAdd("java01");//作为第一个元素添加到集合中
		dl.myAdd("java02");
		dl.myAdd("java03");
		dl.myAdd("java04");
		
		while(!dl.isNull())
			System.out.println(dl.myGet());//获取最后一个元素
	}
}

class Queue{
	private LinkedList<Object> link;
	
	Queue(){//生成一个链表对象
		link = new LinkedList<Object>();
	}
	
	public void myAdd(Object obj){//作为第一个元素添加
		link.addFirst(obj);
	}
	
	public Object myGet(){//获取最后一个元素,并移除
		return link.removeLast();
	}
	public boolean isNull(){//判断集合是否为空
		return link.isEmpty();
	}
}
           

===Vector===

package collection.list;

import java.util.Enumeration;
import java.util.Vector;


/*
枚举就是vector特有的取出方式。
发现枚举和迭代器很像。其实枚举和迭代是一样的。

因为枚举的名称以及方法的名称都过长,所以枚举被迭代器取代了。
枚举就郁郁而终了。
*/


class VectorDemo{
	public static void main(String[] args){
		Vector<String> v = new Vector<String>();
		v.add("java01");
		v.add("java02");
		v.add("java03");
		v.add("java04");
		
		Enumeration<String> en = v.elements();
		
		while(en.hasMoreElements()){
			System.out.println(en.nextElement());
		}
		
	}
}
           

三、Set

===HashSet===

package set;

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

/*
|--Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
	|-HashSet:底层数据结构是哈希表。
			  HashSet是如何保证元素唯一性的呢?
				是通过元素的两个方法,hashCode和equals来完成的。
				如果元素的HashCode值相同,才会判断equals是否为true。
				如果元素的HashCode值不同,就不会调用equals方法。
				
			  注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素
				的hashCode和equals方法。先判断hashCode方法,如果相同再判断equals方法。
				
	|-TreeSet:可以对set集合中的元素进行排序。
	
Set集合的功能和Collection是一致的。

*/


public class HashSetDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet<String> hs = new HashSet<String>();
		
		hs.add("java04");//添加元素
		hs.add("java05");
		System.out.println(hs.add("java01"));//添加元素,并打印元素是否存在的值
		hs.add("java02");
		hs.add("java03");
		hs.add("java03");
		System.out.println(hs.add("java01"));//元素已经存在,打印出false
		
		
		for(Iterator<String> it = hs.iterator(); it.hasNext();){//遍历集合
			System.out.println(it.next());
		}
	}

}
           

练习:

package set;

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

/*
练习:
	往HashSet集合中存入自定义对象(人对象)
		姓名和年龄相同视为同一个人,为重复元素。
		
	HashSet是如何保证元素唯一性的呢?
		是通过元素的两个方法,hashCode和equals来完成的。
		如果元素的HashCode值相同,才会判断equals是否为true。
		如果元素的HashCode值不同,就不会调用equals方法。
				
*/

class HashSetTest{
	public static void main(String[] args){
		//创建HashSet集合
		HashSet<PersonHashSet> hs = new HashSet<PersonHashSet>();
		sop("\n---------添加元素-----------");
		hs.add(new PersonHashSet("a1",11));
		hs.add(new PersonHashSet("a2",12));
		hs.add(new PersonHashSet("a3",13));
		hs.add(new PersonHashSet("a4",14));
		
		sop("\n---------重复添加一个元素-----------");
		hs.add(new PersonHashSet("a2",12));
		
		//判断是否包含一个元素
		sop("\n---------是否包含一个指定元素-----------");
		sop(hs.contains(new PersonHashSet("a4",14)));
		
		//移除一个元素
		sop("\n---------移除一个元素-----------");
		hs.remove(new PersonHashSet("a3",13));
		
		sop("\n---------打印集合中的元素-----------");
		for(Iterator<PersonHashSet> it = hs.iterator(); it.hasNext();){//遍历集合
			PersonHashSet p = (PersonHashSet)it.next();
			sop(p.getName() + "......" + p.getAge());
		}	
	}
	
	public static void sop(Object obj){//打印对象
		System.out.println(obj);
	}
}


//创建一个Person类
class PersonHashSet{
	private String name;
	private int age;
	PersonHashSet(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	public String getName(){
		return name;
	}
	
	public int getAge(){
		return age;
	}
	
	//覆写HashCode方法,判断对象是否相同,如果HashCode相同,再判断equals方法
	public int hashCode(){
		System.out.println(this.name + "-------hashCode");//测试哪个对象调用hashCode方法
		return name.hashCode() + age*39;
	}
	
	//覆写equals方法,判断对象是否相同
	public boolean equals(Object obj){
		if(!(obj instanceof PersonHashSet))//判断对象是否是Person类对象
			return false;
		PersonHashSet p = (PersonHashSet)obj;//向下转型
		//测试哪个对象调用equals方法,并和哪个对象做比较
		System.out.println(this.name + "----equals---" + p.name);
		return this.name.equals(p.name) && this.age == p.age;
	}
}
           

===TreeSet===

package set;

import java.util.Iterator;
import java.util.TreeSet;
/*
|--Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
	|-HashSet:底层数据结构是哈希表。
			  HashSet是如何保证元素唯一性的呢?
				是通过元素的两个方法,hashCode和equals来完成的。
				如果元素的HashCode值相同,才会判断equals是否为true。
				如果元素的HashCode值不同,就不会调用equals方法。
				
			  注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素
				的hashCode和equals方法。先判断hashCode方法,如果相同再判断equals方法。
				
	|-TreeSet:底层数据结构是二叉树。可以对set集合中的元素进行排序。
				二叉树是保证元素唯一性的依据。
				用compareTo方法的返回值判断大小。
				
				TreeSet排序:
					第一种方式:让元素自身具备比较性。元素需要实现comparable接口,
						覆盖compareTo方法。这种方式也成为元素的自然顺序或默认顺序。
					第二种方式:当元素自身不具备比较性时,或者具备的比较性不是需要的时候,
						需要让集合自身具备比较性。
						在集合一初始化时,就有了比较方式。
						
Set集合的功能和Collection是一致的。

记住:排序时当主要条件相同时一定要判断次要条件。

练习:
	需求:(第一种排序方式)
		往TreeSet集合中存储自定义对象学生。
		按照学生年龄进行排序。
*/
public class TreeSetDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		TreeSet<Student> ts = new TreeSet<Student>();
		ts.add(new Student("张三",26));
		ts.add(new Student("李四01",23));
		ts.add(new Student("王五",20));
		ts.add(new Student("李四02",23));//年龄相同时,比较姓名
		ts.add(new Student("小王",20));
		ts.add(new Student("王五",20));//重复元素不会重新存储
		
		for(Iterator<Student> it = ts.iterator(); it.hasNext();){//遍历集合
			Student s = (Student)it.next();
			System.out.println(s.getName() + "-----" + s.getAge());
		}
	}
}


//实现compareable接口,该接口强制让对象具备比较性
class Student implements Comparable<Object>{
	private String name;
	private int age;
	
	Student(String name,int age){
		this.setName(name);
		this.setAge(age);
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
	//覆写compareTo方法,定义按年龄排序的方法
	public int compareTo(Object o) {
		
		if(!(o instanceof Student))//判断是否是相同类,不是相同类抛异常
			throw new RuntimeException("输入的类不是Student类");
		Student s = (Student)o;
//		System.out.println(this.name + "-----compareTo------" + s.name);
		if(this.age > s.age)
			return 1;
		//如果年龄相同,按照姓名进行排序。字符串本身有自带的compareTo方法。
		if(this.age == s.age){
			return this.name.compareTo(s.name);
		}
		return -1;
			
	}
}
           
package set;

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


/*
 * 当元素自身不具备比较性,或者具备的比较性不是所需要的,这时就需要让容器自身具备比较性。
 * 
 * 思路:
 * 		1、定义一个类,实现comparator接口,并覆盖compare方法,做为比较器。
 * 		2、定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
 * 
 * 练习:(第二种排序方式)
 * 		需求:
 * 			1、往TreeSet集合中存储自定义对象学生。
			2、按照学生年龄进行排序。
			3、现在需求改变,需要按照姓名来排序,但又不能修改原有的排序代码
			
 * 注意:当两种排序都存在时,以比较器为主。
 * 
 * 
 */
public class TreeSetDemo2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		//将比较器作为参数传递给集合
		TreeSet<Student> ts = new TreeSet<Student>(new MyCompare());
		ts.add(new Student("李四01",26));
		ts.add(new Student("李四04",23));
		ts.add(new Student("李四02",20));
		ts.add(new Student("李四02",23));//姓名相同,比较年龄
		ts.add(new Student("李四03",20));
		ts.add(new Student("李四04",23));//对象重复,不会添加
		
		for(Iterator<Student> it = ts.iterator(); it.hasNext();){//遍历集合
			Student s = (Student)it.next();
			System.out.println(s.getName() + "-----" + s.getAge());
		}
	}
}

//自定义比较器
class MyCompare implements Comparator<Object>{

	public int compare(Object o1, Object o2) {
		Student s1 = (Student)o1;
		Student s2 = (Student)o2;
		int num = s1.getName().compareTo(s2.getName());
		if(num == 0){
			return s1.getAge()-s2.getAge();//这种方法也可行
			//调用Integer类是compareTo方法
			//return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		}
		return num;
	}
}
           

练习:

package set;

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


/*
	练习:
		按照字符串长度排序
	思路:字符串本身具备比较性,但是它的比较方式不是所需要的,这时就只能使用比较器
 */
public class TreeSetTest {

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeSet<String> ts = new TreeSet<String>(new StringLengthComparator());
		ts.add("abcd");
		ts.add("abd");
		ts.add("cd");
		ts.add("d");
		ts.add("adbcd");
		ts.add("aacd");
		
		for(Iterator<String> it = ts.iterator(); it.hasNext();){//遍历集合
			System.out.println(it.next());
		}
	}
}

class StringLengthComparator implements Comparator<Object>{

	public int compare(Object o1, Object o2) {
		String s1 = (String)o1;
		String s2 = (String)o2;
		int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if(num == 0) 
			return s1.compareTo(s2);
		return num;
	}

		
}


           

继续阅读