【TreeSet】的应用及【泛型】高级应用总结

一、【基本定义和特点】

TreeSet::这个集合就是为了实现该集合中元素是自然数排序,具有无序性,和不可重复性的特点!

我们来验证一下:

<span style="font-size:18px;"><span style="font-size:18px;">import java.util.*;
class TreeSetDemo1 
{
	public static void main(String[] args) 
	{
		TreeSet ts=new TreeSet();
		ts.add("abcd");
		ts.add("bcd");
		ts.add("accd");
		ts.add("bdd");
		ts.add("bdd");
		ts.add("Acd");
		
		//迭代取出
		Iterator i=ts.iterator();
		while (i.hasNext())
		{
			sop(i.next());
		}
		/*执行的结果:
		Acd
		abcd
		accd
		bcd
		bdd
		可以看出存入的顺序和取出的顺序是无序性,ts.add("bdd")添加了两次,取出只有一个,
		即是无重复性的反应,OK
		*/
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}</span></span>
因为TreeSet集合是为了实现该集合中元素是自然数排序
这时候应该想到在String类中也有个int compareTo(String str)的方法,
此方法是为了让两个字符串进行自然数排序,返回int类型:负数,正数,和0

二、【TreeSet集合中添加自定义的类】

不用问,肯定知道,都是实现了一个comparable的接口去调用自身的int compareTo(Object obj)

为什么会这样呢?
我们用练习说明:
自定一个学生类,把该学生类添加到TreeSet集合中后,通过年龄去排序出来定义基本的简单类吧:学生类中只有基本的name和age属性为例,最终通过年龄的自然数去排序出来

<span style="font-size:18px;"><span style="font-size:18px;">/*
其实:TreeSet的底层数据结构是二叉树
comparareTo()方法,返回值是0,是说明元素是相同的……直接删除,不再存入其中
【重点】当排序是,主要条件相同时,一定判断一下次要条件
*/</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">import java.util.*;
//学生类
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)
	{
		//第一步,按照年龄去排序
		//第二步,如果年龄相同的情况,再具体判断学生类中的姓名属性去排序,
		//这时候就交给原来String类中compareTo的方法去自动排序即可
		
		//所以:
		//判断添加的类是不是都是学生类,不是就用抛出异常的方式提醒!
		if (!(obj instanceof Student))
			throw new RuntimeException("添加的不是学生类对象");

		//把添加的对象缩小到Student的具体实例话类上进行年龄的判断
		Student stu=(Student)obj;

		//按照具体需求去进行
		if (this.age>stu.age)
			return 1;
		
		if (this.age==stu.age)
		{
				return this.name.compareTo(stu.name);
		}
			

		return -1;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}
}

class  TreeSetAddObject2
{
	public static void main(String[] args) 
	{
		TreeSet ts=new TreeSet();
		//把学生实例化对象加入其中
		ts.add(new Student("wangming",28));

		ts.add(new Student("wangming",20));
		ts.add(new Student("wangming",20));
	
		ts.add(new Student("zhijie",26));
		ts.add(new Student("zhiainan",26));

		ts.add(new Student("yanghua",23));
		ts.add(new Student("wankez",30));
		
		Iterator i=ts.iterator();
		//迭代的方式取出去遍历就OK
		while (i.hasNext())
		{
			Student stu=(Student)i.next();
			//打印在Student对象在TreeSet集合内部的排序情况
			sop(stu.getName()+","+stu.getAge());
		}
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}</span></span>
最终的总结:
【默认排序】第一种方式:让元素自身具备比较性;元素需要实现Comparable接口,覆盖compareTo()方法,这种方式的排序也可以说是自然排序,或者是默认排序!
当加入自定的类在TreeSet中,要根据具体的需求去重写实现Comparable接口的方法
compareTo的方法,依次让TreeSet集合的内部去按照需求内容就行排序就行!


三、【比较器的定义】

<span style="font-size:18px;"><span style="font-size:18px;">/*
TreeSet的第二种排序方式:
当元素自身不具备比较性时,或者具备的比较性不是所需要的,
那样,就需要让集合自身具备比较性
这样的话,就在集合才在初始化时就具备比较性!

在api文档中查到想让集合自身具有比较性,那样就让要定义一个
【比较器】,将比较器对象作为参数传递给TreeSet集合的构造函数中
*/
import java.util.*;
//学生类
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)
	{
		//第一步,按照年龄去排序
		//第二步,如果年龄相同的情况,再具体判断学生类中的姓名属性去排序,
		//这时候就交给原来String类中compareTo的方法去自动排序即可
		
		//所以:
		//判断添加的类是不是都是学生类,不是就用抛出异常的方式提醒!
		if (!(obj instanceof Student))
			throw new RuntimeException("添加的不是学生类对象");

		//把添加的对象缩小到Student的具体实例话类上进行年龄的判断
		Student stu=(Student)obj;

		//按照具体需求去进行
		if (this.age>stu.age)
			return 1;
		
		if (this.age==stu.age)
		{
				return this.name.compareTo(stu.name);
		}
			

		return -1;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}
}
class  TreeSetAddObjectSecond3
{
	public static void main(String[] args) 
	{
		TreeSet ts=new TreeSet(new Mycomparator());
		//把学生实例化对象加入其中
		ts.add(new Student("wangming",28));

		ts.add(new Student("wangming",28));
		ts.add(new Student("wangming",20));
	
		ts.add(new Student("zhijie",26));
		ts.add(new Student("zhiainan",26));

		ts.add(new Student("yanghua",23));
		ts.add(new Student("wankez",30));
		
		Iterator i=ts.iterator();
		//迭代的方式取出去遍历就OK
		while (i.hasNext())
		{
			Student stu=(Student)i.next();
			//打印在Student对象在TreeSet集合内部的排序情况
			sop(stu.getName()+","+stu.getAge());
		}
	}
	 
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

//自定义比较器

class Mycomparator implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		Student s1=(Student)o1;
		Student s2=(Student)o2;
		
		if (!((s1 instanceof Student) && (s2 instanceof Student)))
			throw new RuntimeException("注意:要比较的对象不是学生类对象");

		//这时候,如果对象中两个同学的名字是一样的,那样就需要进一步判断年龄了
		//所以,这时候就需要对年龄进一步做出判断才行!
		/*
		if (kid==0)
		{
			//对年龄进行判断:
			if (s1.getAge() > s2.getAge())
			{
				return 1;
			}

			if (s1.getAge() == s2.getAge())
			{
				return 0;
			}

			return -1;
		}
		return kid;*/
		//做完这根kid的判断之后,发现实际上有另外一种方法,那就是用基本数据类型类去判断更便捷
		
		int kid=s1.getName().compareTo(s2.getName());
		if (kid == 0)
		{
			return new Integer(s1.getAge()).compareTo(s2.getAge());
		}
		return kid;
	}
}</span></span>
四、【泛型的应用】

<span style="font-size:18px;"><span style="font-size:18px;">/*
下面用泛型的思想来做按照字符串长度的排序
【泛型】定义:在JDK1.5之后:为了提高安全性,所以在定义集合的时候,就必须指定存入集合
中元素的类型
【格式】将要接受的类型写在“<>”中
【好处】
1.避免在运行的时候才出现ClassCastException(类型不能转换异常),提前在编译时就能进行提示
2.避免强制转换的问题出现,让程序看起来简单明了
*/

import java.util.*;
class GenericityDemo5
{
	public static void main(String[] args) 
	{
		//在定义集合时就要指定类型,类型写在“<>”中,这里我接受的是字符串类型
		TreeSet<String> ts=new TreeSet<String>(new MyGenerComparator());

		ts.add("sjfklasjfs");
		ts.add("afadfa");
		ts.add("fasfaewfa");
		ts.add("asfadsfassfds");
		ts.add("asfadsfas");
		
		//在定义迭代器时,也必须标注才行,这样免得在
		//while中还要强制转换类型,简化了代码
		Iterator<String> i=ts.iterator();

		while (i.hasNext())
		{
			//Stirng s=(String)i.next();因为有泛型,就不用这句话,不需要强制转换了
			sop(i.next());
		}
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

//一样的原理,在定义比较器时,实现的接口Comparator也要指定接受类型
class MyGenerComparator implements Comparator<String>
{
	//所以当覆盖方法的时候,就直接用接受到的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:18px;"><span style="font-size:18px;">/*
当不知道需要引用的数据类型是什么时,就需要自定义一个工具类来完成一个万能的自动转换
下面以学生和工人类为例:当不知道是接受谁时,这是就可以用泛型的思想来完成
*/

//定义工人类
class Worker
{
}
//定义学生类
class Student
{
}
//定义一个自己的工具,实现接受后,智能转换的过程
//SuperUtil是自己定义的需要接受的引用对象而已
class MyUtil<SuperUtil>
{
	private SuperUtil su;
	//set,get方法很简单,不再介绍了
	public void setObject(SuperUtil su)
	{
		this.su=su;
	}

	public SuperUtil getObject()
	{
		return su;
	}
}

class MyGenericity6 
{
	public static void main(String[] args) 
	{
		//这时指定传入的是如果是Student的类,那么他会自动进行转换,很方便
		//即便是出错了,也会在编译时报出错误!

		MyUtil<Student> my=new MyUtil<Student>();
		my.setObject(new Student());
		//所以以下就不用进行手动强转了
		Student s=my.getObject();
	}
}

//下面是看一下,没有泛型之前的做法:
//用的都是Object的基础类接受的引用对象,接受之后,需要自己做对应的强转才能正常使用!
//定义工人类
/*
class Worker
{
}
//定义学生类
class Student
{
}

class MyUtil
{
	private Object obj;
	//set,get方法很简单
	public void setObject(Object obj)
	{
		this.obj=obj;
	}

	public Object getObject()
	{
		return obj;
	}
}

class MyGenericity 
{
	public static void main(String[] args) 
	{
		
		MyUtil my=new MyUtil();
		my.setObject(new Student());
		//需要进行手动强转了,否则报错
		Student s=(Student)my.getObject();
	}
}
*/</span></span>

五、【泛型可以应用到类上或者方法上】

<span style="font-size:18px;"><span style="font-size:18px;">/*
【泛型应用在方法中的情况】
在开发的过程中,还有一种情况,那就是当一个类被确定是,但是其方法中的引用对象是不确定的,
这时候也可以用到泛型来定义,在同一个方法中操作不同的引用对象
*/
//实例:

class Demo
{
	//定义一个在展示方法中去输出引用对象的简单方法
	public <T> void showMethod(T t)
	{
		System.out.println(t);
	}
	//定义一个在打印方法中去输出引用对象的简单方法
	public <Z> void printMethod(Z z)
	{
		System.out.println(z);
	}
}

class MethodGenericity7
{
	public static void main(String[] args) 
	{
		//在类中不再指定要传入的引用对象
		Demo d=new Demo();
		d.showMethod("wangwang");
		d.showMethod(new Double(89.767));
		d.printMethod("nihaoma!");
		d.printMethod(new Integer(99));

		/*
		输出结果:
		wangwang
		89.767
		nihaoma!
		99
		//这种就是应用同一个方法也能输出不同引用对象的实例
		*/
	}
}</span></span>

请看实例:

<span style="font-size:18px;"><span style="font-size:18px;">/*
之前是把泛型应用到类上或者方法上的例子,同样,泛型能够同时应用到类上和方法上
但是需要注意的是:static的方法应用泛型格式上有点不一样!
下面以例子具体说明:
*/

class Demo<T>
{
	//方法show定义的泛型和类上定义的是同一个引用对象,所以在void前面不用再写<T>了
	public void show(T t)
	{
		System.out.println(t);
	}

	//这是定义了和类不一样的泛型
	public <Z> void print(Z z)
	{
		System.out.println(z);
	}

	//同理:static方法是永远都不能定义和类一样的泛型引用对象的,即是不能访问类上的泛型对象
	//当静态方法上访问的对象也不能确定时,定义在static方法就行!
	public static <X> void staticShow(X x)
	{
		System.out.println(x);
	}
}
class MethodGenerTest8 
{
	public static void main(String[] args) 
	{
		Demo<String> d=new Demo<String>();
		d.show("the same with Demo class");
		//d.show(new Integer(99));//报错,因为该方法的泛型和类一样,是String类型

		//虽然类中指定了相应的Stirng类型,但是print方法却是可以和类一样,也可以不一样的
		d.print("the same with Demo class"); //可以跟类泛型一样
		d.print(new Integer(99)); //可以和类泛型不一样

		//静态方法的泛型实例
		d.staticShow("static method");
		d.staticShow(new Integer(99)); 
	}
}
/*【总结:】
1.泛型可以定义在类上,方法上(静态的方法不能访问类定义的泛型)
2.多个方法中(除static方法外)的泛型可以和类泛型一样,也可以不一样!
*/</span></span>
六、【泛型应用到接口上的具体分析】

<span style="font-size:18px;"><span style="font-size:18px;">/*
那么泛型可以定义在接口上面吗?
看实例分析:
*/

//定义一个接口,接口中有一个抽象的方法
interface Inter<T>
{
	void show(T t);
}
//实现该接口的类
class InterImpl<T> implements Inter<T>
{
	//覆盖接口中的方法,应该保持泛型和接口一样
	public void show(T t)
	{
		System.out.println(t);
	}
	
	//再定义一个和接口中的泛型不一样的方法
	public <Z> void print(Z z)
	{
		System.out.println(z);
	}
}

class  InterfaceGeneriDemo9
{
	public static void main(String[] args) 
	{
		//指定该接口的实现类泛型是String类型
		InterImpl<String> i=new InterImpl<String>();

		i.show("wangwang");
		//i.show(new Integer(99));//这样就是错误的,因为show方法定义的是和接口一样的类型
		i.print(new Integer(99));
	}
}
//【总结】泛型是可以用在接口上的</span></span>

七、【泛型的限定】

/*泛型的限定!
【限定的种类】
1.?这是一个通配符号,可以理解是占位符
2.? extends E(上限定):可以接受E类型,或者是E的子类型
3.? super E(下限定):可以接受E类型,或者E的父类型
*/
import java.util.*;

//以下第一个程序是自定义一个泛型的方法去迭代取出元素
/*class GeneriXianding10
{
	public static void main(String[] args) 
	{
		ArrayList<String> ss=new ArrayList<String>();
		ss.add("wangalkjg");
		ss.add("wasdf");
		ss.add("wandf");
		ss.add("wang");

		ArrayList<Integer> si=new ArrayList<Integer>();
		si.add(new Integer(89));
		si.add(new Integer(9));
		si.add(new Integer(5));
		si.add(new Integer(2));

		showCollection(ss);
		showCollection(si);


	}
	
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

	//因为都有通过迭代取出的方法,所以定义一个迭代方法的泛型实例就可以取出元素
	public static void showCollection(ArrayList<?> al)
	{
		Iterator<?> i=al.iterator();
		while (i.hasNext())
		{
			sop(i.next());
		}
	}
}*/

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 GeneriXianding10
{
	public static void main(String[] args) 
	{
		ArrayList<Person> al=new ArrayList<Person>();
		al.add(new Person("wangke"));
		al.add(new Person("wan"));
		al.add(new Person("wgke"));
		//showCollection(al);

		ArrayList<Student> als=new ArrayList<Student>();
		als.add(new Student("wangke----1"));
		als.add(new Student("wan----2"));
		als.add(new Student("wgke----3"));
		
		showCollection(als);
		//这句话相当于:ArrayList<Person> al=new ArrayList<Student>();
		//左边是人的总类,而在右边只是人的一个子类(一个实例而已),所以两边类型不匹配
		//必然报错
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

	//Person写为?也可以实现(所有类型的打印),但是我们需要只是打印Person或者Person的子类
	//这时候就需要用到 
	//? extends Person(上限定) 或者 ? super Student(下限定) 
	//只需要把showCollection方法中的Person改为? extends Person就行
	
	public static void showCollection(ArrayList<? extends Person> a)
	{
		Iterator<? extends Person> i=a.iterator();
		while (i.hasNext())
		{
			sop(i.next().getName());
		}
	}

}

八、【泛型高级应用总结】

/*
写一个比较器的泛型实例,最后还是用通用的迭代方法显示出来:
*/
import java.util.*;
//定义了一个父类,人类
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 Worker extends Person
{
	Worker(String name)
	{
		super(name);
	}
}

class BiJiaoQi11
{
	public static void main(String[] args) 
	{
		//把学生类添加到TreeSet集合中
		TreeSet<Student> tss=new TreeSet<Student>(new MyComp());
		tss.add(new Student("abc--1"));
		tss.add(new Student("abc--2"));
		tss.add(new Student("abc--3"));
		tss.add(new Student("abc--4"));

		//把工人类添加到TreeSet集合中
		TreeSet<Worker> tsw=new TreeSet<Worker>(new MyComp());
		tsw.add(new Worker("abc--001"));
		tsw.add(new Worker("abc--002"));
		tsw.add(new Worker("abc--003"));
		tsw.add(new Worker("abc--004"));
		
		//调用通用的迭代方式显示不同的类
		showIter(tss);
		showIter(tsw);
	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	
	//定义了一个通用的迭代取出函数
	//取出的对象是Person的所有子类型
	public static void showIter(TreeSet<? extends Person> ts)
	{
		Iterator<? extends Person> it=ts.iterator();
		while (it.hasNext())
		{
			sop(it.next().getName());
		}
	}
}
/*这里很重要:
如果Person改写成Student的话,只能比较Student类
如果Person改写成Worder的话,只能比较Worder类
但是传入的是父类,就意味着可以比较父类的所有子类了
【温馨提示】传入的是子类,那就只比较相应的子类,传入的是父类,那就可以比较父类其下的所有子类
这就是其 ? super E (下限的具体体现)
*/

class MyComp implements Comparator<Person>
{
	public int compare(Person p1,Person p2)
	{
		return p2.getName().compareTo(p1.getName());
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值