黑马程序员——Java基础---集合框架

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

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

Java中集合类的关系图
黑马程序员——Java基础---集合框架_第1张图片

第二讲   Collection
Collection接口有两个子接口:List(列表),Set(集)
List:可存放重复元素,元素存取是有序的。
Set:不可以存放重复元素,元素存取是无序的。

一、Collection接口中常见的操作
1、添加
add(e);
addAll(collection);
2、删除
remove(e);
removeAll(collection);
clear();
3、判断
contains(e);
isEmpty();
4、获取
iterator();
size();
5、获取交集
retainAll();
6、集合变数组
toArray();
二、迭代
1、概述
迭代是取出集合中元素的一种方式。
对于集合的元素取出这个动作:
当不足以用一个函数来描述,需要用多个功能来体现,所以就将取出这个动作封装成一个对象来描述。就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合
内部的元素。那么取出方式就被定义成了内部类。而每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都具有共性内容: 判断和取出。那么就可以将这些共性抽取。
那么这些内部类都符合一个规则(或者说都抽取出来一个规则)。该规则就是Iterator。通过一个对外提供的方法:iterator();,来获取集合的取出对象。
因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
2、迭代的常见操作:
hasNext();    //有下一个元素,返回真
next();    //取出下一个元素
remove();    //移除
注:在迭代循环中next()调用一次,就要用hasNext()判断一次。
使用:
ArrayList list = new ArrayList(); //创建一个集合
Iterator it = list .iterator();    //获取迭代器,用于取出集合中的元素。
第一种打印方式:
for(Iterator it = al.iterator(); it.hasNext() ; )
{
System.out.println(it.next());
}
第二种打印方式:
while(it.hasNext())
{
System.out.println(it.next());
}
3、迭代注意的事项:
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。
迭代器的next方法返回值类型是Object,所以要记得类型转换。


第三讲 List
一、List
组成:
List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
二、List的特有方法
凡是可以操作角标的方法都是该体系特有的方法。
1、增
add(index,element);   //指定位置添加元素
addAll(index,Collection);   //在指定位置增加给定集合中的所有元素,若省略位置参数,则在当前集合的后面依次添加元素
2、删
remove(index);   //删除指定位置的元素
3、改
set(index,element);   //修改指定位置的元素。
4、查
get(index);   //通过角标获取元素
subList(from,to);   //获取部分对象元素
listIterator();   //List特有的迭代器
int indexOf(obj):获取指定元素的位置。
ListIterator listIterator();  
注:List集合判断元素是否相同,移除等操作,依据的是元素的equals方法。
三、ListIterator 
1、概述
ListIterator是List集合特有的迭代器,是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常。所以在迭代器时,只能用迭代器的方法操作元素。可是
Iterator方法是有限的,只能对元素进行判断,取出,删除的操作。如果想要其他的操作,如添加、修改等,就需要使用其子接口:ListIterrator。该接口只能通过List集合的
ListIterator方法获取。
2、ListIterator的特有方法
add(obj);    //增加
set(obj);    //修改为obj
hasPrevious();    //判断前面有没有元素
previous();    //取前一个元素
四、枚举Enumeration
枚举:
就是Vector特有的取出方式,Vector有三种取出方式。
其实枚举和迭代是一样的,因为枚举的名称及方法的名称都过长,所以被迭代取代了。
特有方法:
addElement(obj);    //添加元素,相当于add(obj);
Enumerationelements(); //Vector特有取出方式(枚举) 
hasMoreElements();   //相当于Iterator的hasNext()方法
nextElements();    //相当于Iterator的next()方法
示例:
class VectorDemo 
{
	public static void main(String[] args) 
	{
		Vector v = new Vector();

		v.add("tom01");
		v.add("tom02");
		v.add("tom03");
		v.add("tom04");

		Enumeration en = v.elements();

		while(en.hasMoreElements())
		{
			System.out.println(en.nextElement());
		}
	}
}

五、LinkedList
LinkedList:底层使用的是链表数据结构。特点:增删速度快,查询慢。
特有方法:
1、增
addFirst();
addLast();
2、获取
getFirst();
getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
3、删
removeFirst();
removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
在JDK1.6出现了替代方法。
1、增
offerFirst();
offerLast();
2、获取
peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。
3、删
pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
示例:
/*
使用LinkedList模拟一个堆栈或者队列数据结构。

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

*/

import java.util.*;

class BuildQueue
{
	private LinkedList link;

	BuildQueue()
	{
		link = new LinkedList();
	}
	public void myAdd(Object obj)
	{
		link.addFirst(obj);
	}
	public Object myGet()
	{
		return link.removeLast();
//		return link.removeFirst();
	}
	public boolean isNull()
	{
		return link.isEmpty();
	}
}

class LinkedListTest 
{
	public static void main(String[] args) 
	{
		BuildQueue  bq = new BuildQueue();
		bq.myAdd("Tom01");
		bq.myAdd("Tom02");
		bq.myAdd("Tom03");
		bq.myAdd("Tom04");

		while(!bq.isNull())
		{
			System.out.println(bq.myGet());
		}
	}
}

第四讲   Set
一、概述
Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。保证元素唯一性的原理:是通过元素的两个方法,hashCode和equals来完成。如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。
|--TreeSet:可以对Set集合中的元素进行排序。默认按照字母的自然排序。底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0。
Set集合的功能和Collection是一致的。
二、HashSet
HashSet:线程不安全,存取速度快。
通过equals方法和hashCode 方法来保证元素的唯一性。
注意:HashSet对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。
示例:
/*
往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。
*/

import java.util.*;

class HashSetTest 
{
	
	public static void main(String[] args) 
	{
		
		HashSet hs = new HashSet();

		hs.add(new Person("Tom01",20));
		hs.add(new Person("Tom02",21));
		hs.add(new Person("Tom03",22));
		hs.add(new Person("Tom04",23));
//		sop("a1:"+hs.contains(new Person("Tom02",21)));

//		hs.remove(new Person("Tom04",22));
		//取出元素
		Iterator it = hs.iterator();

		while(it.hasNext())
		{
			Person p = (Person)it.next();
			sop(p.getName()+":"+p.getAge());
		}
	}
	//打印
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
//描述人
class Person
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public int hashCode()
	{
//		System.out.println(this.name+"...hashCode");
		return name.hashCode()+age;
	}
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Person))
			return false;
		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;
	}
}

三、TreeSet
1、特点
a、底层的数据结构是二叉树结构。
b、可以对Set集合中的元素进行排序。因为TreeSet类实现了Comparable接口,该接口强制让添加到集合中的元素进行了比较,需要复写compareTo方法,才能让对象按指定需求进行排序,并加入集合。
java中很多类都具有比较性,其实就是实现了comparable接口。
注意:排序时,当主要条件相同时,一定判断一下次要条件。
c、保证元素唯一性的依据:compareTo方法return 0,是正整数、负整数或零,则两个对象较大、较小或相同,相同时则不会存入。
2、TreeSet排序的两种方式:
1)第一种方式:自然排序
让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也成为元素的自然顺序,或者叫做默认顺序
示例:
import java.util.*;


class  TreeSetDemo
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet();
		ts.add(new Student("Tom01",22));
		ts.add(new Student("Tom02",21));
		ts.add(new Student("Tom03",24));
		ts.add(new Student("Tom05",24));

		Iterator it = ts.iterator();

		while(it.hasNext())
		{
			Student stu = (Student)it.next();
			System.out.println(stu.getName()+"..."+stu.getAge());
		}

	}
}
//学生类
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;
		if(this.age > s.age)
			return 1;
		if(this.age == s.age)
		{
			return this.name.compareTo(s.name);
		}
		return -1;
	}
	//复写hashCode
	public int hashCode()
	{
		return name.hashCode()+age;
	}
	//复写equals方法
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");

		Student s = (Student)obj;
		return this.name.equals(s.name) && this.age==s.age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;

	}
}
2)第二种方式:比较器
当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。比较器构造方式:定义一个类,实现Comparator接口,覆盖compare方法。
当两种排序方式都存在时,以比较器为主。
示例:
/*
需求:
往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
*/

import java.util.*;

class TreeSetTest
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet();
		
		ts.add(new Student("Tom02",22));
		ts.add(new Student("Tom02",21));
		ts.add(new Student("Tom007",20));
		ts.add(new Student("Tom09",19));
		ts.add(new Student("Tom6",18));
		//ts.add(new Student("Tom007",20));
		ts.add(new Student("Tom01",28));

		Iterator it = ts.iterator();

		while(it.hasNext())
		{
			Student stu = (Student)it.next();
			System.out.println(stu.getName()+"..."+stu.getAge());
		}
	}
}
//学生类
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;

		if(this.age>s.age)
			return 1;
		if(this.age==s.age)
		{
			return this.name.compareTo(s.name);
		}
		return -1;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
}
//定义一个比较器
class MyCompare implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		Student s1 = (Student)o1;
		Student s2 = (Student)o1;

		int num = s1.getName().compareTo(s2.getName());

		if(num==0)
		{
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));

			/*
			if(s1.getAge()>s2.getAge())
				return 1;
			if(s1.getAge()==s2.getAge())
				return 0;
			return -1;
			*/
		}
		return num;
	}
}

第五讲   泛型(Generic)
一、概述
1、JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。
2、JDK1.5的集合类希望在定义集合时,明确表明你要向集合中装入那种类型的数据,无法加入指定类型以外的数据。
3、泛型是提供给javac编译器使用的可以限定集合中的输入类型说明的集合时,会去掉“类型”信息,使程序运行效率不受影响,对参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。
4、由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,如用反射得到集合,再调用add方法即可。
5、格式:
通过<>来定义要操作的引用数据类型。
6、好处
a、 将运行时期出现问题ClassCastException,转移到了编译时期。,方便于程序员解决问题。让运行时问题减少,安全。 
b、避免了强制转换麻烦。
示例:
class GenericDemo 
{
	public static void main(String[] args) 
	{

		ArrayList al = new ArrayList();

		al.add("abc01");
		al.add("abc0991");
		al.add("abc014");

		//al.add(4);//al.add(new Integer(4));
		

		Iterator it = al.iterator();
		while(it.hasNext())
		{
			String s = it.next();

			System.out.println(s+":"+s.length());
		}
	}
}
、泛型定义中的术语
如:ArrayList类和ArrayList
1、ArrayList整个称为泛型类型
2、ArrayList中的E称为类型变量或类型参数
3、整个ArrayList称为参数化类型
4、ArrayList中的Integer称为类型参数的实例或实际类型参数
5、ArrayList中的<>称为typeof
6、ArrayList称为原始类型
三、在使用java提供的对象时,什么时候写泛型?
通常在集合框架中很常见,只要见到<>就要定义泛型。
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
四、泛型类
1、若类实例对象中要使用到同一泛型参数,即这些地方引用类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型。
2、什么时候定义泛型类
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。
3、泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所以要操作的类型就已经固定了。
4、类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:
示例:
class Utils
{
	private QQ q;
	public void setObject(QQ q)
	{
		this.q = q;
	}
	public QQ getObject()
	{
		return q;
	}
}


class  GenericDemo
{
	public static void main(String[] args) 
	{

		Utils u = new Utils();

		u.setObject(new Student());
		Worker w = u.getObject();;
	}
}
注意:
1、在对泛型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
2、当一个变量被声明为参数时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用,因为静态成员是被所有参数化的类共享的,所以静态成员不应该有类级别的类型参数。
五、泛型方法
泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
例:
class Demo
{
	public  void show(T t)
	{
		System.out.println("show:"+t);
	}
	public  void print(Q q)
	{
		System.out.println("print:"+q);
	}
	public  static  void method(W t)
	{
		System.out.println("method:"+t);
	}
}
class GenericMethod 
{
	public static void main(String[] args) 
	{
		Demo  d = new Demo();
		d.show("haha");
		d.show(4);
		d.print(5);
		d.print("hehe");
	}
}
扩展:泛型定义在接口上
如:
interface Inter
{
	void show(T t);
}

class InterImpl implements Inter
{
	public void show(T t)
	{
		System.out.println("show :"+t);
	}
}
class GenericDemo5 
{
	public static void main(String[] args) 
	{

		InterImpl i = new InterImpl();
		i.show(4);
		//InterImpl i = new InterImpl();
		//i.show("haha");
	}
}
通配符:
也可以理解为占位符。

泛型的限定;
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限
示例:
import java.util.*;

class GenericDemo6 
{
	public static void main(String[] args) 
	{

		ArrayList al = new ArrayList();
		al.add(new Person("person1"));
		al.add(new Person("person2"));
		al.add(new Person("person3"));
		//printColl(al);

		ArrayList al1 = new ArrayList();
		al1.add(new Student("Tom"));
		al1.add(new Student("Jerry"));
		al1.add(new Student("Jack"));
		printColl(al1); //ArrayList al = new ArrayList(); error
	}
	
	public static void printColl(Collection al)
	{
		Iterator it = al.iterator();

		while(it.hasNext())
		{
			System.out.println(it.next().getName());
		}
	}
	
}
class Person
{
	private String name;
	Person(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
}
class Student extends Person
{
	Student(String name)
	{
		super(name);
	}
}

class Comp implements Comparator
{
	public int compare(Person s1,Person s2)
	{
		Person s1 = new Person("person1");
		return s1.getName().compareTo(s2.getName());
	}
}
/*
TreeSet ts = new TreeSet(new Comp());
ts.add(new Student("Tom"));
ts.add(new Student("Jerry"));
ts.add(new Student("Jenny"));
*/
泛型的应用:
练习:
mport java.util.*;
class GenericTest
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet(new Comp());

		ts.add(new Student("stu05"));
		ts.add(new Student("stu02"));
		ts.add(new Student("stu06"));
		ts.add(new Student("stu03"));
		
		Iterator it = ts.iterator();

		while(it.hasNext())
		{
			System.out.println(it.next().getName());
		}
		
		TreeSet ts1 = new TreeSet(new Comp());

		ts1.add(new Worker("worker05"));
		ts1.add(new Worker("worker02"));
		ts1.add(new Worker("worker06"));
		ts1.add(new Worker("worker03"));
		
		Iterator it1 = ts1.iterator();

		while(it1.hasNext())
		{
			System.out.println(it1.next().getName());
		}
	}
}
/*
class StuComp implements Comparator
{
	public int compare(Student s1,Student s2)
	{
		return s1.getName().compareTo(s2.getName());
	}
}
class WorkerComp implements Comparator
{
	public int compare(Worker w1,Worker w2)
	{
		return w2.getName().compareTo(w2.getName());
	}
}
*/
class Comp implements Comparator 
{
	public int compare(Person p1,Person p2)
	{
		return p2.getName().compareTo(p1.getName());
	}
}
class Person
{
	private String name;
	Person(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public String toString()
	{
		return "person:"+name;
	}
}
class Student extends Person
{
	Student(String name)
	{
		super(name);
	}
}
class Worker extends Person
{
	Worker(String name)
	{
		super(name);
	}
}

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



你可能感兴趣的:(java学习笔记)