关键字:TreeSet、泛型
Set:无序,不可重复元素。数据结构不一样,保证数据唯一性的方式也不一样。
1. 让元素自身具备比较性,元素要实现Comparable接口,覆盖compareTo()方法,这种方式也称为元素的自然顺序,或者叫默认顺序。许多java已有类都已经实现该接口,例如,String、Integer等。代码举例,
public int compareTo(Student st)//先比较年龄再比较姓名
{
}
2. 当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时需要让集合自身具备比较性。在集合初始化时,就有了比较方式。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。定义一个比较器,实现Comparator接口,覆盖compare()方法(返回值是正数、负数和0,不一定是1或-1)。代码举例,
class MyCompare implements Comparator<Student>//比较器
{
}
当两种排序都存在时,以比较器为主。比较器更加常用。做项目时,一定要留有接口。
注意:主要条件和次要条件搭配使用,防止元素丢失。涉及到对元素的操作都与排序有关。
泛型
当集合中存入不同类型数据时,某些操作会因为类型不同引发异常,例如,Integer类和String类无法同时输出长度。
JDK1.5后出现的新特性,用于解决安全问题,是一种安全机制。让集合只能装一种类型的对象,如果有其他类对象进入,编译不通过。
泛型格式,通过< >来定义只能操作的引用数据类型,例如,ArrayList<String> ss = new ArrayList<String>();定义一个ArrayList容器,元素都是String类型。
好处:1. 将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题,让运行期间问题减少,更加安全。
2. 避免了强制装换的繁琐,强制客观的限定类型。
在使用java提供的对象时,何时使用泛型?在集合框架中很常见,只要见到< >就要定义泛型。其实< >用来接受数据类型的。当使用集合时,将集合中要存储的数据类型(引用数据类型)作为参数传递到< >中即可,类似函数中传递参数。
HashSet集合框架不能使用泛型,因为内部的equals仍然使用Object作为参数,而Object类没有泛型。
定义一个新类,需要在内部添加hashCode()、equals()、toString()并实现Comparable接口复写compareTo()方法,以便于适应各种集合框架。
泛型扩展
当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型类完成扩展。例如:
class Demo<T>//内部函数只能操作T类型。
{
}
泛型类,类的内部无需再明确操作类型,无需转换动作,但是只能操作某一引用类型的数据。泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。类定义后,创建对象只操作一种数据。
泛型方法,为了让不同方法可以操作不同类型,而且类型还不确定,可以将泛型定义在方法上。例如,
class Demo_2
{
}
也可以将泛型类和泛型方法混合使用,泛型方法走自己的类型,随意,例如,
class Demo_3<T>
{
}
泛型静态方法:静态方法不可以访问类上定义的泛型;如果静态方法操作的引用数据类型不确定,可以将泛型定义在静态方法上。例如,
public static<R> void fun(R r)
{
}
注意泛型的位置:返回值类型的前面,修饰符的后面。泛型类的位置是,类名后面。
注意泛型的位置:class Utils<QQ>;interface Inter<T>;public<T> void show(T t);public static<R> void fun(R r);ArrayList<String> arr = new ArrayList<String>();
泛型接口:两种方式:
子类已经确定操作类型,例如:
class Demo_1 implements Inter<String>
{
}
子类不能确定操作类型,继续使用泛型类,例如,
class Demo_4<T> implements Inter<T>
{
}
泛型的高级应用:限定
当操作类型不明确时,可以使用通配符(站位符)来表示。例如,
public static void printArray(ArrayList<?> ar)
{
}
不用<?>占位符也可以,只是不严谨。将?换成泛型T也可以,T可以代表具体类型,在方法内部接收数据。例如,T t = it.next();。<?>不能在方法内接受数据类型。
使用泛型可以接受不同的对象,但是对象的特有方法不能再使用,例如,length();只要是Object类的方法都能用,例如,toString()。
子父类数据需要同时操作时,使用泛型限定,例如
public static void printArray(ArrayList<? extends Person> ar)//打印Person和其子类。
{
}
?,通配符,也可以理解为站位符,意为必须具备泛型,但具体泛型不知道。1.5以后都要写,用于站位。
泛型的限定:
?extends E:可以接受E类型或者其子类型,上限。例如,
?Super E:可以接受E类型及其父类型,下限。许多集合不可以有下限,例如,ArrayList。
Comparator比较器可以传入父类,使得子类也可以使用比较器。但比较方法必须是父类的。利用了多态的特性。例如,
class Com implements Comparator<Person>//父类的比较器
{
}