TreeSet泛型.docx
《TreeSet泛型.docx》由会员分享,可在线阅读,更多相关《TreeSet泛型.docx(12页珍藏版)》请在冰豆网上搜索。
![TreeSet泛型.docx](https://file1.bdocx.com/fileroot1/2022-12/15/5590999f-add5-41d8-884e-029ae1962ca4/5590999f-add5-41d8-884e-029ae1962ca41.gif)
TreeSet泛型
Set:
无序,不可以重复元素。
|--HashSet:
数据结构是哈希表。
线程是非同步的。
保证元素唯一性的原理:
判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。
|--TreeSet:
可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return0.
TreeSet排序的第一种方式:
让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
因为此,在定义一个类的时候,如果这个类要进行存储的话,一般要覆盖hashCode、equals方法,并实例Comparator接口。
因为存到数据结构为哈希表的集合里要覆盖hashCode、equals方法,而存到数据结构为二叉树的,则需要实现Comparable接口,而且实现了该接口,还可以用Collections和Arrays的sort方法进行排序。
最好也让这个类成为一个JavaBean,这让使用更方便。
注:
当一个Student类具有可比较性(实现了Comparable接口),把它存到了TreeSet集合中,但是,它的自然排序不是我们想要的排序方式,这时就可以给TreeSet指定一个比较器(Comparator),则排序方式按比较器中的规则进行。
泛型:
(几乎所有的集合类都定义了泛型)
<>是用来传递引用数据的类型,如String类型、Date类型,又如
ArrayList,这就说明我们给ArrayList传递了一个引用数据类型的参数,这个参数就是String,这告诉JDK说ArrayList里所装的引用元素的类型都是String类型的,如果你装的元素不是String类型,那么JDK在编译时就会给你报错。
在Jdk文档中的、,这里的T、E只是个变量名,而它们的值是什么呢?
就是引用的数据类型,如String、Date等,这些就可以是这些T、E变量的值。
T代表类型,E代表元素。
其实这个字母可以随便取,只是一个变量名字而已。
又如Map集合中的,K代表key,V代表value。
只是一个变量名而已
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。
现在定义泛型来完成扩展。
泛型类
classUtils
{
publicvoidprint(Tt)
{
System.out.println(t);
}
}
在类中定义的泛型,这样的类叫“泛型类”,在类中定义的泛型,可以在整个类中使用,如我们在newUtils()时,我们传递了一个String类型,那么在类中任何地方出现的T代表的都是String,如print方法中的T就是String,这时在调用print方法时就只能传String类型的参数,否则就会报错
泛型方法
classUtils
{
publicvoidprint(Tt)
{
System.out.println(t);
}
}
在方法中定义的泛型,这样的方法叫“泛型方法”。
在方法中定义的泛型,在这个方法中使用,如publicvoidprint(。
。
。
),那么在这个方法中的参数就只能是Date类型。
也就是说你在<>中传递的是什么类型,方法中接受的参数就是什么类型的。
注:
在方法里定义的泛型只在该方法有效,所以多个方法里的泛型的变量名可以相同,如:
publicvoidprint(Tt){}
publicTgetObj(){}
注意1:
classUtils
{
publicstaticvoidprint(Tt)
{
System.out.println(t);
}
}
这样编写语法不正确,因为在调用print方法时,Utils对象还没产生,也就说还没定义呢?
所以入静态方法中的泛型必定是定义在方法上的。
方法泛型只能加在返回类型的前面,如:
publicstaticvoidprint(Tt){}这是正确的
publicstaticvoidprint(Tt){}这是错误的
注意2:
classUtils
{
publicstaticvoidprint(Tt)
{
System.out.println(t);
}
}
classDemo
{
publicstaticvoidmain(Stringargs[])
{
Utilsutils=newUtils();
utils.print("abc");
}
}
在声明了泛型后,在使用时,如果没有传进泛型所需的值,那么变量的值是什么呢?
是Object,也就是说在上面Demo类中调用utils.print("abc");方法时,该方法的参数类型为Object,传进去的参数“abc”会被提升为Object。
接口中的泛型:
publicinterfaceGenericDemo3{
voidshow(Tt);
}
classDemo3ImplimplementsGenericDemo3{
@Override
publicvoidshow(Stringt){
System.out.println("abc");
}
publicstaticvoidmain(String[]args){
Demo3Impldemo=newDemo3Impl();
demo.show("abc");
}
}
上面的例子中Demo3Impl实现GenericDemo3,那么必须覆盖接口中的voidshow(Tt);方法,在classDemo3ImplimplementsGenericDemo3{}中传递的泛型类型是String,所以覆盖voidshow(Tt);方法中的T就是String,也就是必须覆盖publicvoidshow(Stringt)方法。
如果Demo3Impl在实现GenericDemo3接口时,也不知道会传给voidshow(Tt)方法中的参数是什么类型,那么Demo3Impl类也可以定义为泛型,如下:
classDemo3ImplimplementsGenericDemo3{
@Override
publicvoidshow(Tt){
System.out.println(t);
}
publicstaticvoidmain(String[]args){
Demo3Impldemo=newDemo3Impl();
demo.show(newDate());
}
}
泛型中的?
通配符
packagecom.itheima.generic;
importjava.util.ArrayList;
importjava.util.Iterator;
publicclassGenericDemo4{
publicstaticvoidmain(String[]args){
ArrayListal1=newArrayList();
ArrayListal2=newArrayList();
al1.add("ab");
al1.add("deab");
al1.add("eee");
al2.add(3);
al2.add(6);
al2.add(55);
printCollection(al1);
printCollection(al2);//会报错
}
publicstaticvoidprintCollection(ArrayListt){
Iteratorit=t.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
上面例子中定义的printCollection方法只能接受的参数是:
ArrayList类型,如果所以printCollection(al2);会报错,要想这个方法能接受的参数不较通用,则可以用?
通配符,修改后的代码如下:
publicstaticvoidprintCollection(ArrayList
>t){
Iterator
>it=t.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
这样printCollection(al2);就不会报错了。
其实这个通用的问题也可以用泛型方法来解决,代码如下:
publicstaticvoidprintCollection(ArrayListt){
Iteratorit=t.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
区别在于?
只是一个占位符,无法引用,而则可以引用,如:
publicstaticvoidprintCollection(ArrayListt){
Iteratorit=t.iterator();
while(it.hasNext()){
Telement=it.next();//这里引用了T
System.out.println(element);
}
}
泛型中的范围限定:
假设有Person类、和Student类、Teacher类,Student继承了Person,Teacher类也继承了Person类,
ArrayListlist=newArrayList;
这样的语句是错误的,先看=号左边:
声明了一个只能存放Student的ArrayList引用变量list
再看=号右边:
new了一个能存放Persion的实例对象
那么右边的实例对象可以add(Teacher),因为Teacher是Person的子类,但是=号左边的引用变量明确声明了只能在放Student,所以这就有矛盾了,所以这个语句也是错误的。
ArrayListlist=newArrayList;
这样的语句是错误的,先看=号左边:
声明了一个能存放Person的ArrayList引用变量list
再看=号右边:
new了一个只能存放Student的实例对象
那么右边的实例对象只可以add(Student),但是=号左边的引用变量明确声明了能在放Person,所以这就有矛盾了,因为Teacher是Person的子类,按=左边的声明,应该是可以存进去的,但是右边的实例对象却又只能add(Student),所以这个语句也是错误的。
上限
extendsPerson>:
这个限定是说:
可以传递的类型为Person或Person的子类。
Person下面的子类不固定,而父类Perso己固定,所以叫上限
下限
superPerson>:
这个限定是说:
可以传递的类型为Person或Person的父类。
Person上面的父类不固定,而子类Person己固定,所以叫下限
这个上限、下限一般用在集合中,如:
上限实例:
packagecom.itheima.generic;
importjava.util.ArrayList;
importjava.util.Iterator;
classGrandpa{
publicStringname;
publicStringgetName(){
name="爷爷";
returnname;
}
}
classFatherextendsGrandpa{
publicStringgetName(){
name="爸爸";
returnname;
}
}
classSonextendsFather{
publicStringgetName(){
name="儿子";
returnname;
}
}
publicclassGenericDemo5{
publicstaticvoidmain(String[]args){
ArrayListgrandpas=newArrayList();
ArrayListfathers=newArrayList();
ArrayListsons=newArrayList();
grandpas.add(newGrandpa());s
fathers.add(newFather());
sons.add(newSon());
//print1(grandpas);这个不符合要求
print1(fathers);
print1(sons);
}
publicstaticvoidprint1(ArrayList
extendsFather>al){//这个方法只能接受Father或Father的子类对象
Iterator
extendsFather>it=al.iterator();
while(it.hasNext()){
System.out.println(it.next().getName());
}
}
}
下限实例:
publicclassGenericDemo6{
publicstaticvoidmain(String[]args){
//TreeSet中的TreeSet(Comparator
superE>c)构造方法
TreeSetts=newTreeSet(newTestGeneric());
ts.add(newSon("abc"));
ts.add(newSon("ddd"));
ts.add(newSon("aaa"));
Iteratorit=ts.iterator();
while(it.hasNext()){
System.out.println(it.next().getName());
}
}
}
classTestGenericimplementsComparator{
@Override
publicintcompare(Fathero1,Fathero2){
returno1.getName().compareTo(o2.getName());
}
}
TreeSet中的TreeSet(Comparator
superE>c)构造方法,这里的E是在TreeSet的类中定义的,也就是说newTreeSet中指定的E是什么类型就是什么类型,比如这个E指定为Son对象类型,那么Comparator
superE>中的E就是Son类型,也就是说这个Comparator参数中的泛型参数可以是Son或Son的父类(Father)。
当Father有多个儿子时对象时,而每个对象都要进行存储到TreeSet集合中,并且需要传递一个比较器(Comparator),这时这个比较器就可以传Father的比较器,这样的比较器对每个儿子都可以用。
要不然的话每个儿子都得指定一个比较器就很麻类了!
实例如下:
packagecom.itheima.generic;
importjava.util.Comparator;
importjava.util.Iterator;
importjava.util.TreeSet;
publicclassGenericDemo7{
publicstaticvoidmain(Stringargs[]){
TreeSetts1=newTreeSet(newStu4Comp());
ts1.add(newStudent4("abc03"));
ts1.add(newStudent4("abc02"));
ts1.add(newStudent4("abc06"));
ts1.add(newStudent4("abc01"));
Iteratorit1=ts1.iterator();
while(it1.hasNext())
{
System.out.println(it1.next().getName());
}
TreeSetts2=newTreeSet(newStu6Comp());
ts2.add(newStudent6("wabc--03"));
ts2.add(newStudent6("wabc--02"));
ts2.add(newStudent6("wabc--06"));
ts2.add(newStudent6("wabc--01"));
Iteratorit2=ts2.iterator();
while(it2.hasNext())
{
System.out.println(it2.next().getName());
}
}
}
classStu4CompimplementsComparator
{
publicintcompare(Student4s1,Student4s2)
{
returns1.getName().compareTo(s2.getName());
}
}
classStu6CompimplementsComparator
{
publicintcompare(Student6s1,Student6s2)
{
returns1.getName().compareTo(s2.getName());
}
}
classPerson
{
privateStringname;
Person(Stringname)
{
this.name=name;
}
publicStringgetName()
{
returnname;
}
publicStringtoString()
{
return"person:
"+name;
}
}
classStudent4extendsPerson
{
Student4(Stringname)
{
super(name);
}
}
classStudent6extendsPerson
{
Student6(Stringname)
{
super(name);
}
}
这里有一个Person类,它有两个儿子Student4、Student6,Student4和Student6都要保存到TreeSet集合中,因为分别为Student4、Student6各创建了一个比较器,如果说Person有很多的儿子都要进行添加到TreeSet集合中的话,那么得为每个儿子都创建一个比较器,那样比较麻类。
在TreeSet的构造函数中的这么一个构造函数:
TreeSet(Comparator
superE> c),所以我们可以创建一个父类的比较器,这样的比较器对每个儿子都通用,如下:
classPersonCompimplementsComparator{
publicintcompare(Persons1,Persons2)
{
returns1.getName().compareTo(s2.getName());
}
}
这个比较器对每个儿子都通用,需要注意的是,Person只能调用Person有的方法。