JAVA笔记__集合框架(Day 17~20)

概述

体系

基本方法演示

java文档中的java.util–>接口–>collection
Collection接口中的共性功能。
1.添加。

boolean add(Object obj);一次添加一个
boolean addAlll(Collection c);接收的是容器。将指定容器中的所有元素添加。

2.删除。

void clear();将容器中所有元素清除
boolean remove(Object o);
boolean removeAlll(Collection c);

3.获取长度

int size();

4.判断

boolean isEmpty();是否为空
boolean contains(Object o);是否包含该元素
boolean containsAll(Collection c);
boolean retainAll(Collection c);

5.将集合转成数组。

toArray();
toArray([]);

6.取出集合元素

Iterator iterator();返回在此collection的元素上进行迭代的迭代器。
获取集合中元素上迭代功能的迭代器对象。
迭代:取出元素的一种方式。
迭代器:具备着迭代功能的对象。
而迭代器对象不需要new。直接通过iterator()方法获取接口即可。

演示Collection中的基本功能。

class ExtendsDemo3 {

	public static void main(String[] args) {
		Collection coll=new ArrayList();//虽然Collection是接口,无法new,但可以找出它地子类来新建对象,这里找ArrayList。
		methodDemo(coll);
	}
    public static void methodDemo(Collection coll) {
    	//添加和删除元素会改变集合的长度。
		//1.添加元素
    	coll.add("abc1");
    	coll.add("abc2");
    	coll.add("abc3");
    	
    	System.out.println(coll.size());//看大小
    	System.out.println(coll.toString());//看内容
    	
    	//2.删除
    	coll.remove("abc2");
    	System.out.println(coll);//看内容
    	
    	//3.清除
    	coll.clear();
    	System.out.println(coll);//看内容
    	
    	//4.包含
    	coll.add("abc1");
    	coll.add("abc2");
    	coll.add("abc3");
    	System.out.println("contains:"+coll.contains("abc"));//看是否包含
	}
}

演示带All的方法

import java.util.ArrayList;
/*
 * 对一个有多个数值的字符串,进行数值的排序。
 */
import java.util.Arrays;
import java.util.Collection;

//MyStringBuilder
class ExtendsDemo3 {
	public static void main(String[] args) {
		methodAllDemo(coll);
	}

	public static void methodAllDemo(Collection coll) {

		// 1.创建两个容器。
		Collection c1 = new ArrayList();
		Collection c2 = new ArrayList();

		// 2.添加元素。
		c1.add("abc1");
		c1.add("abc2");
		c1.add("abc3");
		c1.add("abc4");

		c2.add("abc2");
		c2.add("abc3");
		c2.add("abc5");

		/*
		 * //判断c1中是否包含c2的所有元素, boolean b=c1.containsAll(c2);
		 * System.out.println("b="+b);//输出false
		 * 
		 * //往c1中添加c2 c1.addAll(c2); System.out.println(c1);
		 * 
		 * //从c1中删除c2 c1.removeAll(c2);//将c1中和c2相同的元素从c1中删除。
		 * System.out.println(c1);//输出[abc1, abc4]
		 */

		c1.retainAll(c2);// 将c1中c2不同是我元素从c1中删除。保留c1中和c2相同的元素。如果没有相同的,返回[]。
		System.out.println(c1);
	}
}

演示迭代器

class ExtendsDemo3 {
	public static void main(String[] args) {
		
		//1.创建集合。
		Collection coll=new ArrayList();
		coll.add("abc1");
		coll.add("abc2");
		coll.add("abc3");
	
		
		//获取该容器的迭代器。
		java.util.Iterator it=coll.iterator();
		
		//================常用方法=============
		for (java.util.Iterator iterator = coll.iterator(); iterator.hasNext();) {
			System.out.println(iterator.next());
		}

		//================第二种方法=============
		/*while(it.hasNext()) //如果有元素,循环。
		{
			System.out.println(it.next());
		}*/
		
		//================第三种方法=============
		/*
		 * System.out.println(it.next());
		System.out.println(it.next());
		System.out.println(it.next());
		System.out.println(it.next());//报错。Exception in thread "main" java.util.NoSuchElementException
*/	}
}

迭代器原理

迭代器是取出collection集合中元素的公共方式。
实现方法是接口

List

List和set的区别

Collection
       |--List:有序(存入的顺序和取出的顺序一致)。有索引。允许重复元素。
       |--Set:不允许重复元素。

List的常见方法

重点List接口中的特有方法:它的特有方法都是围绕索引定义的。
支持增删改查

add(index,element)

remove(index)

set(index,nevelement)

int indexOf(element);
element get(index);

演示List特有的方法

class ExtendsDemo3 {
	public static void main(String[] args) {
		List list = new ArrayList();
		methodDemo(list);

	}

	public static void methodDemo(List list) {

		// 1.常规添加元素
		list.add("abc1");
		list.add("abc2");
		list.add("abc3");

		// 2.插入元素
		list.add(1, "hehe");
		System.out.println(list);

		// 3.删除元素
		list.remove(1);
		// list.remove(1);
		System.out.println(list);

		// 4.获取。
		System.out.println(list.get(1));// 报错,Exception in thread "main" java.lang.IndexOutOfBoundsException
		System.out.println(list.indexOf("abc1"));

		// 5.修改
		list.set(1, "k");
		System.out.println(list);

		// 取出集合中所有的元素(迭代方式)
		for (java.util.Iterator it = list.iterator(); it.hasNext();) {
			System.out.println("iterator:" + it.next());
		}

		// List集合特有的取出方式。
		for (int i = 0; i < list.size(); i++) {
			System.out.println("get:" + list.get(i));
		}
	}
}

ListIterator

如果迭代过程中同时add其他元素。会引发异常。

迭代过程中使用了其他集合对象同时对元素进行操作,导致了迭代的不确定性。引发了该异常。

解决思想:在迭代过程中,想要执行一些操作,使用迭代器的方法即可。

使用list集合的特有的迭代器:ListIterator。通过List集合的方法ListIterator()获取该迭代器对象。

ListIterator可以实现在迭代过程中的增删改查。它使用角标实现方法的。
它除了有next(),还可以previous()。
注意:迭代器Iterator只有三个方法,不能完成增改查
‘当要用到增改查的时候,就要用ListIterator。

boolean hasNext() 
          如果仍有元素可以迭代,则返回 trueboolean next() 
          返回迭代的下一个元素。
void	remove() 
          从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

举例:

class IteratorDemo {
	public static void main(String[] args) {
		
		List list = new ArrayList();
		
		list.add("abc1");
		list.add("abc2");
		list.add("abc3");
		list.add("abc4");
		
		//在遍历的过程中,如果遍历到abc2,添加一个元素haha
		for (java.util.Iterator it = list.iterator(); it.hasNext();) {
			Object obj = it.next();
			
			if(obj.equals("abc2")) 
				list.add("haha");// 报错,并发修改java.util.ConcurrentModificationException
			    //4个迭代器,但有5个元素。
		}
		System.out.println(list);
	}
}

改进:

class IteratorDemo {
	public static void main(String[] args) {
		
		List list = new ArrayList();
		
		list.add("abc1");
		list.add("abc2");
		list.add("abc3");
		list.add("abc4");
		
		//在遍历的过程中,如果遍历到abc2,添加一个元素haha

		for (java.util.ListIterator it = list.listIterator(); it.hasNext();) {
			Object obj = it.next();
			
			if(obj.equals("abc2")) 
				it.add("haha");
		}
		System.out.println(list);
	}
}

List子类介绍

List集合的具体子类.子类之所以区分是因为内部的数据结果(存储数据方式)不同。
     |--Vector:数据结构是数组。数据是可变长度的(不断new新数组并将原数组元素复制到新数组)。线程同步的。
        JDK1.0(JDK1.0只有集合对象 )。都慢。
     |--ArrayList:也是数组结构,也是长度可变。JDK1.2(集合框架从1.2开始),线程不同步的,替代了Vector。
                  增删速度不快。查询速度很快。
     |--LinkedList:链表结构。线程不同步的。增删速度很快。

ArrayList

一、存储自定义对象
需求:往ArrayList中存储自定义对象。Person(name,age)
思路:
1.描述Person。
2.定义容器对象。
3.将多个Person对象,存储到集合中。
4.取出Person对象。

public class Person {
	private String name;
	private int age;
	
	
	public Person() {
		super();
	}
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
class ExtendsDemo3 {
	public static void main(String[] args) {

		// 1.创建ArrayList集合对象
		List list = new ArrayList();

		// 2.添加Person类型的对象
		Person p1 = new Person("lisi1", 21);
		Person p2 = new Person("lisi2", 22);

		list.add(p1);// add(Object obj)
		list.add(p2);
		list.add(new Person("lisi3", 23));

		// 取出元素,用普通迭代器的方法。
		for (java.util.Iterator it = list.listIterator(); it.hasNext();) {
			// it.next();取出的元素都是Object类型的。需要用到具体对象的内容时,需要向下转型。
			Person p = (Person) it.next();// 向下转型

			System.out.println(p.getName() + ":" + p.getAge());
		}
	}
}

练习二:去除重复元素
需求:定义功能:请除去ArrayList集合中的重复元素。
方法1:

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

		// 1.创建ArrayList集合对象
		List list = new ArrayList();

		list.add("abc1");
		list.add("abc4");
		list.add("abc2");
		list.add("abc1");
		list.add("abc4");
		list.add("abc2");
		list.add("abc1");
		list.add("abc4");
		list.add("abc2");
		System.out.println(list);
		singleElement(list);
		System.out.println(list);

	}

	// 定义功能,取出重复元素。
	public static void singleElement(List list) {
		for (int x = 0; x < list.size() - 1; x++) {
			Object obj_x = list.get(x);
			for (int y = x + 1; y < list.size(); y++) {
				if (obj_x.equals(list.get(y))) {
					list.remove(y);// 一旦remove,长度改变。所以y还得再回到原位进行比较。
					y--;
				}
			}
		}
	}
}

方法2:
思路:
1.最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素。
2.对原有容器进行元素的获取,并到临时容器中去判断是否存在。容器本身就有这个功能。判断元素是否存在。
3.存在就不存储,不存在就存储。
4.遍历完原容器后,临时容器中存储的就是唯一性的容器。

//IteratorDemo
class ExtendsDemo3 {
	public static void main(String[] args) {

		// 1.创建ArrayList集合对象
		List list = new ArrayList();

		list.add("abc1");
		list.add("abc4");
		list.add("abc2");
		list.add("abc1");
		list.add("abc4");
		list.add("abc2");
		list.add("abc1");
		list.add("abc4");
		list.add("abc2");
		System.out.println(list);
		singleElement2(list);
		System.out.println(list);

	}

	// 去除重复元素方式二:
	public static void singleElement2(List list) {
		//1.定义一个临时容器。
		List temp=new ArrayList();
		
		//2.遍历原容器
		for (java.util.Iterator iterator = list.iterator(); iterator.hasNext();) {
			Object obj= (Object) iterator.next();
			
			//3.在临时容器中判断遍历到的元素是否存在。
			if(!(temp.contains(obj))) {
				//4.如果不存在,就存储到临时容器中。
				temp.add(obj);
			}
		}
		//5.将原容器清空。
		list.clear();
		
		//6.将临时容器中的元素都存储到原容器中。
		list.addAll(temp);
	}
}

把这个思想用到自定义对象:

public class Person {
	private String name;
	private int age;
	
	
	public Person() {
		super();
	}
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	//建立Person类自己的判断对象是否相同的依据,必须要覆盖Object类中的equals方法。
    public boolean equals(Object obj) {
    	
    	System.out.println(this+"...."+obj);//这里的this是temp。
    	
    	//为了提高效率,如果比较的对象是同一个,直接返回true。
    	if(this==obj) {
    		return true;
    	}
    	
    	if(!(obj instanceof Person)) {
    		throw new ClassCastException("类型错误");
    	}
    	Person p=(Person)obj;
    	return this.name.equals(p.name)&&this.age==p.age;
    }
    
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
class IteratorDemo {
	public static void main(String[] args) {

		// 1.创建ArrayList集合对象
		List list = new ArrayList();

		// 2.添加Person类型的对象
		Person p1 = new Person("lisi1", 21);
		Person p2 = new Person("lisi2", 22);
				
		list.add(p1);// add(Object obj)
		list.add(p1);// add(Object obj)//存储了一个地址相同的对象。
		list.add(p2);
		list.add(new Person("lisi3", 23));
		list.add(new Person("lisi1", 21));
		list.add(new Person("lisi2", 22));

		System.out.println(list);
		singleElement2(list);//去除重复元素
		System.out.println(list);

	}

	// 去除重复元素方式二:
	public static void singleElement2(List list) {
		//1.定义一个临时容器。
		List temp=new ArrayList();
		
		//2.遍历原容器
		for (java.util.Iterator iterator = list.iterator(); iterator.hasNext();) {
			Object obj= (Object) iterator.next();
			
			//3.在临时容器中判断遍历到的元素是否存在。
			if(!(temp.contains(obj))) {//contains实际是equals的封装,Object中的equals是看地址是否一致。
				//4.如果不存在,就存储到临时容器中。
				temp.add(obj);
			}
		}
		//5.将原容器清空。
		list.clear();
		
		//6.将临时容器中的元素都存储到原容器中。
		list.addAll(temp);
	}
}

LinkedList

特殊的方法

class IteratorDemo {
	public static void main(String[] args) {
		//1.创建一个链表对象。//演示XXXFirst XXXLast。
		LinkedList link=new LinkedList();
		
		//2.添加方法
		link.addFirst("abc1");
		link.addFirst("abc2");
		link.addFirst("abc3");
		
		//3.获取元素
		System.out.println(link.getFirst());//abc3
		System.out.println(link.getFirst());//abc3
		
		/*//4.删除元素
		System.out.println(link.removeFirst());//abc3,先返到开头
		System.out.println(link.removeFirst());//去除,abc2
		System.out.println(link.removeFirst());//去除,abc1
        */		
		
		//5.取出link中所有元素。
		while(!link.isEmpty()) {
			System.out.println(link.removeFirst());//removeLast();
		}
	}
}

实现队列结构
需求:请通过LinkedList实现一个堆栈,或者队列数据结构。
堆栈:先进后出。First In Last Out FILO.
队列:先进先出。First In First Out FIFO.

class MyQueue {
	private LinkedList link;
	MyQueue(){
		link=new LinkedList();
	}
	
	/*
	 * 添加元素的方法
	 */
	public void myAdd(Object obj) {
		//内部使用的是linkedList的方法。
		link.addFirst(obj);
	}
	
	/*
	 * 获取队列元素的方法
	 */
	public Object myGet() {
		return link.removeLast();
	}
	
	/*
	 * 集合中是否有元素的方法
	 */
	public boolean isNull() {
		return link.isEmpty();
	}
}
class MyQueueDemo {

	public static void main(String[] args) {
		
		//1.创建自定义的队列对象
		MyQueue queue=new MyQueue();
		
		//2.添加元素
		queue.myAdd("abc1");
		queue.myAdd("abc3");
		queue.myAdd("abc4");
		queue.myAdd("abc5");
		
		//3.获取所有元素。先进先出。
		while(!queue.isNull()) {
			System.out.println(queue.myGet());
		}
	}
}

Hash

Set集合:不允许重复元素。和Collection的方法相同。Set集合取出方法只有一个:迭代器。
      |--HashSet:不保证有序。哈希(散列)表结构。
                 如何保证唯一性?
                 元素必须覆盖hashCode和equals方法。
                 覆盖hashCode方法是为了根据元素自身的特点确定hash值。
                 覆盖equals方法,是为了解决哈希值的冲突。
      |--TreeSet:二叉树数据结构。可以对元素进行排序。不同步的。
                 如何保证元素唯一性?
                 参考的就是比较方法的返回值是否是0,是,就是重复元素,不存。
                 排序方式:需要元素具备比较功能。所以元素需要实现Comparable接口。覆盖compareTo方法。

HashSet集合演示

//HashSetDemo
class ExtendsDemo3 {

	public static void main(String[] args) {
		
		//1.创建一个Set容器对象。
		Set set=new HashSet();
		
		//2.添加元素
		set.add("haha");
		set.add("abc");
		set.add("nba");
		set.add("heihei");
		
		//3.只能用迭代器取出。
		for (java.util.Iterator it= set.iterator(); it.hasNext();) {
			System.out.println(it.next());		
		}
	}
}

结果:

haha
abc
heihei
nba

哈希表

哈希表_冲突的解决

当哈希算法算出的两个元素的值相同时,称为哈希冲突。
冲突后,需要对元素进行进一步的判断。判断的是元素的内容。equals();

哈希算法:hashcode();
在java.lang中的Object中的方法摘要中。

哈希表在哦安端圆度是否相同,依据hashcode方法。

如果哈希重复(哈希值相同),再判断元素的equals方法。如果equals方法返回true,不存,返回false,存储。

哈希表_存储自定义对象

需求:往HashSet中存储学生对象(姓名,年龄)。通姓名。同年龄视为同一个人 。不存。
思路:
1.描述学生。
2.定义容器。
3.将学生对象存储到容器中。

public class Student {
	private String name;
	private int age;
	
	Student(){
	}
	
	Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	/*
	 * 覆盖hashCode方法。根据对象自身的特点定义哈希值。
	 * 
	 */
	public int hashCode(){
		final int Number=37;
		return name.hashCode()+age*Number;//哈希冲突降低
	}
	
	/*
	 * 需要定义对象自身判断内容相同的依据,覆盖equals方法。
	 */
	public boolean equals(Object obj){
		if(this==obj) {
			return true;
		}
		
		if(!(obj instanceof Student)) {
			throw new ClassCastException(obj.getClass().getName()+"类型错误");
		}
		
		Student stu=(Student) obj;
		return this.name.equals(stu.name)&&this.age==stu.age;
		
	}
	public void setName(String name) {
		this.name=name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age=age;
	}
	
	public int getAge() {
		return age;
	}
	
	public String toString() {
		return "Student[name"+name+",age="+age+"]";
	}
}
class HashSetDemo {

	public static void main(String[] args) {
		
		//发现存储了同姓名同年龄的学生时可以的。
		//原因是每一次存储学生对象,都先调用hashCode方法获取哈希值。
		//但是调用的是Object类中的hashCode,所以不同的对象,哈希值也不同。
		//这就是同姓名同年龄存入的原因。
		
		/*
		 * 解决:
		 * 需要根据学生对象自身的特点来定义哈希值。
		 * 所以就需要覆盖hashCode()方法。
		 */
		//1.创建容器对象。
		Set set=new HashSet();
		
		//2.存储学生对象。
		set.add(new Student("xiaoqiang",20));
		set.add(new Student("xiaoqiang",20));//原本应该去掉这个结果,但是这里的地址不同。
		set.add(new Student("wangcai",27));
		set.add(new Student("xiaoming",22));
		set.add(new Student("daniu",24));
	
		//3.获取所有学生
		for (java.util.Iterator it= set.iterator(); it.hasNext();) {
			Student stu=(Student)it.next();
			
			System.out.println(stu.getName()+"::"+stu.getAge());		
		}
		
	}
}

字符串String也有自己hashCode()方法:

public int hashCode()
返回此字符串的哈希码。 String 对象的哈希码根据以下公式计算:
 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 
使用 int 算法,这里 s[i] 是字符串的第 i 个字符, n 是字符串的长度, ^ 表示求幂。(空字符串的哈希值为 0。)

LinkedHashSet

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
实现有序
Set set=new HashSet();改为Set set=new LinkedHashSet();即可。

TreeSet

演示

class TreeSetDemo{
	public static void main(String[] args) {		
		Set set=new TreeSet();
		
		set.add("abc");
		set.add("nba");
		set.add("heihei");
		set.add("haha");
		set.add("heihei");
	
		for (java.util.Iterator it= set.iterator(); it.hasNext();) {	
			System.out.println(it.next());		
		}		
	}
}

自定义演示

public class Student implements Comparable{
	private String name;
	private int age;
	
	Student(){
	}
	
	Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	
	public void setName(String name) {
		this.name=name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age=age;
	}
	
	public int getAge() {
		return age;
	}
	
	public String toString() {
		return "Student[name"+name+",age="+age+"]";
	}
	
    //学生就具备了比较功能。该功能是自然排序使用的方法。
	//自然排序就年龄的升序排序为主。
	@Override
	public int compareTo(Object o) {
		Student stu=(Student)o;
		System.out.println(this.name+":"+this.age+"......"+stu.name+":"+stu.age);
		if(this.age>stu.age)
			return 1;
		if(this.age<stu.age)
			return -1;
		return 0;
	}
}
class TreeSetDemo {
	public static void main(String[] args) {		
		Set set=new TreeSet();
		
		set.add(new Student("xiaoqiang",20));
		//java,lang.AlassCastException:因为学生要排序,就需比较,二没有定义比较方法,无法完成排序。
		//比较add方法中使用的是Comparable接口的比较方法。
		set.add(new Student("xiaoming",22));
		set.add(new Student("daniu",24));
	
		for (java.util.Iterator it= set.iterator(); it.hasNext();) {	
			Student stu=(Student)it.next();
			System.out.println(stu.getName()+"::"+stu.getAge());		
		}		
	}
}

结果:

xiaoqiang:20......xiaoqiang:20
xiaoming:22......xiaoqiang:20
daniu:24......xiaoqiang:20
daniu:24......xiaoming:22
xiaoqiang::20
xiaoming::22
daniu::24

TreeSet_比较功能compareTo

注意:

if(this.age>stu.age)
			return 1;
		if(this.age<stu.age)
			return -1;
		return 0;

改为

return 1;//就成为有序的。

TreeSet_比较功能注意事项

假如年龄相同而名字不同,那么可以把上述代码的第一段改成如下:

public class Student implements Comparable{
	private String name;
	private int age;
	
	Student(){
	}
	
	Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	
	public void setName(String name) {
		this.name=name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age=age;
	}
	
	public int getAge() {
		return age;
	}
	
	public String toString() {
		return "Student[name"+name+",age="+age+"]";
	}
	
    //学生就具备了比较功能。该功能是自然排序使用的方法。
	//自然排序就年龄的升序排序为主。
	@Override
	public int compareTo(Object o) {
		Student stu=(Student)o;
		System.out.println(this.name+":"+this.age+"......"+stu.name+":"+stu.age);
		int temp=this.age-stu.age;
		return temp==0?this.name.compareTo(stu.name):temp;//比大小。
	}
}

TreeSet比较器

需求中也有这样一种情况,元素具备的比较功能不是所需要的,也就是说不想按照自然排序的方式,而是按照自定义的排序方式,对元素进行排序。

而且,存储到TreeSet中的元素万一没有比较功能,该如何排序呢?

这时,就只能使用第二种比较方式——是让集合具备比较功能。定义一个比较器。

实现Comparator接口,覆盖compare方法。将Comparator接口的对象作为参数传递给TreeSet集合的构造函数。

比较器更为灵活。自然排序通常都作为元素的默认排序。

int  compare(Object o1,Object o2)boolean	equals(Object obj) ;指示某个其他对象是否“等于”此 Comparator。
/*
 * 自定义图=一个比较器。用来对学生对象按照姓名进行排序。
 */
public class ComparatorByName extends Object implements Comparator{
	
	public int compare(Object o1,Object o2) {
		Student s1=(Student)o1;
		Student s2=(Student)o2;
		
		int temp=s1.getName().compareTo(s2.getName());
		return temp==0?s1.getAge()-s2.getAge():temp;
	}
}
public class Student implements Comparable{
	private String name;
	private int age;
	
	Student(){
	}
	
	Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	
	public void setName(String name) {
		this.name=name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age=age;
	}
	
	public int getAge() {
		return age;
	}
	
	public String toString() {
		return "Student[name"+name+",age="+age+"]";
	}
}
class ExtendsDemo3 {
	public static void main(String[] args) {	
		
		//初始化Treeset集合明确一个比较器。
		Set set=new TreeSet(new ComparatorByName());
		
		set.add(new Student("xiaoqiang",20));
		set.add(new Student("daniu",24));
		set.add(new Student("xiaoming",22));
		set.add(new Student("tudou",18));
		set.add(new Student("daming",22));
		set.add(new Student("dahuang",19));
	
		for (java.util.Iterator it= set.iterator(); it.hasNext();) {	
			Student stu=(Student)it.next();
			System.out.println(stu.getName()+"::"+stu.getAge());		
		}		
	}
}

集合名词阅读技巧

技巧:
jdk1.2以后出现的集合框架中的常用子类对象,存在的规律。
前缀名数据结构面,后缀名是所属体系名。
ArrayList:数组结构。看到数组就知道查询快,看到List就知道可以重复,可以增删改查。
LinkedList::链表结构,增删快。XXXFirst; XXXLast;XXX:add get remove
HashSet:哈希表,就要想到元素必须覆盖hashCode equals。查询速度更快。不保证有序。看到Set就知道不可以重复。
LinkedHashSet::链表+哈希表,可以实现有序。
TreeSet:二叉树,可以排序。就要想要两种比较方式:一种是自然排序comparable 一种是比较器Comparator。

Foreach语句

JDK1.5特性:
增强for循环。作用:用于遍历Collection集合or数组。
格式:

for(元素类型变量:Collection容器or数组)
{}

对于数组的遍历,如果不操作其角标,可以使用增强for;
如果要操作角标,使用传统for循环。

传统for循环和增强for循环有什么区别呢?
增强for必须有遍历目标,而该目标只能是Collection数组。

class ExtendsDemo3 {
	public static void main(String[] args) {	
		
		Collection coll=new ArrayList();
		coll.add("abc1");
		coll.add("abc2");
		coll.add("abc3");
		
		/*for(java.util.Iterator it=coll.iterator();it.hasNext();) {
			Object obj=it.next();
			System.out.println(obj);
		}*/
		
		for(Object obj:coll) {
			System.out.println(obj);
		}
				
		//对于数组的遍历,如果不操作其角标,可以使用增强for;
		//如果要操作角标,使用传统for循环。
		int[] arr= {23,15,32,78};
		
		for(int x:arr) {
			System.out.println(x);
		}	
	}
}

Enumeration接口

Enumeration:枚举。
具枚举取出方式的容器只有Vector。

class ExtendsDemo3 {
	public static void main(String[] args) {	
		
		Vector v=new Vector();
		
		v.add("abc1");
		v.add("abc2");
		v.add("abc3");
		v.add("abc4");
		
		//获取枚举(已过时)
		for(Enumeration en=v.elements();en.hasMoreElements();) {
			System.out.println("enumeration:"+en.nextElement());
		}
		
		//获取迭代(可以在迭代过程中进行操作)
		for (java.util.Iterator it = v.iterator(); it.hasNext();) {
			System.out.println("iterator:"+it.next());
		}
		//高级or(最简单)
		for(Object obj:v) {
			System.out.println("foreach:"+obj);
		}
	}
}

练习

需求1:对多个字符串(不重复)按照长度排序(由短到长)。
思路:
1.多个字符串,需要容器存储。
2.选择哪个容器。字符串是对象,可以选择集合,而且不重复,选择Set集合。
3.还需要排序,可以选择TreeSet集合。

public class ComparatorByLength implements Comparator{
	public int compare(Object o1,Object o2) {
		//对字符串按照长度比较。
		String s1=(String)o1;
		String s2=(String)o2;
		
		//比较长度。
		int temp=s1.length()-s2.length();
		//长度相同,再按字典顺序。
		return temp==0?s1.compareTo(s2):temp;
	}
}
class ExtendsDemo3 {
	public static void main(String[] args) {	
		sortStringByLength();
	}
	public static void sortStringByLength() {
		
		Set set=new TreeSet(new ComparatorByLength());//自然排序的方式。
		
		set.add("haha");
		set.add("abc");
		set.add("zz");
		set.add("nba");
		set.add("xixixi");
		set.add("haha");
		for(Object obj:set){
		System.out.println(obj);
		}
	}
}

需求2:对多个字符串(重复),按照长度排序。
思路:
1.能使用TreeSet么?不能。
2.可以存储到数组,list。这里先选择数组。
回顾:
之前写的按照自然排序的方法。

class ExtendsDemo3 {
	public static void main(String[] args) {	
		sortStringByLength2();
	}
	public static void sortStringByLength2() {
		String[] strs= {"haha","abcccc","zero","xixi","nba","abcccc","cctv","zero"};
		//排序就需要嵌套循环。位置变换。
		for(int x=0;x<strs.length-1;x++) {
			for(int y=x+1;y<strs.length;y++) {
				if(strs[x].compareTo(strs[y])>0) {
					swap(strs,x,y);
				}
			}
		}
		for(String s:strs) {
			System.out.println(s);
		}
	}
	private static void swap(String[] strs, int x, int y) {
		String temp=strs[x];
		strs[x]=strs[y];
		strs[y]=temp;
	}
}

在新的需求下:

public class ComparatorByLength implements Comparator{
	public int compare(Object o1,Object o2) {
		//对字符串按照长度比较。
		String s1=(String)o1;
		String s2=(String)o2;
		
		//比较长度。
		int temp=s1.length()-s2.length();
		//长度相同,再按字典顺序。
		return temp==0?s1.compareTo(s2):temp;
	}
}
class ExtendsDemo3 {
	public static void main(String[] args) {	
		sortStringByLength2();
	}
	public static void sortStringByLength2() {
		String[] strs= {"haha","abcccc","zero","xixi","nba","abcccc","cctv","zero"};
	    //自然排序可以使用String类中的compareTo方法。
		//但是现在要的是长度排序,这就需要比较器。
		//定义一个按照长度排序的比较器对象。
		Comparator comp=new ComparatorByLength();
		
		//排序就需要嵌套循环。位置变换。
		for(int x=0;x<strs.length-1;x++) {
			for(int y=x+1;y<strs.length;y++) {
				//if(strs[x].compareTo(strs[y])>0) {//按照字典顺序。
				if(comp.compare(strs[x],strs[y])>0) {//按照长度顺序。
					swap(strs,x,y);
				}
			}
		}
		for(String s:strs) {
			System.out.println(s);
		}
	}
	private static void swap(String[] strs, int x, int y) {
		String temp=strs[x];
		strs[x]=strs[y];
		strs[y]=temp;
	}
}

集合框架_泛型

概述

class ExtendsDemo3 {
	public static void main(String[] args) {	
		
		int[] arr=new int[2];
		arr[0]=2.0;//会报错
		
		List list=new ArrayList();
		
		list.add("abc");
		list.add(4);//List.add(Integer.valueOf(4));自动装箱
		
		for (java.util.Iterator it = list.iterator(); it.hasNext();) {
			//Object obj=it.next();
			String str=(String) it.next();
			//System.out.println(it.next()); //这里调用的是toString方法
			System.out.println(str.length());//java.lang.ClassCastException: 
			//java.lang.Integer cannot be cast to java.lang.String
		}
	}
}

出现报错
为了运行时期不出现类型异常。可以在定义容器时,就明确容器中的元素的类型。
这样在集合中传入其他类型时,就会报错,保证了其安全性。

//HashSetDemo
class GenericDemo {
	public static void main(String[] args) {	
	
		List<String> list=new ArrayList<String>();
		
		list.add("abc");
		list.add(4);//List.add(Integer.valueOf(4));自动装箱
		
		for (java.util.Iterator<String> it = list.iterator(); it.hasNext();) {
			//Object obj=it.next();
			String str=it.next();//这里就不需要强转。
			//System.out.println(it.next()); 
			System.out.println(str.length());
		}
	}
}

总结:
泛型
在JDK1.4版本之前,容器什么类型的对象都可以存储。但是在取出时,需要用到对象的特有内容时,需要做向下转型。

但是对象的类型不一致,导致了向下转型发生了ClassaCastException异常,

为了避免这个问题,只能主观上控制往集合中存储的对象类型保持一致。

JDK1.5以后解决了该问题,在定义集合时,就直接明确集合中存储元素的具体类型。

这样,编译器在编译时,就可以对几何中存储的对象类型进行检查。
一旦发现类型不匹配,就编译失败。这个技术就是泛型 技术。

好处:
1.将运行时期的问题转移到了编译时期,可以更好地让程序员发现问题并解决问题。
2.避免了向下转型的麻烦。

综合以上:泛型就是应用在编译时期的一项安全机制。

**泛型的擦除:**编译器通过泛型对元素类型进行检查,只要检查通过,就会生成class文件中,就将泛型标识去掉了。

**泛型的表现:**泛型技术在集合框架中应用的范围很大,什么时候需要写泛型?
1.只要看到类,或者接口在描述时右边定义<>,就需要泛型。
其实时,容器在不明确操作元素的类型的情况下,对外提供了一个参数<>。
使用容器时,只要将具体的类型实参传递给该参数即可。
说白了,泛函就是,传递类型参数。

class GenericDemo2 {
	public static void main(String[] args) {	
		//创建一个List集合.存储整数.List ArratList
		List<Integer> list=new ArrayList<Integer>();
		list.add(5);                          
		list.add(6);
		
		for(java.util.Iterator<Integer> it=list.iterator();it.hasNext();) {
			Integer integer=it.next();
			System.out.println(integer);
		}	
	}
}
class GenericDemo3 {
	public static void main(String[] args) {	
		Set<String> set=new TreeSet<String>();
		set.add("abcd");
		set.add("aa");
		set.add("nba");
		set.add("cba");
		
		for(String s:set) {
		System.out.println(s);}	
	}
}

当对象为Student类型时,

import java.util.LinkedList;

public class Student implements Comparable<Student>{
	private String name;
	private int age;
	
	Student(){
	}
	
	Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	public void setName(String name) {
		this.name=name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age=age;
	}
	
	public int getAge() {
		return age;
	}
	
	public String toString() {
		return "Student[name"+name+",age="+age+"]";
	}
	
    //学生就具备了比较功能。该功能是自然排序使用的方法。
	//自然排序就年龄的升序排序为主。
	@Override
	public int compareTo(Student o) {
		Student stu=o;
		int temp=this.age-stu.age;
		return temp==0?this.name.compareTo(stu.name):temp;//比大小。
	}
}
import java.util.Set;
import java.util.TreeSet;

//GenericDemo3
class ExtendsDemo3 {
	public static void main(String[] args) {		
		Set<Student> set<Student>=new TreeSet<Student>();
		
		set.add(new Student("xiaoqiang",20));
		set.add(new Student("xiaoming",22));
		set.add(new Student("daniu",24));
	
		for (java.util.Iterator<Student> it= set.iterator(); it.hasNext();) {	
			Student stu=it.next();
			System.out.println(stu.getName()+"::"+stu.getAge());		
		}		
	}
}

Set List Iterator comparable comparator后面都要加

或者

import java.util.Comparator;


/*
 * 自定义图=一个比较器。用来对学生对象按照姓名进行排序。
 */
public class ComparatorByName extends Object implements Comparator{
	
	public int compare(Object o1,Object o2) {
		Student s1=(Student)o1;
		Student s2=(Student)o2;
		
		int temp=s1.getName().compareTo(s2.getName());
		return temp==0?s1.getAge()-s2.getAge():temp;
	}
}
import java.util.Set;
import java.util.TreeSet;

import javax.naming.CompoundName;

//GenericDemo3
class ExtendsDemo3 {
	public static void main(String[] args) {		
		Set<Student> set=new TreeSet<Student>(new ComparatorByName());
		
		set.add(new Student("xiaoqiang",20));
		set.add(new Student("xiaoming",22));
		set.add(new Student("daniu",24));
	
		for (java.util.Iterator<Student> it= set.iterator(); it.hasNext();) {	
			Student stu=it.next();
			System.out.println(stu.getName()+"::"+stu.getAge());		
		}		
	}
}

当TreeSet变为HashSet,对象中有重复对象时,应该把重复对象去掉,这时的结果是没有重复结果且无规律的。

import java.util.LinkedList;

public class Student {
	
	private String name;
	private int age;
	
	Student(){
	}
	
	Student(String name,int age){
		this.name=name;
		this.age=age;
	}
	
	
	public void setName(String name) {
		this.name=name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setAge(int age) {
		this.age=age;
	}
	
	public int getAge() {
		return age;
	}
	
	public String toString() {
		return "Student[name"+name+",age="+age+"]";
	}
	
    @Override
	public int hashCode() {
    	final int NUMBER = 38;
		return this.name.hashCode()+age*NUMBER;
	}

	@Override
	public boolean equals(Object obj) {//注意,这里的强转是必须的,否则不能覆盖.
		if(this==obj)//如果是同一个
			return true;
		if(!(obj instanceof Student))
			throw new ClassCastException();
		Student stu=(Student)obj;
		return this.getName().equals(stu.getName())&&this.getAge()==stu.getAge();
	}

}
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

import javax.naming.CompoundName;

//GenericDemo3
class ExtendsDemo3 {
	public static void main(String[] args) {		
		Set<Student> set=new TreeSet();
		
		set=new HashSet<Student>();
		
		set.add(new Student("xiaoqiang",20));
		set.add(new Student("xiaoqiang",20));
		set.add(new Student("xiaoming",22));
		set.add(new Student("xiaoming",22));
		set.add(new Student("daniu",24));
	
		for (java.util.Iterator<Student> it= set.iterator(); it.hasNext();) {	
			Student stu=it.next();
			System.out.println(stu.getName()+"::"+stu.getAge());		
		}		
	}

泛型类

  • 创建一个用于操作Student对象的工具类,对对象进行设置和获取.
  • 太有局限性了,可不可以定义一个可以操作所有对象的工具呢?
  • 类型向上抽取.
  • 当要操作的对象类型不确定的时候,为了扩展,可以使用Object类型来完成.
  • 但是这种方式有一些小弊端,回出现转型,向下转型容易在运行时期发生ClassCastException.
  • jdk1.5以后,新的解决方案.
  • 类型不确定时,可以对外提供参数.由使用者通过传递参数的形式完成类型的确定.
  • 在定义时就明确参数。由使用该类的调用者来传递具体的类型。
/*
 * 创建一个用于操作Student对象的工具类,对对象进行设置和获取.
 * 太有局限性了,可不可以定义一个可以操作所有对象的工具呢?
 * 类型向上抽取.
 * 当要操作的对象类型不确定的时候,为了扩展,可以使用Object类型来完成.
 * 但是这种方式有一些小弊端,回出现转型,向下转型容易在运行时期发生ClassCastException.
*
 * jdk1.5以后,新的解决方案.
 * 类型不确定时,可以对外提供参数.由使用者通过传递参数的形式完成类型的确定.
 * 在定义时就明确参数。由使用该类的调用者来传递具体的类型。
 */
//=========================老老版===============
/*class Tool{
	private Student stu;

	public Student getStu() {
		return stu;
	}

	public void setStu(Student stu) {
		this.stu = stu;
	}
}*/

//=======================jdk1.4==================
class Tool{
	private Object obj;
	
	public Tool() {
		super();
	}

	public Tool(Object obj) {
		super();
		this.obj = obj;
	}

	public Object getObj() {
		return obj;
	}

	public void setObj(Object obj) {
		this.obj = obj;
	}
}
//=======================jdk1.5==================
//在定义时就明确参数。由使用该类的调用者来传递具体的类型。
class Util<W>{//泛型类
	private W obj;

	public W getObj() {
		return obj;
	}

	public void setObj(W obj) {
		this.obj = obj;
	}
}
public class Person {
	private String name;
	private int age;
	
	public Person() {
		super();
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}
	
	@Override
	public String toString() {
		return "Person [name="+getName()+",age="+getAge()+"]";
	}
}
public class Student extends Person{
	public Student() {
		super();
	}

	public Student(String name, int age) {
		super(name, age);
		// TODO Auto-generated constructor stub
	}

	@Override
	public String toString() {
		return "Person [name="+getName()+",age="+getAge()+"]";
	}
}
public class Worker extends Person
{
	public Worker() {
		super();
	}
	
	public Worker(String name,int age) {
		super(name,age);
	}

	@Override
	public String toString() {
		return "Worker [name()="+getName()+",age()="+getAge()+"]";
	}
}
//GenericDemo4
class ExtendsDemo3 {
	public static void main(String[] args) {		
		/*Tool tool=new Tool();
		tool.setObj(new Student());//Object obj=new Student();已经被提升为Object
		//Student stu=tool.getObj();//student类型就不能接收Object类型,要加强转.
		tool.setObj(new Worker());//编译没问题,但会出现ClassCastException.
		Student stu=(Student)tool.getObj();*/
		
		Util<Student> util=new Util<Student>();
		util.setObj(new Student());
		//util.setObj(new Worker());//如果类型不匹配,直接编译失败。
		Student stu=util.getObj();//避免了向下转型。
		
		System.out.println(stu);
	}
}

泛型方法

class GenericDemo5 {
	public static void main(String[] args) {		
		Demo<String> d=new Demo<String>();
		d.show("abc");
		
		//d.print(6);//报错,那么如何打印int型?
		Demo<Integer> d1=new Demo<Integer>();
		d1.show(6);
		//d1.show("abc");//这时候就会有问题。
		
	}
}

class Demo<W>{
	public void show(W w) {
		System.out.println("show:"+w);
	}
	
	public void print(W w) {
		System.out.println("print:"+w);
	}
}

如何改进?
除了在类上定义泛型,还可以在方法上定义泛型:

class GenericDemo5 {
	public static void main(String[] args) {		
		Demo<String> d=new Demo<String>();
		d.show("abc");
		
		//d.print(6);//报错,那么如何打印int型?
		Demo<Integer> d1=new Demo<Integer>();
		d1.print(6);
		//d1.show("abc");//这时候就会有问题。
		
		Demo<String> d2=new Demo<String>();
		d2.show("abc");//还是只能用String。
		d2.print(6);//可以写任何类型。
	}
}


class Demo<W>{
	public void show(W w) {//加static会失败。静态是无法访问类上定义的泛型的。因为泛型在new对象时才存在。而静态优先于new对象存在。
		//如果静态方法需要定义泛型,泛型只能定义在方法上。
		System.out.println("show:"+w);
	}
	
	public static <A> void staticShow(A a) {
		System.out.println("static show:"+a);
	}
	public <Q> void print(Q w) {//泛型方法。
		System.out.println("print:"+w);
	}
}

泛型接口

//GenericDemo6
class ExtendsDemo3 {
	public static void main(String[] args) {	
		SubDemo d=new SubDemo();
		d.show("abc");
	}
}


interface Inter<T>{//泛型接口
	public void show(T t);
}

//============在类上定义泛型================
class InterImpl1<W> implements Inter<W>{

	@Override
	public void show(W t) {
		System.out.println("show:"+t);
	}
}
//====子类确定泛型===
class SubDemo extends InterImpl1<String>{
	
}
//=============类上确定接口的泛型===============
class InterImpl2 implements Inter<String>{

	@Override
	public void show(String t) {
		System.out.println("show:"+t);
	}
}

泛型_通配符

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.text.html.HTMLDocument.Iterator;

//GenericDemo7
class ExtendsDemo3 {
	public static void main(String[] args) {	
		List<Student> list=new ArrayList<Student>();
		
		list.add(new Student("abc1",21));
		list.add(new Student("abc2",22));
		list.add(new Student("abc3",23));
		list.add(new Student("abc4",24));
	
		printCollection(list);
		
		Set<String> set=new HashSet<String>();
		set.add("haha");
		set.add("xixi");
		set.add("hoho");
		
		printCollection(set);
		
	}

	private static void printCollection(Collection<?> coll) {//在不明确具体类型的情况下,可以使用通配符来表示。
		for(java.util.Iterator<?> it=coll.iterator();it.hasNext();) {
			Object obj=it.next();
			System.out.println(obj);
		}
	}
}

泛型_限定

泛型的限定:

extends E:接收E类型或者E的子类型。泛型上限
? super E:接收E类型或者E的父类型。泛型下限
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.text.html.HTMLDocument.Iterator;

//GenericDemo7
class ExtendsDemo3 {
	public static void main(String[] args) {	
		List<Student> list=new ArrayList<Student>();
		
		list.add(new Student("abc1",21));
		list.add(new Student("abc2",22));
		list.add(new Student("abc3",23));
		list.add(new Student("abc4",24));
	
		printCollection(list);
		
		Set<Worker> set=new HashSet<Worker>();
		set.add(new Worker("haha",23));
		set.add(new Worker("xixi",24));
		set.add(new Worker("hoho",21));
		set.add(new Worker("haha",29));
	
		
		printCollection(set);
		
	}

	private static void printCollection(Collection<? extends Person> coll) {
	//在不明确具体类型的情况下,可以使用通配符来表示。
		for(java.util.Iterator<? extends Person> it=coll.iterator();it.hasNext();) {
			Person p=it.next();
			System.out.println(p.getName());
		}
	}
}

泛型_限定应用

显示泛型限定在api中的体现。
TreeSet的构造函数。

TreeSet(Collection<? extends E> coll);

上限?

什么时候会用到上限呢?
一般往集合存储元素时。如果集合定义了E类型,通常情况下应该存储E类型的对象。
对于E的子类型的对象E类型也可以接受。所以这时可以将泛型从E改为? Extends E

import java.util.ArrayList;
import java.util.Collection;
import java.util.TreeSet;


//GenericDemo9
class ExtendsDemo3 {
	public static void main(String[] args) {
		
		Collection<Student> coll=new ArrayList<Student>();
		coll.add(new Student("abc1",21));
		coll.add(new Student("abc2",22));
		coll.add(new Student("abc3",23));
		coll.add(new Student("abc4",24));
		
		TreeSet<Person> ts=new TreeSet<Person>(coll);
		ts.add(new Person("abc8",21));
		
		for (java.util.Iterator<Person> it= ts.iterator(); it.hasNext();) {
			Person person =  it.next();
			System.out.println(person.getName());
		}
			
		}
		
	}
	
class MyTreeSet<E>{
	MyTreeSet(){
		
	}
	MyTreeSet(Collection<? extends E> c){
		
	}
}

下限

什么时候会用到下限呢?
当从容器中取出元素操作时,可以用E类型接收,也可以用E的父类型接收。

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


//GenericDemo9
class ExtendsDemo3 {
	public static void main(String[] args) {
		
		//创建一个比较器。
		Comparator<Person> comp=new Comparator<Person>() {

			@Override
			public int compare(Person o1, Person o2) {
				int temp=o1.getAge()-o2.getAge();
				return temp==0?o1.getName().compareTo(o2.getName()):temp;
			}
			
		};
		
		TreeSet<Student> ts=new TreeSet<Student>(comp);
		ts.add(new Student("abc1",21));
		ts.add(new Student("abc2",28));
		ts.add(new Student("abc3",23));
		ts.add(new Student("abc4",25));
		
		TreeSet<Worker> ts1=new TreeSet<Worker>(comp);
		ts1.add(new Worker("abc11",21));
		ts1.add(new Worker("abc22",27));
		ts1.add(new Worker("abc33",22));
		ts1.add(new Worker("abc44",29));
		
		for (Iterator<Student> it = ts.iterator(); it.hasNext();) {
			Student student =  it.next();
			System.out.println(student);
		}
	}
}
	
class YouTreeSet<E>{
	YouTreeSet(Comparator<? super E> comparator){
		
	}
	YouTreeSet(Collection c){
		
	}
}

集合框架_Map

特点&常见方法

Map:双列集合,一次存一对,键值对。要保证键的唯一性。
共性的功能:
1.添加
v put(key,value);
putAll(Map<k,v> map)

2.删除
void clear();
v remove(key);

3.判断
boolean contiansKey(object);
boolean contiansValue(object);
boolean isEmpty();

4.获取
V get(Value);
int size();

演示:

import java.util.HashMap;
import java.util.Map;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		Map<Integer,String> map=new HashMap<Integer,String>();
		methodDemo(map);
		/*
		 * 需求:Map集合中存储学号,姓名。
		 */
		
		
	}
	
	public static void methodDemo(Map<Integer,String> map) {
		//存储键值对。如果键相同,会出现值覆盖。
		System.out.println(map.put(3, "xiaoqiang"));//结果为null
		System.out.println(map.put(3, "erhu"));//返回的是旧值。结果为xiaoqiang
		map.put(7, "wangcai");
		map.put(2, "daniu");
		
		//System.out.println(map.remove(7));//wangcai,移除会改变长度
		System.out.println(map.get(7));//wangcai
		
		System.out.println(map);//{2=daniu, 3=erhu, 7=wangcai}
	}
}

keySet方法

keySet方法。取出所有的键,并存储到set集合中。
map集合没有迭代器,但是可以将map集合转成set集合,再使用迭代器即可。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		/*
		 * 取出map中所有的元素。
		 * map存储姓名--归属地。
		 */
		
		Map<String,String> map=new HashMap<String,String>();
		
		map.put("xiaoqiang","Beijing");
		map.put("wangcai","funiushan");
		map.put("daniu","heifengzhai");
		map.put("erhu","wohudong");
		
		//keySet方法。取出所有的键,并存储到set集合中
		Set<String> keySet=map.keySet();
		for (Iterator<String> it = keySet.iterator(); it.hasNext();) {
			String key=it.next();
			String value=map.get(key);
			System.out.println(key+":"+value);//结果是无序的
		}
	}
}

entrySet()方法

Map.Entry其实就是一个Map接口中的内部接口。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		/*
		 * 取出map中所有的元素。
		 * map存储姓名--归属地。
		 */
		
		Map<String,String> map=new HashMap<String,String>();
		
		map.put("xiaoqiang","Beijing");
		map.put("wangcai","funiushan");
		map.put("daniu","heifengzhai");
		map.put("erhu","wohudong");
		
		//演示entrySet
		Set<Map.Entry<String,String>> entrySet=map.entrySet();
		
		for (Iterator<Map.Entry<String,String>> it = entrySet.iterator(); it.hasNext();) {
			Map.Entry<String, String> entry = it.next();
			String key=entry.getKey();
			String value=entry.getValue();
			System.out.println(key+":"+value);
		}
	}
}

Map.Entry的解释:

interface MyMap{
	//entry就是map接口中的内部接口
	public static interface MyEntry{
	}
}
class MyDemo implements MyMap.MyEntry{
}

value()方法

可以重复,所以是Collection

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		/*
		 * 取出map中所有的元素。
		 * map存储姓名--归属地。
		 */
		
		Map<String,String> map=new HashMap<String,String>();
		
		map.put("xiaoqiang","Beijing");
		map.put("wangcai","funiushan");
		map.put("daniu","heifengzhai");
		map.put("erhu","wohudong");
		map.put("zhizunbao","wohudong");
		
		//演示value()所有的值
		Collection<String> values=map.values();
		for (Iterator<String> it = values.iterator(); it.hasNext();) {
			String value = it.next();
			System.out.println(value);
		}
	}
}

Map_常见子类

Map
      |--Hashtable:哈希表,同步,JDK1.0,不允许null键,null值。
      |--HashMap:哈希表,是不同步的,允许null键,null值。
      |--TreeMap:二叉树,不同步的。可以对map集合中的键进行排序。

HashSet和TreeSet是以HashMap和TreeMap为底层。

Map存储自定义对象练习

需求:
学生对象(姓名;年龄)都有对应的归属地。
key=Student value=String.

1.将员工和归属存储到HashMap集合中并取出。
同姓名同年龄视为同一个员工。

2.按照员工的年龄进行升序排序并取出。
按照员工的姓名进行升序排序并取出。

需求1:

public class Employee {
	private String name;
	private int age;
	
	
	public Employee() {
		super();
	}
	
	public Employee(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	@Override
	public String toString() {
		return "Employee [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		/*
		 * 1.将员工和归属存储到HashMap集合中并取出。同姓名同年龄视为同一个学生。
		 */
		
		Map<Employee,String> map=new HashMap<Employee,String>();
		
		map.put(new Employee("xiaozhang",24), "北京");
		map.put(new Employee("laoli",34), "上海");
		map.put(new Employee("mingming",26), "南京");
		map.put(new Employee("xili",30), "广州");
		map.put(new Employee("laoli",34), "铁岭");
		
		
		Set<Employee> keySet=map.keySet();
		for(Employee employee:keySet) {
			String value=map.get(employee);
			System.out.println(employee.getName()+":"+employee.getAge()+"..."+value);
		}
		/*for (Iterator<Employee> it = keySet.iterator(); it.hasNext();) {
			Employee employee = it.next();			
		}*/
		
		/*for (Employee employee:map.keySet()) {	
		}*/
	}
}

需求2:

public class Employee implements Comparable<Employee>{
	private String name;
	private int age;
	
	
	public Employee() {
		super();
	}
	
	public Employee(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	@Override
	public String toString() {
		return "Employee [name=" + name + ", age=" + age + "]";
	}


	@Override
	public int compareTo(Employee o) {
		
		int temp=this.age-o.age;
		return temp==0?this.name.compareTo(o.name):temp;
	}
}
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		/*
		 * 按照员工的年龄进行升序排序并取出。
		 */
		
		Map<Employee,String> map=new TreeMap<Employee,String>();
		
		map.put(new Employee("xiaozhang",24), "北京");
		map.put(new Employee("laoli",34), "上海");
		map.put(new Employee("mingming",26), "南京");
		map.put(new Employee("xili",30), "广州");
		map.put(new Employee("laoli",34), "铁岭");
		
		//entrySet
		Set<Map.Entry<Employee,String>> entrySet=map.entrySet();
		for(Map.Entry<Employee,String> me:entrySet) {
			Employee key=me.getKey();
			String value=me.getValue();
			System.out.println(key.getName()+":"+key.getAge()+"..."+value);
		}
	}
}

或者

public class Employee {
	private String name;
	private int age;
	
	
	public Employee() {
		super();
	}
	
	public Employee(String name, int age) {
		super();
		this.name = name;
		this.age = 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;
	}

	@Override
	public String toString() {
		return "Employee [name=" + name + ", age=" + age + "]";
	}
}
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		/*
		 * 按照员工的姓名进行升序排序并取出。
		 */
		//自定义比较器
		Comparator<Employee> comparator=new Comparator<Employee>() {

			public int compare(Employee o1, Employee o2) {
				int temp=o1.getName().compareTo(o2.getName());
				return temp==0?o1.getAge()-o2.getAge():temp;
			}
			
		};
		
		Map<Employee,String> map=new TreeMap<Employee,String>(comparator);
		
		map.put(new Employee("xiaozhang",24), "北京");
		map.put(new Employee("laoli",34), "上海");
		map.put(new Employee("mingming",26), "南京");
		map.put(new Employee("xili",30), "广州");
		map.put(new Employee("laoli",34), "铁岭");
		
		//entrySet
		Set<Map.Entry<Employee,String>> entrySet=map.entrySet();
		for(Map.Entry<Employee,String> me:entrySet) {
			Employee key=me.getKey();
			String value=me.getValue();
			System.out.println(key.getName()+":"+key.getAge()+"..."+value);
		}
	}
}

LinkedHashMap

无序变有序
把HashMap改成LinkedHashMap即可。

Map查表法

当什么时候使用map集合呢?
当需求中出现映射关系时,应该最先想到map集合。

import java.util.HashMap;
import java.util.Map;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		String cnweek=getCnWeek(3);
		System.out.println(cnweek);
		String EnWeek=getEnWeek(cnweek);
		System.out.println(EnWeek);
	}
	
	//根据中文星期,获取对应的英文星期。
	//中文和英文相对应。可以建立表。没有有序的编号,只能通过map集合。
	public static String getEnWeek(String cnWeek) {
		
		//创建一个表。
		Map<String,String> map=new HashMap<String,String>();
		
		map.put("星期一", "Monday");
		map.put("星期二", "TuesDday");
		map.put("星期三", "Wednesday");
		map.put("星期四", "Thursday");
		map.put("星期五", "Friday");
		map.put("星期六", "Saturday");
		map.put("星期日", "Sunday");
		
		return map.get(cnWeek);
	}
	/*
	 * 根据用户的指定的数据获取对应的星期。
	 */
	public static String getCnWeek(int num) {
		if(num>7||num<=0) {
			throw new NoWeekException(num+",没有对应的星期");
		}
		String[] cnWeeks= {"","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
		return cnWeeks[num];
	}
}

Map查表法练习

需求:
“bwbaerbctyxacecrtdcvr”
获取字符串中每一个字母出现的次数,要求结果格式:a(2)b(1)d(3)……

思路:
1.获取到字母。
2.如何获取字母次数?比较?
发现字母和次数有对应关系。而且对应关系的一方具备唯一性。
就想到了Map集合。map集合就是一张表。
3.使用查表法就可以。
先查第一个字母在表中的次数。如果次数不存在,说明是第一次出现,将该字母和1存储到表中。
以此类推。当要查的次数存在,将次数取出并自增后,再和对应的字母存储到表中,map表的特点是相同键,值覆盖。
4.查完每一个字母后,表中存储的就是每一个字母出现的次数。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

//MapDemo
class ExtendsDemo3 {
	public static void main(String[] args) {
		String str="bwa+ercty=xace-crtdcvr";
		String char_count=getCharCount(str);
		System.out.println(char_count);
	}

	private static String getCharCount(String str) {
		//1.将字符串转成字符数组。
		char[] chs=str.toCharArray();
		
		//2.定义map集合表。
		Map<Character,Integer> map=new TreeMap<Character,Integer>();		
		//3.遍历字符数组。获取每一个字母。
		for (int i = 0; i < chs.length; i++) {
			//只对字母操作。
			if(!(chs[i]>='a'&&chs[i]<='z'||chs[i]>='A'&&chs[i]<='Z'))
				continue;
			
			//将遍历到的字母作为键去查表。获取值。
			Integer value=map.get(chs[i]);
			int count=0;//用于记录次数。
			//如果次数存在,就用count记录该次数。如果次数不存在,就不记录,只对count自增变成1.
			if(value!=null){
				count=value;
			}
			count++;
			map.put(chs[i], count);
			
			//=======或者下面这个方法====
			/*if(value==null) {
				map.put(chs[i], 1);
			}else {
				value++;
				map.put(chs[i],value);
			}*/
			
			
			
		}
		
		return toString(map);
	}
/*
 * 将map集合中的元素转成指定格式的字符串。a(2)b(1)d(3)……
 */
	private static String toString(Map<Character, Integer> map) {
		//1.数据多,无论类型是什么,最终都要变成字符串,所以可以使用StringBuilder
		StringBuilder sb=new StringBuilder();
	
		//2.遍历集合map。
		Set<Character> keySet=map.keySet();
		for (Iterator<Character> it = keySet.iterator(); it.hasNext();) {
			Character key = it.next();
			Integer value=map.get(key);
			
			//将键值存储到sb中
			sb.append(key+"("+value+")");
			
		}
		return sb.toString();
	}
}

Collections方法

集合框架的工具类:
Collections:定义的都是操作Collection的静态方法。

排序&逆序

1.对list排序

sort(list);

排序方法上泛型的具体解释:

class Student implements Comparable<Person>
{
	public int compareTo(Person p) {
		
	}
}
public static<T extends Comparable<? super T> > void sort(List<T> list)//加泛型 这里的Comparable是接口
{
}
public static void sort(List<Student> list)
{
	stu1.compareTo(stu2);
}

2.逆序

reverseOrder();

具体方法演示:

import java.util.Comparator;

public class ComparatorByLength implements Comparator<String> {	
	@Override
	public int compare(String o1, String o2) {
		int temp=o1.length()-o2.length();
		return temp==0? o1.compareTo(o2):temp;
	}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//Collecions
class ExtendsDemo3 {
	public static void main(String[] args) {
		methodDemo1();
	}

	private static void methodDemo1() {
		List<String> list=new ArrayList<String>();
		list.add("abcd");
		list.add("z");
		list.add("hehe");
		list.add("nba");
		
		System.out.println(list);
		
		//对list排序。自然排序。使用的是元素的comparaTo方法。
		Collections.sort(list);
		System.out.println(list);
		
		//想按照长度排序
		Collections.sort(list,new ComparatorByLength());
		System.out.println(list);
		
		//强行逆转比较器的顺序,Collections.reverseOrder();
		Collections.sort(list,Collections.reverseOrder(new ComparatorByLength()));
		System.out.println(list);
	}
}

最值&同步方法

3.最值

.max min
具体演示:

import java.util.Comparator;

public class ComparatorByLength implements Comparator<String> {	
	@Override
	public int compare(String o1, String o2) {
		int temp=o1.length()-o2.length();
		return temp==0? o1.compareTo(o2):temp;
	}
}
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.swing.text.html.HTMLDocument.Iterator;

//Collecions
class ExtendsDemo3 {
	public static void main(String[] args) {
		Collection<String> coll=new ArrayList<String>();
		coll.add("abcd");
		coll.add("aa");
		coll.add("zzzz");
		coll.add("nba");
		
		String max=getMax(coll);
		String max1=Collections.max(coll);//和上一行的功能其实是一样的
		String max2=Collections.max(coll,new ComparatorByLength());//找最长的
		System.out.println(max);
		System.out.println(max1);
		System.out.println(max2);
	}
	/*
	 * 模拟一个获取集合最大值的功能。
	 */
	
	public static<T extends Object&Comparable<? super T>> T getMax(Collection<? extends T> coll) {//传进来的是T  方法是T  返回是T
	//public static String getMax(Collection<String> coll) {//传进来的是T  方法是T  返回是T
		
		
		//Collection只支持迭代
		//java.util.Iterator<String> it=coll.iterator();
		java.util.Iterator<? extends T> it= coll.iterator();//迭代器哪里来的,就要和哪里一致。
		
		//1.定义变量记录容器中其中一个。
		//String max=it.next();//第一个
		T max=it.next();
		
		//2.遍历容器所有的元素。
		while(it.hasNext()) {
			//String temp=it.next();//第二个
			T temp=it.next();
			//3.在遍历过程中进行比较,只要比变量中的值哒。用变量记录下来。
			if(temp.compareTo(max)>0) {
				max=temp;
			}
		}
		return max;
	}
}

练习:
模拟一个Collection min(Collection coll,Comparator comp)

4.二分查找

5.将非同步集合转成同步集合。

同步重点
ArrayList和List有什么区别:
List安全 ArrayList不安全,但是ArrayList快。
多线程可以用集合框架工具类Collections中的同步集合方法,将非同步转成同步
(JDK1.2没有不同步)
Collections中有一个可以将非同步集合转成同步集合的方法。

sysnchronized集合(非同步集合)

Arrays方法

用来操作数组的工具类,方法都是静态的。

import java.util.Arrays;

//Arrays
class ExtendsDemo3 {
	public static void main(String[] args) {
		Integer[] arr=new Integer[3];
		swap(arr,1,2);
		
		String[] arr1=new String[3];
		swap(arr1,1,2);
		
		int[] arr2= {45,23,78,11,99};
		System.out.println(Arrays.toString(arr2));
	}
	
	/*public static void swap(int[] arr,int x,int y) {
		int temp=arr[x];
		arr[x]=arr[y];
		arr[y]=temp;
	}*/
	
	public static<T> void swap(T[] arr,int x,int y) {
		T temp=arr[x];
		arr[x]=arr[y];
		arr[y]=temp;
	}
}

数组转成集合

Arrays–>Collections

Arrays.asList();

数组转成集合,就是为了使用集合的方法操作数组中的元素。
**注意:不能使用集合的增删方法。不能改变长度。**因为数组长度不可变

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//Arrays
class ExtendsDemo3 {
	public static void main(String[] args) {
		String[] strs= {"abc","haha","nba","zz"};
		
		boolean b=myContains(strs,"nba");
		System.out.println(b);
		
		//发现集合中本身有这个方法contains
		//将数组转成集合。即可。
		List<String> list=Arrays.asList(strs);
		
		list.add("qq");// java.lang.UnsupportedOperationException
		//注意:不能使用集合的增删方法。
		
		System.out.println(list.contains("nba"));
	}
	
	public static boolean myContains(String[] arr,String key) {
		
		for (int i = 0; i < arr.length; i++) {
			String str = arr[i];
			
			if(str.equals(key))
				return true;
		}
		return false;
	}
}

如果数组中都是引用数据类型,转成集合时,数组元素直接作为集合元素。
如果数组中的都是基本数据类型,会将数组对象作为集合中的元素。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//Arrays
class ExtendsDemo3 {
	public static void main(String[] args) {

		int[] arr= {45,23,78,11,99};
		
		List list=Arrays.asList(arr);
		System.out.println(list.size());//结果为1
		System.out.println(list.get(0));//结果为[I@15db9742
	}
}

如何使用泛型
int<>也是元素类型

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//Arrays
class ExtendsDemo3 {
	public static void main(String[] args) {

		int[] arr= {45,23,78,11,99};
		
		List<int[]> list=Arrays.asList(arr);//写元素类型
		System.out.println(list.size());//
		System.out.println(list.get(0));//
	}
}

把int改为Integer:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//Arrays
class ExtendsDemo3 {
	public static void main(String[] args) {

		Integer[] arr= {45,23,78,11,99};
		
		List list=Arrays.asList(arr);//写元素类型
		System.out.println(list.size());//5
		System.out.println(list.get(0));//45
	}
}

集合转成数组

Collections–>Arrays

Collection.toArray(T[] a);

传入的数组长度如果小于集合长度,方法中会创建一个新的长度和集合长度一致的数组。
如果传入的数组长度大于等于集合长度,会使用传入的数组,所以建议长度定义为集合的size();

为什么要把集合转成数组?
就是为了限定对元素的操作,比如增删。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//Arrays
class ExtendsDemo3 {
	public static void main(String[] args) {

		//集合转成数组
		List<String> list=new ArrayList<String>();
		list.add("abc");
		list.add("haha");
		
		String[] arr=list.toArray(new String[3]);
		System.out.println(Arrays.toString(arr));//把数组转成字符串,结果为[abc, haha, null]
	}
}

可变参数

JDK1.5
可变参数需要注意,只能定义在参数列表的最后。

以前怎么写?

//ParamDemo
class ExtendsDemo3 {
	public static void main(String[] args) {

		int sum = add(4, 5);
		int sum1 = add1(4, 5, 6);
		
		int[] arr= {34,1,5,7};
		int sum2 = add2(arr);
	}

	private static int add(int i, int j) {
		return i + j;
	}

	private static int add1(int i, int j, int k) {
		return i + j + k;
	}
	
	public static int add2(int[] arr) {
		int sum=0;
		for (int i = 0; i < arr.length; i++) {
			sum=arr[i];
		}
		return sum;
	}
}

现在可以这么写:

//ParamDemo
class ExtendsDemo3 {
	public static void main(String[] args) {

		int sum=add(43,4,5,6,7);
		int sum1=add(43,4,5,6,7,8,9);
	}
	
	public static int add(int... arr) {
		int sum=0;
		for (int i = 0; i < arr.length; i++) {
			sum=arr[i];
		}
		return sum;
	}
}

静态导入

static

import  java.util.*;
import  static java.util.Collections.*;
import  static java.lang.System.*;

//StaticImportDemo
class ExtendsDemo3 {
	public static void main(String[] args) {

		List<String> list=new ArrayList<String>();
		list.add("a");
		list.add("c");
		//Collections.sort(list);
		//Collections.max(list);
		
		sort(list);//调用的都是静态方法
		System.out.println(max(list));
		out.print("hello");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值