集合框架2
一、TreeSet
1、Set:无序,不可以重复元素
|--HashSet:数据结构是哈希表。线程是非同步的。
保证元素唯一性的原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。
|--TreeSet:可以对Set集合中的元素进行排序,验证程序如下。
1、Set:无序,不可以重复元素
|--HashSet:数据结构是哈希表。线程是非同步的。
保证元素唯一性的原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。
|--TreeSet:可以对Set集合中的元素进行排序,验证程序如下。
import java.util.*;
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts= new TreeSet();
ts.add("cba");
ts.add("aaa");
ts.add("dbc");
ts.add("Dac");
Iterator it=ts.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
}
二、TreeSet存储自定义对象
需求:
往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
记住,排序时,当主要条件相同时,一定判断一下次要条件。
需求:
往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
记住,排序时,当主要条件相同时,一定判断一下次要条件。
import java.util.*;
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Student("lisi02",22)); //02首先进入内存
ts.add(new Student("lisi007",20)); //007进入内存,调用compareTo方法,和02比较
ts.add(new Student("lisi09",19)); //09进入内存,调用compareTo方法,和02 /07比较
//ts.add(new Student("lisi08",19));
//ts.add(new Student("lisi007",20));
//ts.add(new Student("lisi01",40));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class Student implements Comparable //该接口强制让学生具备比较性,符合comparable接口,自动调用compareTo方法
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj)
{
//return 0;
if(!(obj instanceof Student)) //instanceof用于判断obj是不是Student对象
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name); //主要条件年龄相同,以次要条件——姓名作为比较方式。姓名为Sting类,已经实现了compareTo方法,可以直接调用
}
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
三、二叉树
底层数据结构是二叉树数据结构
二叉树数据结构特点:左小右大的数据结构,特高比较性能,又被称为红黑树,比较时先去中间数字,可以提高比较效率
保证元素唯一性的依据,通过,compareTo方法return 0.
TreeSet排序的第一种方式:让元素(列入示例程序中的student)自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
四、实现Comparator方式排序(常用,对外提供接口,提供功能扩展)
TreeSet的第二种排序方式,当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性,在集合初始化时,就有了比较方式。
当两种排序都存在时,以比较器为主。
定义一个类,实现Comparator接口,覆盖compare方法。
class Student implements Comparable//该接口强制让学生具备比较性。
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(Object obj) //学生比较器,
{
//return 0;
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student)obj;
//System.out.println(this.name+"....compareto....."+s.name);
if(this.age>s.age)
return 1;
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet( new MyCompare()); //构造一个新的空 TreeSet,它根据指定比较器进行排序
//TreeSet ts = new TreeSet(); 以学生比较器为主的写法
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi02",21));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi007",29));
//ts.add(new Student("lisi007",20));
//ts.add(new Student("lisi01",40));
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class MyCompare implements Comparator //定义一个比较器
{
public int compare(Object o1,Object o2)
{
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num==0)
{
//第一种年龄比较写法
if(s1.getAge()>s2.getAge())
return 1;
if(s1.getAge()==s2.getAge())
return 0;
return -1;
// return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); 第二种年龄比较写法
}
return num;
}
}
五、TreeSet练习
练习:按照字符串长度排序。
字符串本身具备比较性。但是它的比较方式不是所需要的。
这时就只能使用比较器。
import java.util.*;
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new StrLenComparator());
ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("aaa");
ts.add("z");
ts.add("hahaha");
Iterator it = ts.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
class StrLenComparator implements Comparator
{
public int compare(Object o1,Object o2)
{
String s1=(String)o1;
String s2=(String)o2;
int num=new Integer(s1.length).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}
另一种写法——匿名内部类
import java.util.*;
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new Comparator()
{
public int compare(Object o1,Object o2)
{
String s1=(String)o1;
String s2=(String)o2;
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
});
ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("aaa");
ts.add("z");
ts.add("hahaha");
Iterator it = ts.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
六、泛型概述
1.5版本可以添加基本数据类型,
要避免,程序编译没问题,运行有问题,列入一下程序编译没问题,但是运行就会出现数据类型转换异常
泛型可以解决以上问题
泛型(可以简单理解为广泛的类型)
JDK1.4版本之前,程序员主管判断,即事先知道存储的元素为String
JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。
好处
1.将运行时期出现问题ClassCastException,转移到了编译时期。,
方便于程序员解决问题。让运行时问题减少,安全。,
2,避免了强制转换麻烦。
import java.util.*;
class GenericDemo
{
public static void main(String[] args)
{
//ArrayList al = new ArrayList();
//泛型表示方法,编译失败,暴露问题
ArrayList<String> al = new ArrayList<String>();
//<> 泛型
//{} 程序结构
//()参数
//[] 数组
al.add("abc01");
al.add("abc0991");
al.add("abc014");
al.add(4);//al.add(new Integer(4));
//设定it为String类型
Iterator<String> it = al.iterator();
while(it.hasNext())
{
String s = it.next();
System.out.println(s+":"+s.length());
}
}
}
七、泛型使用
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,
只要见到<>就要定义泛型。
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
import java.util.*;
class GenericDemo2
{
public static 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())
{
String s = it.next();
System.out.println(s);
}
}
}
class LenComparator implements Comparator<String>//泛型
{
public int compare(String o1,String o2)//泛型,对于equal不能用此方法
{
//倒序排列写法,交换o2和o1值
int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));
if(num==0)
return o2.compareTo(o1);
return num;
}
}
八、泛型类
class Tool
{
private Worker w;
public void setWorker(Worker w)
{
this.w = w;
}
public Worker getWorker()
{
return w;
}
}
class Worker
{
}
class Student
{
}
//泛型前做法。
class Tool
{
private Object obj;
public void setObject(Object obj)
{
this.obj = obj;
}
public Object getObject()
{
return obj;
}
}
泛型类。
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。
现在定义泛型来完成扩展。
class Utils<QQ>
{
private QQ q;
public void setObject(QQ q)
{
this.q = q;
}
public QQ getObject()
{
return q;
}
}
class GenericDemo3
{
public static void main(String[] args)
{
Utils<Worker> u = new Utils<Worker>();
u.setObject(new Student());
Worker w = u.getObject();;
Tool t = new Tool();
t.setObject(new Student());
Worker w = (Worker)t.getObject();
}
}
九、泛型方法
import java.util.*;
class Demo
{
public <T>void show(T t)
{
System.out.println("show:"+t);
}
public <T> void print(T t)
{
System.out.println("show:"+t);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();
d.show("haha");
d.show(new Integer(4));
d.print("heihei");
}
}
例如:ArrayList<E>集合,类型明确后,所有方法操作的都是同一个类型
静态方法不可以访问类上定义的泛型。以下程序为错误写法
import java.util.*;
class Demo<T>
{
public <T>void show(T t) //操作类型和对象一样
{
System.out.println("show:"+t);
}
public <Q> void print(Q t) //操作对象与方法一致
{
System.out.println("show:"+t);
}
public static <T> void method(T t) //与类操作类型相同,错误
{
System.out.println("method:"+t);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo <String> d = new Demo<String>();
d.show("haha");
d.print(5);
}
}
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
import java.util.*;
class Demo<T>
{
public <T>void show(T t) //操作类型和对象一样
{
System.out.println("show:"+t);
}
public <Q> void print(Q t) //操作对象与方法一致
{
System.out.println("show:"+t);
}
public static <W> void method (W t) //与类操作类型不相同,正确
{
System.out.println("method:"+t);
}
//常见错误写法 public static void<W> method(W t)或public <W>static void method(W t),正确写法为返回类型+函数名
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo <String> d = new Demo<String>();
d.show("haha");
d.print(5);
Demo.method("heihei");
}
}
十一 、泛型接口
子类已经知道操作类型
interface Inter<T>
{
void show(T t);
}
class InterImpl implements Inter<String>
{
public void show(String t)
{
System.out.println("show :"+t);
}
}
class GenericDemo5
{
public static void main(String[] args)
{
InterImpl i = new InterImpl();
i.show("haha");
}
}
子类已经知道操作类型
interface Inter<T>
{
void show(T t);
}
class InterImpl<T> implements Inter<T>
{
public void show(T t)
{
System.out.println("show :"+t);
}
}
class GenericDemo5
{
public static void main(String[] args)
{
InterImpl<Integer> i = new InterImpl<Integer>();
i.show(4);
}
}
十二、泛型限定
1、对象类型不确定,使用通配符表示
import java.util.*;
class GenericDemo6
{
public static 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);
public static void printColl(ArrayList<?> al) // ?通配符
{
Iterator<?> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().toString());
//System.out.println(it.next().length());
//错误写法,如同多态,不能预先使用子类中特有方法,通配符不能保证可以使用length,列入通配符为Integer中就没有length,
//但是toString可以使用,因为任何类型都具备toString
}
}
//另外一种表示方式
public static <T> void printColl(ArrayList<T> al) // T通配符
{
Iterator<T> it = al.iterator();
while(it.hasNext())
{
T t =it.next();
System.out.println(t);
}
}
}
2、类型不匹配,会导致错误
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 GenericDemo4
{
public static void main(String[] args)
{
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
//printColl(al);
ArrayList<Person> al = new ArrayList<Person>();
all.add(new Student("abc--1"));
all.add(new Student("abc--2"));
all.add(new Student("abc--3"));
printColl(all);
//ArrayList<Student> al=new ArrayList<Person>();error,类型不匹配
}
public static void printColl(ArrayList <Person> al)
{
Iterator< Person> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
3.使用泛型限定写法
上限限定,列入TreeSet中的Comparator
public static void printColl(ArrayList <? extends Person> al)
{
Iterator<? extends Person> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
//下限限定,列入collection中的addAll()
public static void printColl(ArrayList <? super Student> al)
//表示可以接收Student类型和Student父类型
{
Iterator<? super Person> it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
比较器泛型
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 Student implements Comparable<Person>//<? super E>
{
public int compareTo(Person s)
{
this.getName()
}
}
class Comp implements Comparator<Person>
{
public int compare(Person s1,Person s2)
{
//Person s1 = new Student("abc1");//
return s1.getName().compareTo(s2.getName());
}
}
TreeSet<Student> ts = new TreeSet<Student>(new Comp());
ts.add(new Student("abc1"));
ts.add(new Student("abc2"));
ts.add(new Student("abc3"));
4.总结
? 通配符。也可以理解为占位符。
泛型的限定;
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限