导读:TreeSet,TreeSet自定义对象,Comparator方式排序,泛型概述,泛型使用,泛型类,泛型方法,静态方法类型,泛型接口,泛型限定
1、TreeSet、TreeSet存储自定义对象
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()));
//想着倒着输出的话,把o2和o1倒一下就可以了。
if(num==0)
returno2.compareTo(o1); //这里也倒一下。
returnnum;
}
}
l 我们在写HashSet集合的时候,要覆盖两个方法,一个叫做hashCode(),一个叫做equals()。这个equals覆写是的是Object,Object没有泛型。这个必须要做转换。转换的时候,还要判断是不是这种类型,不要瞎写。
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);
}
}