JAVA------集合框架


一,概述
    数据多了用对象存,对象多了用集合存,常用的两种存对象的容器是数组和集合,数组和集合类容器的不同:
    1,数组虽然也可以存储对象,但长度是固定的,集合长度是可变的;
    2,数组中可以存储基本数据类型,集合中只能存储对象。
    3,数组只能储存单一类型的对象,集合可以则不同。
二,集合框架的形成与分类( Collection接口
     1,List:元素是有序的(怎么存进去的怎么取出来),元素可以重复,因为该集合体系有索引
         1.1  ArrayList:(线程不同步)底层的数据结构使用的是数组结构。特点:查询速度很快,但是增删稍慢
         1.2  LinkedList:底层使用的是链表数据结构。特点:查询很慢,增删速度非常的快
         1.3  Vector:(线程同步)底层是数组数据结构。ArrayList效率比它快,Vector查询慢,增删也慢,一般不用Vector
     2,Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复
         2.1 HashSet:(线程不同步)底层数据结构是hashtable(哈希表)。
               HashSet是如何保证元素的唯一性呢?
               Answer:通过元素的两个方法,hashCode和equals来完成,如果元素的hashcode值相同才会调用equals是否为true,如果元素的Hashcode值不同,就直接在该Hashcode对应的物理地址上分配空间存储对象。
                 PS:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法
         2.2  TreeSet:可以对Set集合中的元素进行排序。
               底层数据结构是二叉树,保证元素的唯一性的依据:compareTo方法return 0,就不唯一了;
               TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法也称这种方式为元素的自然顺序,或者叫做默认顺序。
               TreeSet的第二种排序方式当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性。在集合一初始化时,就有了比较方式,通过构造函数就能够实现
               两种排序方式(简述)
               (1),元素自身具备比较性(实现comparable接口,实现compareTo方法);
               (
2)当初始化集合的时候,传入一个比较器,这个比较器需要自定义一个类实现Comparator接口中的compare方法。 
                当两种排序方式都存在时,选取构造函数中的比较器更好,因为它初始化集合时就存在了,当Comparator比较器不符合要求,还可用Comparable接口中的方法。
      PS:Set集合的功能和Collection是一致的。
  3,集合框架的构成及分类图形结构如下
集合框架的构成及分类.png

4,为什么会出现这么多集合框架呢?
无标题.png
        如上图,这些存储方式都具备了一些相同的操作,将这些操作提取共同的部分,形成最父类的接口,子类只需继承父类并按照各自的操作方式实现父类的方法就行了。每一个容器对数据的存储方式称之为数据结构。
三,集合框架中的共性方法
1,增删和获取操作
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_1()
{		
	//创建一个集合容器,使用Collection接口的子类List接口中的已知实现子类ArrayList
	ArrayList<String> al=new ArrayList<String>();
	
	//1,添加元素
	al.add("java-01");
	al.add("java-02");
	al.add("java-03");
	al.add("java-04");
	
	//输出原集合
	sop(al);
	
	//2,删除元素
	al.remove("java-02");
	
	//3,获取个数,集合长度
	sop(al.size());
	
	//4,判断元素
	sop("al.contains('java-01') "+al.contains("java-01"));
	
	//清空集合中的所有元素
	al.clear();
	/*Iterator<String> iterator=al.iterator();
	while(iterator.hasNext())
	{
		sop(iterator.next(););
	}*/		
	sop(al);//输出改变后的集合	
	sop(al.isEmpty());//判断集合是否为空
}</span></span>
2,判断操作(containsAll,removeAll,retainAll)
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_2()
{
	ArrayList<String> arr=new ArrayList<String>();
	arr.add("java-01");
	arr.add("java-02");
	arr.add("java-03");
	arr.add("java-04");	
	ArrayList<String> arr2=new ArrayList<String>();
	arr2.add("java-03");
	arr2.add("java-05");
	arr2.add("java-06");
	arr2.add("java-04");
	
	sop(arr.containsAll(arr2));//判断arr中是否包含arr2中的所有元素,返回值是boolean类型
	sop(arr);
	sop(arr.retainAll(arr2));//取交集,all中只会保留和all2相同的元素
	sop(arr);
	arr.removeAll(arr2);//删除arr中与arr2中相同的元素,返回值是boolean
	sop(arr);
}</span></span>
3,迭代器
     3.1 什么是迭代器?(形象的比喻:电玩城里面的投币夹小娃娃的游戏机,箱子相当于容器,夹子就是迭代器)
          其实就是集合取出元素的方式,因为每个集合都有一种取出的方式,而实现取出这种功能不是一两个方法就能搞定的,因此将取出这种功能封装成一个对象,每一个集合里面都封装了一个取出自身元素的对象,而取出的方式因为每个对象而发生改变。将取出的类叫做迭代器,迭代器定义在集合的内部,因为迭代器要操作的是集合内部的数据,因此将迭代器这个接口定义在集合的内部,用内部类实现,这样就可以直接访问集合内部的元素,那么取出的方式就被定义成了内部类,而每一个容器的数据结构也不同,所以取出的动作和细节也不一样,但是都是共性内容(判断和取出),那么就可以进行共抽取,形成一个迭代器的接口,定义集合时只需在内部实现这个接口就Ok 了。
     3.2 这些内部类都符合一个规则,该规则是Iterator,如何获取集合的取出对象呢?
        通过一个对外提供的方法,iterator()方法。  
        使用方法类似于下例:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_get()//取出
{
	ArrayList arr=new ArrayList();
	arr.add("java-01");
	arr.add("java-02");
	arr.add("java-03");
	arr.add("java-04");
	
	Iterator it=arr.iterator();//获取迭代器,用于取出集合中的元素
	while(it.hasNext()){
		sop(it.next());
	}
	
	//这种方式更节约内存,It用完之后就释放了
	for(Iterator It=arr.iterator();It.hasNext();){
		sop(It.next());
	}
}</span></span>
四,List体系特有的方法(凡是能够操作角标的方法都是该体系特有的方法
    1, 增
       add(int  index,Object  element);在指定索引位置添加元素
       addAll(int  index,Collection  col) ;将col集合中所有值添加到当前对象中
    2, 删
       remove(int  index);移除索引位置为index的元素
       removeAll(Collection  col);移除该对象中和col集合中相同的元素
    3, 改
       set(int  index,Object  element);修改索引为index的值为element
    4,查
       get(int  index);获取索引位置为index的元素值
       subList(int  start,int  end);
       listIterator();List集合特有的迭代器,ListIterator是Iterator的子接口
       PS:在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常,所以,在使用迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,listIterator来实现,这个是List中特有的迭代器, 该接口只能通过List集合的对象调用lsitIterator方法获取 。
    5.Vetctor特有的枚举法遍历集合
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class VectorDemo {
	public static void main(String args[])
	{
		Vector v=new Vector();
		v.add("Java-1");
		v.add("Java-2");
		v.add("Java-3");
		v.add("Java-4");
		
		v.elementAt(0);
		//用枚举的方式获取所有元素
		Enumeration en=v.elements();
		while(en.hasMoreElements())
		{
			System.out.println(en.nextElement());
		}
		
		//迭代器
		Iterator it=v.iterator();
		while(it.hasNext())
		{
			System.out.println(it.next());
		}
	}
}</span></span>
       分析:Vector中带elements的方法都是它的特有方法,他是容器的始祖,后被ArrayList代替了,枚举就是Vector特有的取出方式,同时它也具备迭代器和遍历的方式。 发现枚举和迭代器很像,其实枚举和迭代器是一样的,因为枚举的名称和方法的名称都过长,所以被迭代器取代了。
    6,LinkedList中特有的方法
     addFirst();
     addLast();
     
     getFirst();
     getLast();获取元素但不删除元素
     
     removeFirst(); 从1.6版本开始使用pollFirst()更好,当集合中没有元素时,会出现NoSuchElementsException,
                            而pollFirst()不用抛出异常,返回null
     removeLast();获取元素的同时删除元素
     
     pollFirst();
     pollLast();获取元素的同时删除元素
     
     peekFirst();
     peekLast();获取值不删除元素
     
     offerFirst():添加元素
     offerLast()
下面这个类是对以上方法的使用:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class LinkedListDemo {
	public static void main(String args[])
	{
		LinkedList link=new LinkedList();
		link.add("java-5");
		link.add("Java-1");
	    link.add("Java-2");
		link.add("Java-3");
		link.add("Java-4");
		link.addFirst("Java-0");
		link.addLast("Java-6");
		sop(link.getFirst());
		sop(link.getLast());
		sop(link.size());
		sop(link.removeFirst());
		sop(link);
		
		Iterator it=link.iterator();
		while(it.hasNext())
		{
			sop(it.next());
		}
		
		//获取所有元素的另一种方法
		while(!link.isEmpty())
		{
			sop(link.removeFirst());//如果Link为空,会出现不存在该元素异常
		}
	}
	private static void sop(Object obj) {
		System.out.println(obj);
	}
}</span></span>
五,List练习
1,LinkedList练习
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*  需求:使用LinkedList模拟一个堆栈或者队列数据结构
    
    堆栈:先进后出,如同一个杯子
    队列:先进先出First in First out FIFO 如同一个水管
 */
import java.util.*;
//将链表封装
class Queue<E>
{
	private LinkedList<E> link=null;
	
	Queue()
	{
		this.link=new LinkedList<E>();
	}
	
	public void myAdd(E e)
	{
		link.add(e);
	}
	
	public E myGet()
	{
		return link.removeLast();//先进后出,堆栈
		//return link.removeFirst();先进先出,队列
	}
	
	public boolean isNull()
	{
		return link.isEmpty();
	}
}
public class LinkedListTest {
	public static void main(String args[])
	{
		Queue<String> que=new Queue<String>();
		que.myAdd("java-1");
		que.myAdd("jav-2");
		que.myAdd("java-3");
		que.myAdd("java-4");
		while(!que.isNull())
		{
			sop(que.myGet());
		}
	}
	private static void sop(Object obj) {
		System.out.println(obj);
	}
}</span></span>
2,ArrayList练习
例子一:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
 需求:去除ArrayList集合中的重复元素
 */
import java.util.*;
public class ArrayListTest {
	public static void main(String args[])
	{
		ArrayList arr=new ArrayList();
		arr.add("1");
		arr.add("2");
		arr.add("1");
		arr.add("2");
		arr.add("1");
		arr.add("2");
		
		sop(singleNew(arr));	
	}
	private static void sop(Object obj) {
		System.out.println(obj.toString());
	}
	
	public static ArrayList singleNew(ArrayList arr)
	{
		ArrayList newArr=new ArrayList();
		Iterator it=arr.iterator();
		while(it.hasNext())
		{
			Object obj=it.next();
			if(!newArr.contains(obj))//如果新的集合中没有该元素,将该元素添加到新集合,否则继续向下查找
				newArr.add(obj);
		}
		return newArr;
	}
}</span></span>

例子二:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
 将自定义对象作为元素存到ArrayList集合中,并去除重复元素
 
 比如:存人对象,同姓名同年龄,视为同一个人,为重复元素。
 
 思路:1,对人描述,将数据封装进人对象。
       2,定义容器,将人存入。
       3,取出。
 PS:List集合判断元素是否相同,依据是元素的equals方法
 */
import java.util.*;
public class ArrayListDemo {
	public static void main(String args[])
	{
		ArrayList arr=new ArrayList();
		arr.add(new Person("zhangsan","nan",23));
		arr.add(new Person("lisi","nan",30));
		arr.add(new Person("wangwu","nv",45));
		arr.add(new Person("zhangsan","nan",23));
		arr.add(new Person("lisi","nan",30));
		arr.add(new Person("wangwu","nv",45));
		
		arr.remove(new Person("wangwu","nv",45));//如果没有修改equals方法,这个删除时不会成功的,因为删除前肯定要调用equals方法判断当前对象与集合中对象是否相等,
		                                         //相等再删除,如果不重写equals方法,它就会按照默认的方法判断两个对象是否相等,不能按照我们判定对象相同的标准判定。
		Out(arr);
		arr=singleNew(arr);
		sop("删除重复元素之后:");
		Out(arr);
		
		
	}
	private static void sop(Object obj) {
		System.out.println(obj.toString());
	}
	
	private static void Out(ArrayList arr)
	{
		Iterator it=arr.iterator();
		while(it.hasNext())
		{
			Person p=(Person)it.next();
			sop("name: "+p.getName()+";sex: "+p.getSex()+";age: "+p.getAge());
		}
	}
	public static ArrayList singleNew(ArrayList arr)
	{
		ArrayList newArr=new ArrayList();
		Iterator it=arr.iterator();
		while(it.hasNext())
		{
			Object obj=it.next();
			//其实contains底层调用的是equals方法
			if(!newArr.contains(obj))//它不知道什么是判断相等的标准,是根据equals来判断是否相等,这儿在Person类中复写equals来实现判断相等与否
				newArr.add(obj);
		}
		return newArr;
	}
}
class Person//创建人的类
{
	private String name,sex;
	private int age;
	
	Person(String name,String sex,int age)
	{
		this.name=name;
		this.age=age;
		this.sex=sex;
	}
	public boolean equals(Object obj)//Person继承自Object,现在这是覆盖父类中的equals方法
	{
		if(!(obj instanceof Person))//判断obj是否是Person类型数据
			return false;
		Person p=(Person)obj;
		return this.name.equals(p.getName())&&(this.age==p.getAge());
	}
	
	public String getName()
	{
		return this.name;
	}
	public int getAge()
	{
		return this.age;
	}
	public String getSex()
	{
		return this.sex;
	}	
}</span></span>

五,Set练习
1,HashSet练习
    1.1,验证Set的无序不重复
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">//用来验证hashset里面的方法
public static void method_1()
{
	HashSet hs=new HashSet();//按照hash值排序的
	hs.add("aa");
	hs.add("bb");
	hs.add("cc");
	hs.add("dd");
	hs.add("dd");//无序不重复
	sop(hs.add("ee"));
	sop(hs.add("ee"));//第二次没有添加进去
	
	//Set取出的方法就只有迭代器
	Iterator it=hs.iterator();
	while(it.hasNext())
	{
		sop(it.next());//无序的
	}
	sop(hs);
}</span></span>

       分析:根据输出结果可以看出,第二次添加ee时返回值是fasle,没有添加成功。
   1.2,hashset集合中存入自定义对象,姓名和年龄相同为一个人,存入重复元素测试
       分析: 首先Set的特点是无序且元素不重复,想要存入重复元素测试,首先得判断元素是否相等,而hashSet中判断元素是否相同先调用hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。 
       PS: 元素相等哈希值一定相等,哈希值相同不一定是同一个元素。
       练习一代码如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
 往hashset集合中存入自定义对象,姓名和年龄相同为一个人,重复元素测试
 */
import java.util.*;
public class HashSetDemo {
	public static void main(String args[])
	{
		HashSet hs=new HashSet();//按照hash值排序的
		hs.add(new Person("a1",12));//存数据先看地址
		hs.add(new Person("a2",13));
		hs.add(new Person("a3",14));
		hs.add(new Person("a3",14));
		hs.add(new Person("a2",13));
		hs.add(new Person("a3",14));
		sop(hs.contains(new Person("a3",14)));
		sop(hs.remove(new Person("a3",14)));
		
		Iterator it=hs.iterator();
		while(it.hasNext())
		{
			Person p=(Person)it.next();
			sop("name--> "+p.getName()+"||Age--> "+p.getAge());
		}
	}
	private 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 boolean equals(Object obj)//Person继承自Object,现在这是覆盖父类中的equals方法
	{
		if(!(obj instanceof Person))//判断obj是否是Person类型数据
			return false;
		Person p=(Person)obj;
		System.out.println(this.name+"...equals..."+p.name);
		return this.name.equals(p.getName())&&(this.age==p.getAge());
	}
	public int hashCode()
	{
		System.out.println(this.name+"......hashCode");
		return name.hashCode()+34*age;
		//return 60;//当hash值相同时才会去调用equals方法,为了调用equals方法去比较,这儿把所有的哈希值都设置为一样的
	}
	public String getName()
	{
		return this.name;
	}
	public int getAge()
	{
		return this.age;
	}	
}</span></span>

分析:从输出结果可以看出,每添加一个元素,都会调用一次hashCode,如果哈希值相同,还会调用equals方法判定,这样保证了元素的唯一性和存储的高效性。同时,当调用remove和contains方法时,也调用了hashCode和equals方法。
    2,TreeSet练习
      2.1  TreeSet会按照字典序给存进来的元素排序
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_1()
{
	TreeSet ts=new TreeSet();
	ts.add("1");
	ts.add("10");
	ts.add("45");
	ts.add("2");
	ts.add("a");
	
	Iterator it=ts.iterator();
	while(it.hasNext())
	{
		sop(it.next());
	}
}</span></span>

        2.2 往TreeSet集合中存自定义对象Student,按照学生的年龄进行排序。当主要条件相同时,一定要判断次要条件(先按照年龄排序,如果年龄相同,再判断姓名是否相同)
           分析:TreeSet 底层的数据结构是二叉树,存入元素前必须先判断元素的大小,而其判断元素大小是通过元素内部复写的compareTo方法或者创建TreeSet对象时构 造函数中创建的Comparator子类对象中的compare方法。因此,当添加自定义的数据类型的元素时,TreeSet对象不知道如何判断元素大 小,因此添加自定义数据类型的元素时必须重写compareTo方法或者实现Comparator接口。
方式一:以复写compareTo方式实现需求的代码如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
   需求:
	   往TreeSet集合中存自定义对象Studen,想按照学生的年龄进行排序。当主要条件相同时,一定要判断次要条件(先按照年龄排序,如果年龄相同,再判断姓名是否相同)
	   当添加自定义对象时,会出现java.lang.ClassCastException异常,因为找不到比较的对象不知道谁大谁小           
 */
import java.util.*;
public class TreeSetDemo_01 {
	public static void main(String args[])
	{
		TreeSet ts=new TreeSet();//二叉树排序,往里面存的数必须具备比较性
		ts.add(new Student("zhangsan",12));
		ts.add(new Student("lisi",36));
		System.out.println(ts.add(new Student("wangwu",34)));
		System.out.println(ts.add(new Student("zhangsan",12)));
		
		Iterator it=ts.iterator();
		while(it.hasNext())
		{
			Student stu=(Student)it.next();
			sop(stu.getName()+"||"+stu.getAge());
		}
	}
	private static void sop(Object obj) {
		System.out.println(obj);
	}
}
class Student implements Comparable//为了具备可比较性,实现一个接口,强制让学生具备比较性
{
	private String name;
	private int age;
	Student(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
	
	public String  getName()
	{
		return this.name;
	}
	public int getAge()
	{
		return this.age;
	}
    @Override
	public int compareTo(Object obj) {
		if(!(obj instanceof Student))
			throw new RuntimeException("不是学生对象");
		Student s=(Student)obj;
		System.out.println(this.age+"----"+s.getAge());
		if(this.age==s.getAge())
			return this.name.compareTo(s.name);
	    return this.age-s.getAge();
	}
}</span></span>

方式二:以实现Comparator接口方式实现需求的代码如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
/*
   当元素自身不具备比较性,或者具备的比较性不是所需要的,现在就构造一个比较器
 */
public class TreeSetDemo_04 {
	public static void main(String args[])
	{
		TreeSet ts=new TreeSet(new MyCompare());//MyCompare是自己定义的一个比较器
		ts.add(new Person("zhangsan",12));
		ts.add(new Person("lisi",36));
		ts.add(new Person("wangwu",34));
		ts.add(new Person("wangwu",34));
		ts.add(new Person("lisi",36));
		
		Iterator it=ts.iterator();
		while(it.hasNext())
		{
			Person stu=(Person)it.next();
			sop(stu.getName()+"||"+stu.getAge());
		}
	}
	private 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 String  getName()
	{
		return this.name;
	}
	public int getAge()
	{
		return this.age;
	}
}
class MyCompare implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		Person s1=(Person)o1;
		Person s2=(Person)o2;
		int num=s1.getName().compareTo(s2.getName());
		if(num==0){
			//return s1.getAge()-s2.getAge();
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));//形成整型的包装类调用compareTo比较也行
		}
		return num;
	}
}</span></span>

PS:要想在TreeSet中使元素按照输入的顺序输出只需将比较器构造为return -1;同理,如果是倒叙输出,则return 1。
六,泛型
1,泛型的优点
     JDK1.5版本之后出现的新特性,用于解决安全问题,是一个安全机制。当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在定义泛型来完成扩展当使用泛型时,可以使类型转换异常等错误出现在编译时,而不是像以前用Object实现时异常出现在运行时。
     好处:
           首先,将运行时期出现的问题ClassCastException(转换异常),转移到了编译时期方便于程序员解决问题,让运行时期问题减少,更安全。
           其次,避免了强制转换的麻烦。
2,泛型的定义
    泛型格式:通过<>来定义要操作的引用数据类型,在使用java提供的对象时,什么时候写泛型呢?
          通常在集合框架下很常见,只要见到<>就要定义泛型, 其实<>就是用来接收类型的,当使用泛型时,将集合中想要存取的数据类型作为参数传递到<>中就行。
    泛型类定义泛型:在整个类中有效,如果被方法使用,那么泛型类型的对象明确要操作的具体数据类型后,所有要操作的类型都已经固定了。
    泛型方法:为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。

PS:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。同时,定义泛型时,左边和右边的数据类型必须相同。
3,泛型中的通配符
    “?” 通配符,也可以理解为占位符
     泛型的限定:
         ? extends E:可以接收E类型或者E的子类型,上限
         ? super E:可以接收E类型或者E的父类型,下限  
下面代码是使用泛型的一个简单示例:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
import java.lang.String;
public class Example {
	public static void main(String args[])
	{
		TreeSet<String> ts=new TreeSet<String>(new LenComparator());//定义一个String类型的容器
       //arr.add(4444);-->arr.add(new Integer(444));会导致编译失败
		ts.add("1");
		ts.add("10");
		ts.add("45");
		ts.add("2");
		ts.add("a");
		
		Iterator<String> it=ts.iterator();
		while(it.hasNext())
		{
			String s=it.next();
			System.out.println(s);
		}
	}
}
class LenComparator implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if(num==0)
			return s1.compareTo(s2);
		return num;
	}
}</span></span>

泛型类中可以定义泛型方法,静态方法的泛型定义等,如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public class Example2 {
	public static void main(String args[])
	{
		Demo<String> d=new Demo<String>();
		d.print("dha");
		d.print(4);//类型定义在方法上,输入什么类型的数据就输出什么类型的数据
		d.show("4");//传入的参数类型必须与泛型确定的类型一致
		Demo.method(4);
		Demo.method("aaa");
	}
}
class Demo<T>//可以泛型类的同时也泛型方法
{
	public void show(T p)
	{
		System.out.println("show: "+p);
	}
	
	public <T> void print(T p)//泛型方法
	{
		System.out.println("print: "+p);
	}
	public static <T> void method(T t) //T在建立对象时明确,而static存在的时候还没有加载对象,先加载静态的,再加载动态的
	{
    	System.out.println("method: "+t);
	}
}</span></span>

继承泛型类或者接口时,可以选择定义泛型子类,也可以定义指定数据类型的子类,如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public class Example3
{
	public static void main(String args[])
	{
		InterDemo<Integer> id=new InterDemo<Integer>();
		id.show(new Integer(4));
		
		InterDemo2 id2=new InterDemo2();
		id2.show("yes");
	}
}
interface Inter<T>
{
	void show(T t);
}
class InterDemo<T> implements Inter<T>
{
	public void show(T t)
	{
		System.out.println(t);
	}
}
class InterDemo2 implements Inter<String>
{
	public void show(String t)
	{
		System.out.println(t);
	}
}</span></span>

泛型的通配符以及泛型限定上限和下限的使用方式如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class Example4 {
	public static void main(String args[])
	{
		ArrayList<String> arr=new ArrayList<String>();
		arr.add("a1");
		arr.add("a2");
		arr.add("a1");
		arr.add("a2");
		System.out.println("arr---print    ");
		print(arr);
		ArrayList<Integer> arr1=new ArrayList<Integer>();
		arr1.add(1);
		arr1.add(2);
		arr1.add(1);
		arr1.add(2);
		System.out.println("arr1---print    ");
		print(arr1);
		ArrayList<Person> arr2=new ArrayList<Person>();
		arr2.add(new Person("a1"));
		arr2.add(new Person("a2"));
		arr2.add(new Person("a1"));
		arr2.add(new Person("a2"));
		System.out.println("arr2---printPer    ");
		printPer(arr2);
		System.out.println("arr2---show    ");
		show(arr2);
		
		//ArrayList<Student> arr3=new ArrayList<Person>();这样是错误的,左边是什么右边就是什么
		ArrayList<Student> arr3=new ArrayList<Student>();
		arr3.add(new Student("a1"));
		arr3.add(new Student("a2"));
		arr3.add(new Student("a1"));
		arr3.add(new Student("a2"));
		System.out.println("arr3---printPer    ");
		printPer(arr3);
		System.out.println("arr3---show    ");
		show(arr3);
	}
	
	public static void print(ArrayList<?> arr)//不明确类型,没法调用?好的方法
	{
		Iterator<?> it=arr.iterator();
		System.out.print("{");
		while(it.hasNext())
		{
			System.out.print(it.next()+",");
		}
		System.out.println("}");
	}
	public static void printPer(ArrayList<? super Student> arr)//能打印的是Student或者Student的父类,泛型限定下限
	{
		Iterator<? super Student> it=arr.iterator();
		System.out.print("{");
		while(it.hasNext())
		{
			Person stu=(Person)it.next();
			System.out.print(stu.getName()+",");
		}
	    System.out.println("}");
	}
	public static void show(ArrayList<? extends Person> arr)//能打印的是Person或者Person的子类,泛型限定上限
	{
		Iterator<? extends Person> it=arr.iterator();
		
		System.out.print("{");
		while(it.hasNext())
		{
			Person stu=it.next();
			System.out.print(stu.getName()+",");
		}
		System.out.println("}");
	}
}
class Person
{
	private String name;
	Person(String name)
	{
		this.name=name;
	}
	public String getName()
	{
		return this.name;
	}
}
class Student extends Person
{
	Student(String name) {
		super(name);
	}
	
}</span></span>

TreeSet构造函数接收一个比较器时有两种情况:1,TreeSet(Collection<? extends E> c);2,TreeSet(Collection<? super E> c)。因此在定义构造函数时,构造一个父类的比较器,子类使用比较器时,就不用分别定义各自的比较器了,例如
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class Example5 {
	public static void main(String args[])
	{
		//TreeSet<Dog> ts=new TreeSet<Dog>(new DogComp());
		TreeSet<Dog> ts=new TreeSet<Dog>(new Comp());
		ts.add(new Dog("wangwang1"));
		ts.add(new Dog("wangwang2"));
		ts.add(new Dog("wangwang3"));
		ts.add(new Dog("wangwang4"));
		
		Iterator<Dog> it=ts.iterator();
		while(it.hasNext())
		{
			System.out.println(it.next().getName());
		}
		
		//TreeSet<Cat> ts1=new TreeSet<Cat>(new CatComp());分别new一个自己的比较器,很麻烦
		TreeSet<Cat> ts1=new TreeSet<Cat>(new Comp());//用泛型传参数时传父类,这样子类也可以用该比较器,不过下面发方法只能用父类中有的方法
		ts1.add(new Cat("miao1"));
		ts1.add(new Cat("miao2"));
		ts1.add(new Cat("miao3"));
		ts1.add(new Cat("miao4"));
		
		Iterator<Cat> it1=ts1.iterator();
		while(it1.hasNext())
		{
			System.out.println(it1.next().getName());
		}
		
	}
}
class Animal
{
	private String name;
	Animal(String name)
	{
		this.name=name;
	}
	public String getName()
	{
		return this.name;
	}
}
class Dog extends Animal
{
	Dog(String name)
	{
		super(name);
	}
}
class Cat extends Animal
{
	Cat(String name)
	{
		super(name);
	}
}
/*class DogComp implements Comparator<Dog>//如果传子类的数据类型进来,需要为不同子类构造比较器,这样很麻烦,就像要给猫和狗分别创建比较器一样
{
	public int compare(Dog d1,Dog d2)
	{
		return d1.getName().compareTo(d2.getName());
	}
}
class CatComp implements Comparator<Cat>//猫数据类型的比较器
{
	public int compare(Cat d1,Cat d2)
	{
		return d1.getName().compareTo(d2.getName());
	}
}*/
//泛型限定是进行泛型扩展用的,有扩展性就有局限性
class Comp implements Comparator<Animal>//创建父类的比较器,动物类的比较器,避免多次构造比较器的麻烦
{
	public int compare(Animal d1,Animal d2)
	{
		return d1.getName().compareTo(d2.getName());
</span></span><pre name="code" class="java"><span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">        }</span></span>
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">}</span></span>
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值