黑马程序员_Java基础_集合框架(二)_15

时间:2021-10-13 11:38:58
                                             ------- android培训java培训、期待与您交流!----------
 

导读:TreeSetTreeSet自定义对象,Comparator方式排序,泛型概述,泛型使用,泛型类,泛型方法,静态方法类型,泛型接口,泛型限定


1TreeSetTreeSet存储自定义对象

l  Set:无序,不可以重复元素。

       |--HashSet:数据结构是哈希表。线程是非同步的。

                            保证元素唯一性的原理:判断元素的hashCode值是否相同。

                            如果相同,还会继续判断元素的equals方法,是否为true

|--TreeSet:可以对Set集合中的元素进行自然顺序的排序。(弥补HashSet无序的不足)。底层数据结构是二叉树。保证元素唯一性的依据:compareTo方法return 0(对于于TreeSet集合它不管你是怎么比的,它只看你的结果是正的负的,还是零。和哈希值没有关系)。如果想让TreeSet集合判断或者删除元素,是否包含走的都是CompareTo方法。

[二叉树默认是按从小到大取(从最左子树开始,由小往大查找)。二叉树中元素多的话,可取一个折中值从中间开始比,以提高效率。]

TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也成为元素的自然顺序,或者叫做默认顺序(元素一定义完,它就已经有了比较性了)。

                            TreeSet的第二种排序方式:

当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。在集合初始化时,就有了比较方式。

l  需求:

TreeSet集合中存储自定义对象学生。想按照学生的年龄进行排序。

记住,排序时,当主要条件相同时,一定判断一下次要条件。

Ø  public interface Comparable<T>:此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。这个接口中只有一个方法,叫做int compareTo(T o)比较此对象(this)与指定对象(o)的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

Ø  TreeSet集合可以排序,可是你给它说过吗?没说过,你说按年龄排它不知道啊,因为学生对象根本不具有比较性。TreeSet说,你必须让你的元素具有比较性,我才能给我你排序。怎样才能有比较性呢?TreeSet说,这个接口,你只要实现了它,你就具有了比较性。

l  import java.util.*;

class TreeSetDemo

{

       publicstatic void main(String[] args)

       {

              TreeSetts = new TreeSet();

              ts.add(newStudent("lisi02",22));

              ts.add(newStudent("lisi007",20));

              ts.add(newStudent("lisi09",19));

              ts.add(newStudent("lisi08",19));   //当主要条件相同的时候,要按次要条件排序,次要条件要相同的话,就相同了。

              //ts.add(newStudent("lisi007",20));

              //ts.add(newStudent("lisi01",40));

              Iteratorit = ts.iterator();

              while(it.hasNext())

              {

                     Studentstu = (Student)it.next();

                     System.out.println(stu.getName()+"..."+stu.getAge());

              }

       }

}

class Student implements Comparable//该接口强制让学生具备比较性。

{

       privateString name;

       privateint age;

       Student(Stringname,int age)

       {

              this.name= name;

              this.age= age;

       }

       publicint compareTo(Object obj) //要进行自我的调用

       {

              //return0;

              if(!(objinstanceof Student))

                     thrownew RuntimeException("不是学生对象");

              Students = (Student)obj;

              System.out.println(this.name+"....compareto....."+s.name);

              if(this.age>s.age)

                     return1;  //大于的话,要返回正数,这里的1的位置可以为任意正数,如10000

              if(this.age==s.age)

              {

                     returnthis.name.compareTo(s.name); //java中很多对象自身就具有比较性。如String已经实现了Comparable接口。有方法compareTo(),返加值也是负数正数和零。

              }

              return-1;

       }

       publicString getName()

       {

              returnname;

       }

       publicint getAge()

       {

              returnage;

       }

}

 

2、集合框架(实现Comparator方式排序)

l  当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

l  TreeSet(Comparator<? super E>comparator)

          构造一个新的空TreeSet,它根据指定比较器进行排序。

l  Comparator的两个方法

Ø  int compare(T o1, T o2):比较用来排序的两个参数。

参数:

o1 - 要比较的第一个对象。

o2 - 要比较的第二个对象。

返回:

根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。

Ø  boolean equals(Object obj):指示某个其他对象是否“等于”此 Comparator

当两种排序都存在时,以比较器为主。

l  定义一个类,实现Comparator接口,覆盖compare方法。(注意不是compareTo()方法,Compareble中的是compareTo()方法)二叉树都是以判断return是否为0判断是否相等。

l  在开发中用Comparetor的多一些,因为它是一个接口。玩项目没有接口的话,项目是死的毫无扩展性可言,日后但凡升级就要了命了。如果没有留接口的话,项目在短期内可以用,如果人家公司提高其业务需求了,你怎么办?没有这些接口,把以前的项目要重新的去改。这时候,不想改的话,跳槽。

l  import java.util.*;

class Student implements Comparable//该接口强制让学生具备比较性。

{

       privateString name;

       privateint age;

       Student(Stringname,int age)

       {

              this.name= name;

              this.age= age;

       }

       publicint compareTo(Object obj)

       {

              //return0;

              if(!(objinstanceof Student))

                     thrownew RuntimeException("不是学生对象");

              Students = (Student)obj;

              //System.out.println(this.name+"....compareto....."+s.name);

              if(this.age>s.age)

                     return1;

              if(this.age==s.age)

              {

                     returnthis.name.compareTo(s.name);

              }

              return-1;

       }

       publicString getName()

       {

              returnname;

       }

       publicint getAge()

       {

              returnage;

       }

}

class TreeSetDemo2

{

       publicstatic void main(String[] args)

       {

              TreeSetts = new TreeSet(new MyCompare()); //学生里面已经有比较方式了,如果传入MyCompare的话,是按MyCompare()来排。

              ts.add(newStudent("lisi02",22));

              ts.add(newStudent("lisi02",21));

              ts.add(newStudent("lisi007",20));

              ts.add(newStudent("lisi09",19));

              ts.add(newStudent("lisi06",18));

              ts.add(newStudent("lisi06",18));

              ts.add(newStudent("lisi007",29));

              Iteratorit = ts.iterator();

              while(it.hasNext())

              {

                     Studentstu = (Student)it.next();

                     System.out.println(stu.getName()+"..."+stu.getAge());

              }

       }

}

class MyCompare implements Comparator

{

       publicint compare(Object o1,Object o2)

       {

              Students1 = (Student)o1;

              Student s2 = (Student)o2;

              intnum = s1.getName().compareTo(s2.getName()); //num先记住比较后的值。

              if(num==0)

              {

                     returnnew Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));

//new一个整型的对于象,利用对象里面的compareTo来比较。

                     /*

                     if(s1.getAge()>s2.getAge()) //麻烦一点的多条语句的方式。

                            return1;

                     if(s1.getAge()==s2.getAge())

                            return0;

                     return-1;

                     */

              }

              returnnum;

       }

}

 

3、集合框架(泛型概述)

l  泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。

l  好处:

1,将运行时期出现问题ClassCastException,转移到了编译时期。,

       方便于程序员解决问题。让运行时问题减少,安全。,

2,避免了强制转换麻烦。

l  泛型格式:通过<>来定义要操作的引用数据类型。

为什么要用<>呢?因为{}已经被程序结构使用了,()被参数用了,[]被数组给我用了,就剩<>了。

l  在使用java提供的对象时,什么时候写泛型呢?

通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的。当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。如,ArrayList<E>,也就是说,你在使用ArrayList<E>这个类的时候你要明确一下,要通过集合,操作什么类型的元素。E代表元素(Element),T代表类型(Type)。

l  import java.util.*;

class GenericDemo

{

       publicstatic void main(String[] args)

       {

              ArrayList<String>al = new ArrayList<String>();

//这句话,表示我定义了一个ArrayList容器,容器中的类型是|String类型。在1.4之前没有泛型的时候,程序员是主观的判定这里面是什么元素。

              //为什么数组是安全的因为它在初始化的时候定义了类型,而对于集合我们初始化的时候没有明确过类型。这就是安全血隐患,如果我们能象数组一样,在定义集合的时候就能定义其中装的是什么元素类型的话,后期不是没有问题了。这就是泛型的由来。

              al.add("abc01");

              al.add("abc0991");

              al.add("abc014");

              //al.add(4);//al.add(newInteger(4)); //集合中只能添加对象是不能添加基本数据类型的。在1.5版本之后,可以添加基本数据类型。因为基本数据类型有一个自动装箱和拆箱动作。

              在这里,编译时不会有错误,而运行时会报ClassCastException。能不能程序员在编译的时候就能看到这个问题,这样程序员解决了,到运行的时候就没有问题了。程序分两部分,编译和运行,编译是由我们来做的事情,运行是由用户来做的事情。用户解决不了这个问题。JAVA1.5之后,对这个问题做了一个解决,它提供了一个新的技术,叫做泛型。这样,问题就可以由编译时期转移到了运行时期。编译失败程序员要解决。

              Iterator<String>it = al.iterator(); //将数据放到了迭代器中,所以也要用泛型

              while(it.hasNext())

              {

                     Strings = it.next(); //这里不用强转了。

                     System.out.println(s+":"+s.length());

              }

       }

}

 

4、集合框架(泛型使用)

l  import java.util.*;

class GenericDemo2

{

       publicstatic void main(String[] args)

       {

              TreeSet<String>ts = new TreeSet<String>(new LenComparator());

              ts.add("abcd");

              ts.add("cc");

              ts.add("cba");

              ts.add("aaa");

              ts.add("z");

              ts.add("hahaha");

              Iterator<String>it = ts.iterator();

              while(it.hasNext())

              {

                     Strings = it.next();

                     System.out.println(s);

              }

       }

}

class LenComparator implementsComparator<String> //Comparaor<T>传入参数类型。

{

       publicint compare(String o1,String o2)

       {

              intnum = new Integer(o2.length()).compareTo(new Integer(o1.length()));

              //想着倒着输出的话,把o2o1倒一下就可以了。

              if(num==0)

                     returno2.compareTo(o1); //这里也倒一下。

              returnnum;

       }

}

l  我们在写HashSet集合的时候,要覆盖两个方法,一个叫做hashCode(),一个叫做equals()。这个equals覆写是的是ObjectObject没有泛型。这个必须要做转换。转换的时候,还要判断是不是这种类型,不要瞎写。

l  我们要自定义一个对象要做什么事情呢?如,一个学生对象,里面有一个hashCode()equals(),还要让他实现一个Comparable接口(compareTo()方法),让学生拥有默认的比较性。至于用不用,写上它,这样即可以存到HashSet中,又可能存到TreeSet中。所以学生上些基本的特性都要先具备。

 

5、集合框架(泛型类)

l  迭代器,比较器,集合都涉及到泛型了。

l  我们能不能在自己定义的类中使用泛型的概念来完成,程序设计呢?

l  一个类对应一个工具类好麻烦,如果你只是为了设置对象,获取对象的话,我是不是可以提高程序的扩展性,抽取对象的共性类型。

class Tool

{

       privateWorker w;

       publicvoid setWorker(Worker w)

       {

              this.w= w;

       }

       publicWorker getWorker()

       {

              returnw;

       }

}

*/

class Worker

{

 

}

class Student

{

}

//泛型前做法。

class Tool  //以前设计的时候都用这样的类,实现程序的扩展,最明显的例子,就是equals

{

       privateObject obj;

       publicvoid setObject(Object obj)

       {

              this.obj= obj;

       }

       publicObject getObject()

       {

              returnobj;

       }

}

//泛型类。

/*

什么时候定义泛型类?

当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。现在定义泛型来完成扩展。(我要操作对象,操作哪个啊?不知道。什么类型不确定,定义一个参数,对方在调用你工具类的时候,由它来指定要操作什么类型的对象)

*/

class Utils<QQ>

{

       privateQQ q;

       publicvoid setObject(QQ q)

       {

              this.q= q;

       }

       publicQQ getObject()

       {

              returnq;

       }

}

class GenericDemo3

{

       publicstatic void main(String[] args)

       {

              Utils<Worker>u = new Utils<Worker>();

              u.setObject(newStudent()); //如果传入的是new Student()我直接让他将错误发生在编译时期。

              Workerw = u.getObject(); //还避免了强转

              /*

              Toolt = new Tool();

              t.setObject(newStudent());

              Workerw = (Worker)t.getObject();

              */

       }

}

 

6、集合框架(泛型方法、静态方法类型)

l  泛型不仅可以定义在类上,还可以定义在方法上。

l  泛型类的一个小的局限性,只要你的对象一确定,要操作的类型也就确定了。

l  根据需求确定是定义在类上,还是定义在方法上。如果类中产生的对象,类型一明确这些类型都跟着走的话,定义在类上最方便。集合就是这么回事ArrayList<E>。定义在方法上的话,你传什么类型他就操作什么类型。

/*

class Demo<T>

{

       publicvoid show(T t)

       {

              System.out.println("show:"+t);

       }

       publicvoid print(T t)

       {

              System.out.println("show:"+t);

       }

 

}

*/

//泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

//为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。

/*

特殊之处:

静态方法不可以访问类上定义的泛型。

如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

*/

class Demo<T> //即定义在类上,又定义在方法上,不重复。可以这样定义

{

       public  void show(T t) //这个show类型是跟着对象走的。

       {

              System.out.println("show:"+t);

       }

       public<Q> void print(Q q) //泛型定义在方法上,就这样定义。类型定义在方法上,你传入什么类型,它就操作什么类型。非常容易。这里的Q写成T也一样,没有影响

       {

              System.out.println("print:"+q);

       }

       public  static <W> void method(W t)  //如果用定义在类上的泛型T,在编译的时候,会出现无法从静态上下文中引用非静态类T这种提示,因为T只有在运行的时候才能被确立成是什么类型。要用定义在方法上的泛型这种形式。定义在方法上的泛型,要写在返回值的前面,修饰符的后面。而不能写在static修饰符的前面。

       {

              System.out.println("method:"+t);

       }

}

class GenericDemo4

{

       publicstatic void main(String[] args)

       {

              Demo<String> d = new Demo<String>();

              d.show("haha");

              d.print(5);

              d.print("hehe");

              Demo.method("hahahahha");

              /*

              Demod = new Demo();

              d.show("haha");

              d.show(newInteger(4));

              d.print("heihei");

              */

              /*

              Demo<Integer>d = new Demo<Integer>();

              d.show(newInteger(4));

              d.print("hah");

              Demo<String>d1 = new Demo<String>();

              d1.print("haha");

              d1.show(5);

              */

       }

}

 

7、集合框架(泛型接口)

//泛型定义在接口上。

interface Inter<T>

{

       voidshow(T t);

}

/*

class InterImpl implementsInter<String> 

{

       publicvoid show(String t)

       {

              System.out.println("show:"+t);

       }

}

*/

class InterImpl<T> implementsInter<T> //如果实现父类的时候也不知道要操作什么类型。这个类型,可以让调用者来指定。

{

       publicvoid show(T t)

       {

              System.out.println("show:"+t);

       }

}

class GenericDemo5

{

       publicstatic void main(String[] args)

       {

              InterImpl<Integer>i = new InterImpl<Integer>();

              i.show(4);

              //InterImpli = new InterImpl();

              //i.show("haha");

       }

}

 

8、泛型限定

l  通配符。也可以理解为占位符。

l  泛型的限定:(我只想打印一个范围,即不想打印全部,也不想打印一个)

 extendsE: 可以接收E类型或者E的子类型。上限。(下边可以一直扩展)

 super E: 可以接收E类型或者E的父类型。下限。(E固定了,上面可以有很多)例:TreeSet(Comparator<? super E> comparator)

import java.util.*;

class GenericDemo6

{

       publicstatic void main(String[] args)

       {

              /*

              ArrayList<String>al = new ArrayList<String>();

              al.add("abc1");

              al.add("abc2");

              al.add("abc3");

              ArrayList<Integer>al1 = new ArrayList<Integer>();

              al1.add(4);

              al1.add(7);

              al1.add(1);

              printColl(al);

              printColl(al1);

              */

              ArrayList<Person>al = new ArrayList<Person>();

              al.add(newPerson("abc1"));

              al.add(newPerson("abc2"));

              al.add(newPerson("abc3"));

              //printColl(al);

              ArrayList<Student>al1 = new ArrayList<Student>();

              al1.add(newStudent("abc--1"));

              al1.add(newStudent("abc--2"));

              al1.add(newStudent("abc--3"));

              printColl(al1);  //ArrayList<? extends Person> al = newArrayList<Student>();error

 

       }

       publicstatic void printColl(Collection<? extends Person> al) //泛型限定。上限,即可以接收Person也可以接收Student

       {

              Iterator<?extends Person> it = al.iterator();

              while(it.hasNext())

              {

                     System.out.println(it.next().getName());

              }

       }

       /*

       //ArrayListal = new ArrayList<Integer>();error 我想打印任意类型的对象,这个时候有这样一种做法,当我们的对象类型不确定的时候,我们可以用一个通配符来表示。1.4之前是没有泛型的,为了兼容老版本,不写泛型也行,但是不严谨。用问题来代替,表示一个点位符。可以以表示为public static <T> void printColl(ArrayList<T>al),表示成一个具体类型的话,这个具体的类型,可以在下面T t = it.next();具体的操作这个类型。?是不明确类型是一个占位符,不能有具体的操作。不能直接打印长度,因为?是一个不明确类型,而it.next.length()是一个具体的方法。可以用it.next.toString因为所有对象都具备。

public staticvoid printColl(ArrayList<?> al)

       {

              Iterator<?>it = al.iterator();

              while(it.hasNext())

              {

                     System.out.println(it.next().toString());

              }

       }

       */

}

class Person

{

       privateString name;

       Person(Stringname)

       {

              this.name= name;

       }

       publicString getName()

       {

              returnname;

       }

}

class Student extends Person

{

       Student(Stringname)

       {

              super(name);

       }

}

/*

class Student implementsComparable<Person>//<? super E>:不传学生,传学生的父类也可以。

{

       publicint compareTo(Person s) //这里Person里面也能接收学生。Person也具有了这个方法

       {

              this.getName()

       }

}

*/

class Comp implementsComparator<Person>

{

       publicint compare(Person s1,Person s2)

       {

              //Persons1 = new Student("abc1");

              returns1.getName().compareTo(s2.getName());

       }

}

TreeSet<Student> ts = newTreeSet<Student>(new Comp());

ts.add(new Student("abc1"));

ts.add(new Student("abc2"));

ts.add(new Student("abc3"));

l  泛型:指定具体类型<Person>,但我想打印很多类型,用<?>Person还有子类型,我想限定一下,其他的我都不要打印,<? extends Person>

l  泛型限定是用于泛型扩展用的。

 

9、泛型限定2(练习)

TreeSet(Comparator<? super E>comparator)

import java.util.*;

class GenericDemo7

{

       publicstatic void main(String[] args)

       {

              TreeSet<Student>ts = new TreeSet<Student>(new Comp());

              ts.add(newStudent("abc03"));

              ts.add(newStudent("abc02"));

              ts.add(newStudent("abc06"));

              ts.add(newStudent("abc01"));

              Iterator<Student>it = ts.iterator();

              while(it.hasNext())

              {

                     System.out.println(it.next().getName());

              }

              TreeSet<Worker>ts1 = new TreeSet<Worker>(new Comp());

              ts1.add(newWorker("wabc--03"));

              ts1.add(newWorker("wabc--02"));

              ts1.add(newWorker("wabc--06"));

              ts1.add(newWorker("wabc--01"));

              Iterator<Worker>it1 = ts1.iterator();

              while(it1.hasNext())

              {

                     System.out.println(it1.next().getName());

              }

       }

}

/*

class StuComp implementsComparator<Student> //用这种方式的话,每多个子类型就要多一个比较器,比较麻烦

{

       publicint compare(Student s1,Student s2)

       {

              returns1.getName().compareTo(s2.getName());

       }

}

class WorkerComp implementsComparator<Worker>

{

       publicint compare(Worker s1,Worker s2)

       {

              returns1.getName().compareTo(s2.getName());

       }

}

*/

class Comp implementsComparator<Person>

{

       publicint compare(Person p1,Person p2)

       {

              return p2.getName().compareTo(p1.getName());

       }

}

class Person

{

       privateString name;

       Person(Stringname)

       {

              this.name= name;

       }

       public String getName()

       {

              return name;

       }

       public String toString()

       {

              return "person :"+name;

       }

}

class Student extends Person

{

       Student(Stringname)

       {

              super(name);

       }

}

class Worker extends Person

{

       Worker(Stringname)

       {

              super(name);

       }

}

 

                                          ------- android培训java培训、期待与您交流!----------