java----集合类

集合类
一、集合类
疑问为什么会出现集合类?
:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储。集合就是存储对象最常用的一种方式。
疑问数组和集合类都是容器,有何不同?
:数组当然也可以存储对象,但长度是固定的。集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象
集合的特点:集合用于存储对象,长度是可变的,可以存储不同类型的对象。
集合框架

疑问为什么会出现这么多容器呢?
:因为每个容器对数据的存储方式都不同。这个存储方式称为——数据结构
import java.util.*;
class Demo
{
	public static void main(String args[]){
		//创建一个集合容器,使用Collection的子类ArrayList
		ArrayList al = new ArrayList();
		//添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//获取集合长度
		System.out.println(al.size());
	}
}

:出现了安全隐患提示,但是不影响运行。

集合的存储
import java.util.*;
class Person
{
	private String name;
	private int age;
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public void show(){
		System.out.println("name = "+name+",age = "+age);
	}
}
class Demo{
	public static void main(String []args){
		Person p = new Person("zhangsan",20);
		ArrayList al = new ArrayList();
		al.add(p);
	}
}
分析:图解

分析
1.add方法的参数类型是Object,以便于接收任意类型对象。
2.集合中存储的都是对象的引用(地址)和数组一样。
删除元素
import java.util.*;
class Demo
{
	public static void main(String args[]){
		//创建一个集合容器,使用Collection的子类ArrayList
		ArrayList al = new ArrayList();
		//添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//删除前打印
		System.out.println("删除前:"+al);
		//删除元素
		al.remove("java02");
		//al.clear();
		System.out.println("删除后:"+al);
	}
}

判断元素
import java.util.*;
class Demo
{
	public static void main(String args[]){
		//创建一个集合容器,使用Collection的子类ArrayList
		ArrayList al = new ArrayList();
		//添加元素
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//判断
		System.out.println("java03是否存在:"+al.contains("java03"));
		System.out.println("集合是否为空:"+al.isEmpty());
	}
}

取交集
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al1 = new ArrayList();
		al1.add("java01");
		al1.add("java02");
		al1.add("java03");
		al1.add("java04");

		ArrayList al2 = new ArrayList();
		al2.add("java01");
		al2.add("java03");
		al2.add("java06");
		
		//取交集,al1中只会保留与al2中相同的元素
		al1.retainAll(al2);
		System.out.println("al1 : "+al1);
		System.out.println("al2 : "+al2);
	}
}

去除两集合相同元素
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al1 = new ArrayList();
		al1.add("java01");
		al1.add("java02");
		al1.add("java03");
		al1.add("java04");

		ArrayList al2 = new ArrayList();
		al2.add("java01");
		al2.add("java03");
		al2.add("java06");
		
		//移除包含的al2中的所有元素
		al1.removeAll(al2);
		System.out.println("al1 : "+al1);
		System.out.println("al2 : "+al2);
	}
}

元素的取出(重点):
迭代器:Iterator接口。
疑问神马是迭代器呢?
:其实就是集合的取出元素的方式。
迭代器原理:把取出方式定义在了集合的内部,这样取出方式就可以直接访问集合内的元素,那么取出方式就被定义成了内部类。而每个容器的数据结构不同,所以取出的动作细节也不一样,但都有共性:判断和取出,那么可以将这些共性抽取,就形成了Iterator接口。
疑问如何获取集合中的对象呢?
:通过一个对外提供的方法iterator();
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//获取迭代器对象
		Iterator it = al.iterator();
		//判断是否有元素
		while(it.hasNext()){
			//因为返回的是Object类型,所以要强制转换成String类
			String s = (String)it.next();
			System.out.println(s);
		}
	}
}

国外的写法
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//放到for循环中,局部变量用完后就会被垃圾回收,节省了空间。
		for(Iterator it = al.iterator();it.hasNext();){
			String s = (String)it.next();
			System.out.println(s);
		}
	}
}
Collection
|——List:元素是有序的,元素可以重复,因为该集合体系有索引。
|——Set:元素是无序的,元素不可以重复。
List特有方法:凡是可以操作角标的方法都是该体系特有的方法。
void add(int index, E element);在列表的指定位置插入指定元素(可选操作)。
boolean addAll(int index, Collection<? extends E> c);将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。 
E remove(int index);移除列表中指定位置的元素(可选操作)。 

E set(int index, E element);用指定元素替换列表中指定位置的元素(可选操作)。
E set(int index, E element);用指定元素替换列表中指定位置的元素(可选操作)。
List<E> subList(int fromIndex, int toIndex);返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
ListIterator<E> listIterator(int index);返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
采用for循环:
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		for(int x=0;x<al.size();x++){
			String s = (String)al.get(x);
			System.out.println(s);
		}
	}
}
采用Iterator
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		for(Iterator it = al.iterator();it.hasNext();){
			String s = (String)it.next();
			System.out.println(s);
		}
	}
}
列表迭代器ListIterator
练习:在迭代过程中,添加或者删除元素。
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//放到for循环中,局部变量用完后就会被垃圾回收,节省了空间。
		for(Iterator it = al.iterator();it.hasNext();){
			Object obj = it.next();
			if(obj.equals("java02")){
				al.add("java08");//添加
				//al.remove("java01");//删除
			}
			System.out.println(obj);
		}
	}
}

分析:发生了ConcurrentModificationException并发修改异常,产生原因在Iterator操作元素时,ArrayList也操作元素。
解决办法:要么使用迭代器的方法,要么使用集合的方法。
发现Iterator里没有添加操作,所以使用其子类ListIteratorList集合特有的迭代器ListIteratorIterator的子接口。在迭代时,不可以通过集合对象的方法操作集合的元素,因为会发生并发修改异常,所以在迭代时,只能用迭代器的方法操作元素。可是Iterator方法是有限的,不能对元素进行判断,取出,删除的操作。如果想要其他的操作如:添加,修改等,就需要使用其子接口ListIterator。该接口只能通过List集合的listIterator();方法获取。
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		//放到for循环中,局部变量用完后就会被垃圾回收,节省了空间。
		for(ListIterator it = al.listIterator();it.hasNext();){
			Object obj = it.next();
			if(obj.equals("java02")){
				it.add("java08");//添加
				//it.remove();//删除
			}
		}
		System.out.println(al);
	}
}

ArrayList:底层的数据结构使用的是数组结构。查询速度很快,但是增删速度稍慢。线程不同步,默认是10个长度,50%延长。
LinkedList:底层的数据结构使用是链表数据结构。增删速度很快,但是查询速度稍慢。(面试)
Vector:底层的数据结构使用是数组结构。1.0版本之后出现。线程同步。被ArrayList替代。100%延长。
数组结构

链表结构

最常用到的集合:
List:ArrayList,LinkerList
Set:HashSet
Map:HashMap
练习:Vector
import java.util.*;
class Demo
{
	public static void main(String args[]){
		Vector v = new Vector();
		v.add("java01");
		v.add("java02");
		v.add("java03");
		v.add("java04");
		Enumeration e = v.elements();
		while(e.hasMoreElements()){
			Object obj = e.nextElement();
			System.out.println(obj);
		}
	}
}
发现:枚举和迭代器很像。其实枚举和迭代器是一样的,因为枚举的名称及方法的名称都过长,所以别迭代器取代了。枚举郁郁而终。
LinkedList特有方法:
void addFirst(E e);将指定元素插入此列表的开头。
void addLast(E e);将指定元素添加到此列表的结尾。
E removeFirst();移除并返回此列表的第一个元素。
E removeLast();移除并返回此列表的最后一个元素。
E getFirst();返回此列表的第一个元素。
E getLast();返回此列表的最后一个元素。
import java.util.*;
class Demo
{
	public static void main(String args[]){
		LinkedList v = new LinkedList();
		v.removeFirst();
	}
}

分析:当集合为空时,调用removeFirst();NoSuchElementException没有这个的元素异常。
解决办法:1.6版本后,出现了pollFirst();获取并移除此列表的第一个元素,如果此列表为空,在返回null
import java.util.*;
class Demo
{
	public static void main(String args[]){
		LinkedList v = new LinkedList();
		v.pollFirst();
	}
}
1.6版本后出现的替代方法
boolean offerFirst(E e);在此列表的开头插入指定的元素。
boolean offerLast(E e);在此列表末尾插入指定的元素。
E peekFirst();获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
E peekLast();获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
获取元素,但不删除元素。如果集合没有元素,会返回null
E pollFirst();获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
E pollLast();获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
获取元素,但元素被删除。如果集合没有元素,会返回null
练习LinkedList模拟一个堆栈或者队列数据结构。
堆栈:先进后出。
import java.util.*;
class DuiZhan
{
	private LinkedList ll;
	DuiZhan(){
		ll = new LinkedList();
	}
	public void myAdd(Object obj){
		ll.offerFirst(obj);
	}
	public Object myGet(){
		return ll.pollFirst();
	}
	public boolean isNull(){
		return ll.isEmpty();
	}
}
class Demo
{
	public static void main(String args[]){
		DuiZhan dz = new DuiZhan();
		dz.myAdd("java01");
		dz.myAdd("java02");
		dz.myAdd("java03");
		dz.myAdd("java04");
		while(!dz.isNull()){
			System.out.println(dz.myGet());
		}
	}
}

队列:先进先出。
import java.util.*;
class DuiLie
{
	private LinkedList ll;
	DuiLie(){
		ll = new LinkedList();
	}
	public void myAdd(Object obj){
		ll.offerFirst(obj);
	}
	public Object myGet(){
		return ll.pollLast();
	}
	public boolean isNull(){
		return ll.isEmpty();
	}
}
class Demo
{
	public static void main(String args[]){
		DuiLie dl = new DuiLie();
		dl.myAdd("java01");
		dl.myAdd("java02");
		dl.myAdd("java03");
		dl.myAdd("java04");
		while(!dl.isNull()){
			System.out.println(dl.myGet());
		}
	}
}

练习:去除ArrayList集合中的重复元素。
import java.util.*;
class Demo
{
	public static void main(String args[]){
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java03");
		al.add("java04");
		al.add("java04");
		System.out.println(singleElement(al));
	}
	public static ArrayList singleElement(ArrayList al){
		ArrayList newAl = new ArrayList();
		Iterator it = al.iterator();
		while(it.hasNext()){
			Object obj = it.next();
			if(!newAl.contains(obj))
				newAl.add(obj);
		}
		return newAl;
	}
}

ArrayListLinkedList的选择:查询多用ArrayList,修改多用LinkedList
Set
|——HashSet:底层数据结构是哈希表。
疑问HashSet是如何保证元素唯一性的呢?
:是通过元素的两个方法:hashCode();equals();来完成的,如果元素的hashCode相同,才会判断equals是否为true。如果元素的hashCode值不同,不会调用equals
注:对于判断元素是否存在,以及删除元素等操作依赖的方法是元素的hashCodeequals方法。ArrayList只依赖equalsHashSet先判断hashCode再判断equals
练习:往HashSet集合中存入自定义对象,姓名和年龄相同为同一个人。
import java.util.*;
class Person
{
	private String name;
	private int age;
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public void show(){
		System.out.println("name = "+name+",age = "+age);
	}
	public int hashCode(){
		System.out.println("hashCode run "+name);
		return 60;
	}
	public boolean equals(Object obj){
		Person p = (Person)obj;
		System.out.println("equals run "+name+"::"+p.name);
		return name.equals(p.name)&&age==p.age;
	}
}
class Demo
{
	public static void main(String args[]){
		HashSet hs = new HashSet();
		System.out.println(hs.add(new Person("zhangsan",20)));
		System.out.println(hs.add(new Person("wangwu",18)));
		System.out.println(hs.add(new Person("wangwu",18)));
	}
}

分析:可以看到,当hashcode相同时,集合开始调用对象的equals方法进行比较。可见HashSet会先判断hashCode值,如果相同则再对equals进行判断。
改进:为了减少判断次数,提高效率,可以对hashcode方法进行复写。
import java.util.*;
class Person
{
	private String name;
	private int age;
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public void show(){
		System.out.println("name = "+name+",age = "+age);
	}
	public int hashCode(){
		System.out.println("hashCode run "+name);
		return name.hashCode()+age*31;
	}
	public boolean equals(Object obj){
		Person p = (Person)obj;
		System.out.println("equals run "+name+"::"+p.name);
		return name.equals(p.name)&&age==p.age;
	}
}
class Demo
{
	public static void main(String args[]){
		HashSet hs = new HashSet();
		System.out.println(hs.add(new Person("zhangsan",20)));
		System.out.println(hs.add(new Person("wangwu",18)));
		System.out.println(hs.add(new Person("wangwu",18)));
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值