黑马程序员--集合(一)

黑马程序员--集合(一)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

集合类

一、概述

1、集合类:储存对象最常用的方式的方式之一。数据多了用对象存,对象多了用集合存。
集合类的特点:只用于存储对象,长度可变,可存储不同类型的对象。
PS:
集合类和数组都是容器,有何不同?
数组长度固定,且只能存相同类型的对象。
集合长度可变;数组可储存基本数据类型,集合只能储存对象。

2、集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
集合框架的优点:
简化程序设计;提高程序效率;提高API的使用效率;提高代码复用性。
集合框架的构成和分类:

二、Collection接口

框架的顶层-->Collection接口:
1、常见方法:
1.1添加:
boolean add(Object obj);
boolean addAll(Collection coll);
1.2删除
boolean remove(Object obj);
boolean removeAll(Collection coll);
void clear();
1.3判断
boolean contains(Object obj);
boolean containsAll(Collection coll);
boolean isEmpty();判读集合中是否有元素。
1.4获取
int size();
Iterator iterator():返回迭代器接口。
迭代器接口:对所有Collection容器进行元素取出的公共接口。
具体方法:
hasNext():若仍有元素可迭代,则返回true。
next():返回迭代的下一个元素。

remove():从迭代器指向的collection中移除迭代器返回的最后一个元素。

PS:
由于不同集合数据结构不同,造成每一个集合存取的方式可能不同。一般当我们需要多个动作(判断、取出)
才能完成一个动作的取出时,我们就将取出动作封装成一个对象。同时,因为其操作元素在集合中,
通过定义内部类,取出方式就可以直接访问集合内容元素。同时,我们将内部类都符合的取出方式规则定义在Iterator接口中,
通过iterator()方法获取。
1.5其他
boolean retainAll(Collection coll):取交集
Object toArray():将集合转成数组

import java.util.*;
/*
1.add方法的参数类型是Object.以便于接收任意类型对象。
2.集合中存储的都是对象的引用(地址)。
3.集合变数组。
Collection接口中的toArray方法。
3.1指定类型的数组到底要定义多长?
当指定类型的数组长度小于集合的size,那么该方法内部会创建一个新的数组。
当指定类型的数组长度大于集合的size,就不会创建一个新的数组。而是使用传递进来的数组。
所以创建一个刚刚好的数组内存处置最优。
3.2为什么要将集合变数组?
当不需要对集合元素增删时,可限定对元素的操作。因为数组长度固定。
*/
class CollectionDemo
{
	public static void main(String[] args)
	{
		base_method();
		other_method();
	}
	public static void base_method()
	{
		Collection col1 = new ArrayList();

		//添加元素
		col1.add("java01");
		col1.add("java02");
		col1.add("java03");
		sop("col1添加:"+col1);

		Collection col2 = new ArrayList();
		col2.addAll(col1);
		sop("col2添加:"+col2);		

		//删除元素
		sop("删除java02:"+col1.remove("java02"));
		col1.clear();
		sop("清空后集合"+col1);

		//判断元素
		sop("java03是否存在:"+col1.contains("java03"));
		sop("col2是否为空?"+col2.isEmpty());
		
		//获取
		sop("获取col2中元素个数:"+col2.size());
		//获取迭代器,取出集合中的元素。接口性引用只能指向自己的子对象。it随for循环结束而释放,更节省内存。
		for(Iterator it = col2.iterator();it.hasNext();)
		{
			System.out.print(it.next()+" ");
		}
		System.out.println();

		Collection col3 = new ArrayList();

		col3.add("java02");
		col3.add("java05");

		sop("col2:"+col2);
		
		//取交集,去除交集
		col3.retainAll(col2);
		sop("取交集:"+col3);

		col3.removeAll(col2);
		sop("移除相同元素:"+col3);
	}
	public static void other_method()
	{
		Collection<String> col4 = new ArrayList<String>();

		col4.add("abc1");
		col4.add("abc2");
		col4.add("abc3");

		//将集合转成数组
		String[] arr = col4.toArray(new String[col4.size()]);
		
		sop("集合转数组:"+Arrays.toString(arr));
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

2、List、Set接口

2.1 List接口
2.1.1 List常见方法:
这些方法有一个共性特点:都可以操作角标。
2.1.1.1 添加
void add(index,element);
void addAll(index,Collection);
2.1.1.2 删除
Object remove(index);
2.1.1.3 修改
Object set(index,element);
2.1.1.4 获取
Object get(index);
int indexOf(object);
int lastIndexOf(object);
List subList(form,to);//展现列表

import java.util.*;
class ListDemo
{
	public static void main(String[] args)
	{
		base_method();
	}
	public static void base_method()
	{
		List li = new ArrayList();

		//添加元素
		li.add("java01");
		li.add("java03");
		li.add("java03");
		
		sop("添加元素:"+li);

		//删除指定位置的元素
		li.remove(2);
		sop("被删除后的集合:"+li);	

		//修改元素
		li.set(1,"java02");
		sop("被修改后的集合"+li);

		li.add(2,"java02");
		sop("定点添加:"+li);

		//通过角标获取元素
		sop("get(1):"+li.get(1));

		//获取所有元素
		for(int x=0;x<li.size();x++)
		{
			System.out.print("li("+x+")="+li.get(x)+" ");
		}
		System.out.println();

		for(Iterator it = li.iterator();it.hasNext();)
		{
			System.out.print("next:"+it.next()+" ");
		}
		System.out.println();

		//通过indexOf获取对象的位置
		sop("index="+li.indexOf("java02"));
		sop("lastIndexOf:"+li.lastIndexOf("java02"));

		List sub = li.subList(0,3);
		sop("sub"+sub);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);		
	}
}
运行结果:

2.1.1.5 ListIterator接口
ListIterator接口是Iterator的子接口。它是List集合特有的迭代器。它只能通过listIterator()方法获取。
Iterator方法只能对元素进行判断、取出、删除的操作,当迭代器需要增加元素等操作时,必须通过集合的方法,
这是会出现并发访问异常,存在安全隐患。ListIterator接口扩展了Iterator接口功能。避免了混合使用集合问题。
ListIterator接口常见方法:
add();
hasNext():正向遍历; 
hasPrevious():逆向遍历; 
next():返回列表中下一个元素;
previous():返回列表中的前一个元素;
remove():移除元素;
set():替换。

//获取数据的方法有两种:迭代器和集合,当两种方式混合使用时,会发生-->并发访问异常。
import java.util.*;
class ListDemo2
{
	public static void main(String[] args) 
	{
		iterator_method();
	}
	public static void iterator_method()
	{
		//演示列表迭代器
		List li = new ArrayList();
		//添加元素
		li.add("java01");
		li.add("java02");	
		li.add("java03"); 
		sop("li="+li);
		
		//本例中,li是集合;it是迭代器。当两种方式访问同一数据时,会存在安全隐患。
		for(Iterator it = li.iterator();it.hasNext();)
		{
			//因为要判断的it.next()要==java02,所以obj(即it)为java01。
			Object obj = it.next();
			if(obj.equals("java02"))
				//因为迭代器只有移除方法,没有添加,所以需要借助集合的add()方法。
				li.add("java008"); 
				it.remove();
			//会输出java01,因为remove只移除了引用,对象还存在。
			sop("obj="+obj);
			sop("li="+li);
		}	
		sop(li);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:


/*
List定义了自己的迭代器接口:ListIterator()。避免Itetator接口中可使用方法较少,混合使用集合和迭代器的问题。
ListIterator是Iterator的子接口。该接口只能通过List集合的listIterator方法获取。
*/
import java.util.*;
class ListDemo3
{
	public static void main(String[] args) 
	{
		iterator_method();
	}
	public static void iterator_method()
	{
		//演示列表迭代器
		List li = new ArrayList();
		//添加元素
		li.add("java01");
		li.add("java03"); 
		li.add(1,"java02");	
		sop("li="+li);

		//其可以增、改、查的原因是它带角标。
		ListIterator lit = li.listIterator();
		
		//判断迭代前有没有元素	
		sop("hasPrevious():"+lit.hasPrevious());
		while(lit.hasNext())
		{
			Object obj = lit.next();
			
			//替换元素
			if(obj.equals("java02"))
				lit.set("java007");
		}
		//判断迭代后有没有元素
		sop("hasNext():"+lit.hasNext());
		sop("hasPrevious():"+lit.hasPrevious());	
		sop("li="+li);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

2.1.2List分类:
List:元素是有序的,元素可以重复。因为该集合体系有索引。
  |--Vector:底层是数组数据结构。线程同步。Vector生成20容量的数组,但是较浪费空间。被ArrayList替代。
  |--ArrayList:底层是数组数据结构。线程不同步。特点:查询块;增删慢。可变长度数组:超过10后,生成15容量的数组。
  |--LinkedList:底层使用的链表数据结构。特点:增删快;查询慢。

import java.util.*;
class LinkedListDemo
{
	public static void main(String[] args)
	{
		LinkedList link = new LinkedList();
	
		//先存的为尾
		link.addFirst("java01");
		link.addFirst("java02");
		link.addFirst("java03");

		sop("link="+link);

		sop("获取尾元素:"+link.getFirst());
		
		sop("获取头元素:"+link.getLast());

		sop("移除尾元素:"+link.removeFirst());

		sop("link="+link);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

JDK1.6后方法:

/*
使用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.pollLast();
	}
	public boolean isNull()
	{
		return link.isEmpty();
	}
}
class LinkedListTest
{
	public static void main(String[] args)
	{
		DuiLie dl = new DuiLie();

		dl.myAdd("java01");
		dl.myAdd("java02");
		dl.myAdd("java03");
		
		while(!dl.isNull())
		{
			System.out.print(dl.myGet()+" ");
		}
		System.out.println();
	}
}
运行结果:

PS:
Enumeration(枚举):是Vector特有的取出方式。枚举和迭代功能一样。

2.2 Set接口
Set接口中元素不可以重复,无序(存入和输出顺序不一定一致)。它的方法和Collection一致。

HashSet保证元素唯一性原理:判断元素的hashCode值是否相同。
如果元素的哈希值相同,才会判断对象内容是否相同。

PS:
1、判断元素是否存在,以及删除等操作,HashSet依赖的方法是元素的hashCode和equals方法;
而ArrayList只依赖equals方法。TreeSet保证元素唯一性的依据compareTo方法。
原因:数据结构不同,所依赖方法也不一样。
2、让HashSet无序变有序,可使用LinkedHashSet。 

import java.util.*;
/*
通过hashSet集合判断Person对象是否相同。姓名和年龄相同视为重复元素。
*/
class Person
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	//复写hashCode()
	public int hashCode()
	{
		//看hashCode的调用记录
		System.out.println(this.name+"....hashCode()");
		//字符串name有自己的hashCode值,排除和相同的情况
		return name.hashCode()+age*37;
	}	
	//复写equals	
	public boolean equals(Object obj)
	{		
		if(!(obj instanceof Person))
			return false;

		//向下转型。因为要使用Person自己的方法。
		Person p = (Person)obj;
		System.out.println(this.name+"...equals.."+p.name);

		return this.name.equals(p.name) && this.age == p.age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
}
class HashSetTest
{
	public static void main(String[] args) 
	{
		HashSet hs = new HashSet();

		hs.add(new Person("a1",11));
		hs.add(new Person("a2",12));
		hs.add(new Person("a3",13));
		hs.add(new Person("a4",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);
	}
}
运行结果:

2.2.1TreeSet排序
a 元素的自然顺序(默认顺序)。让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。
/*
需求:往TreeSet集合中存储自定义对象学生。按照学生的年龄进行排序。

注意:排序时,当主要条件相同时,一定判断一下次要条件。
Comparable是一个接口,用于强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。
compareTo():比较此对象与指定对象的顺序。返回负数、零、整数。
ClassCastException:类型转换异常。
*/
import java.util.*;
//Comparable接口强制让学生具备比较性
class Student implements Comparable
{
	private String name;
	private int age;

	Student(String name,int age)
	{
		this.name = name;
		this.age = age;
	}

	//复写compareTo()
	public int compareTo(Object obj)
	{
		if(!(obj instanceof Student))
			throw new RuntimeException("不是学生对象");
		Student s = (Student)obj;
		
		System.out.println(this.name+"...compareto..."+s.name);

		int temp = this.age-s.age;

		//有具体返回值可以用三元运算符,年龄相同,再按名字排。
		return temp==0?this.name.compareTo(s.name):temp;
	}

	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
}
class TreeSetDemo
{
	public static void main(String[] args)
	{
		TreeSet ts = new TreeSet();

		//所存元素必须具备比较性, TreeSet()才能排序。
		ts.add(new Student("lisi02",22));
		ts.add(new Student("lisi04",20));
		ts.add(new Student("lisi02",19));
		ts.add(new Student("lisi01",20));
	
		for(Iterator it = ts.iterator();it.hasNext();)
		{
			Student stu = (Student)it.next();//向下转型。
			System.out.println(stu.getName()+"..."+stu.getAge());
		}
	}
}
运行结果:

b 自定义比较器。让集合自身具备比较性:定义一个类,实现Comparator接口,覆盖compare方法。将该类对象
作为参数传递给TreeSet集合的构造函数。这种方法适用于:元素自身不具备比较性或不具备自己所需的比较性。
当两种方式都存在时,以比较器为主。

/*
练习:按照字符串长度排序。
自定义比较器:元素自身不具备比较性或不具备自己所需的比较性。
*/
import java.util.*;
class TreeSetTest
{	
	public static void main(String[] args)
	{
		TreeSet ts = new TreeSet(new StrLenComparator());

		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("z");
		ts.add("hahhaha");
	
		for(Iterator it = ts.iterator();it.hasNext();)
		{
			System.out.println(it.next());
		}
	}
}
//实现Comparator接口,覆盖compare方法。
class StrLenComparator implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		String s1 = (String)o1;	
		String s2 = (String)o2;	
		
		//String类的compareTo方法
		int num =new Integer(s1.length()).compareTo(new Integer(s2.length()));

		if(num==0)
			//主要条件符合,判断次要条件
			return s1.compareTo(s2);
		return num;
	}

}
运行结果:

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值