JAVA--集合之泛型与List集合的排序.
泛型首先贴上甲骨文官网对泛型的解释可以使用泛型开发一个更好的解决方案,在实例化时为所使用的容器分配一个类型,也称泛型类型,这样就可以创建一个对象来存储所分配类型的对象。泛型类型是一种类型参数化的类或接口,这意味着可以通过执行泛型类型调用 分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。...
泛型
首先贴上甲骨文官网对泛型的解释
可以使用泛型开发一个更好的解决方案,在实例化时为所使用的容器分配一个类型,也称泛型类型,这样就可以创建一个对象来存储所分配类型的对象。泛型类型是一种类型参数化的类或接口,这意味着可以通过执行泛型类型调用 分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。
大意就是进行"参数化类型",在类,接口,方法的定义上都可以使用,用来指定数据类型名,编译器在进行编译的时候检查传入数据的类型,免得在运行的时候出现大量的错误.需要注意的是,泛型只能传入引用数据类型,不能传入基本数据类型.
然后来看一个不用泛型与用泛型存储多种类型数据的对比实例,可能会对以上的内容有一个了解.
不使用泛型:
首先定义一个简单的Point类型:
/*一个简单的Point类,只提供构造器,get方法与toString方法*/
public class Point {
private int x;private int y;
/*构造器*/
public Point(int x, int y) {
this.x = x;
this.y = y;
}
/*get方法*/
public int getX() { return x; }
public int getY() { return y; }
/*toString方法*/
public String toString() {
return "("+x+","+y+")";
}
}
然后提供容器类型Cotain类型,提供一个能存储任何类型数据的Object类型数组作为容器:
import java.util.Arrays;
/*容器类型*/
public class Contain {
/*想要存储各种类型数据,就必须要用Object类型的"容器"了.*/
private Object[] objs;
public Contain(){
/*初始化容器*/
objs=new Object[0];
}
/*向容器添加元素的方法*/
public void add(Object o){
/*扩容以存储数据*/
objs=Arrays.copyOf(objs,objs.length+1);
/*数据添加至容器*/
objs[objs.length-1]=o;
}
/*通过下标取出元素*/
public Object get(int index){
if (index>0&&index<objs.length)
return objs[index];
else {
throw new RuntimeException("传入参数有误.");
}
}
}
测试类TestContain:
public class TestContain {
public static void main(String[] args) {
/*初始化容器类型*/
Contain c=new Contain();
/*存入String类型数据*/
c.add("String类型数据1");
c.add("String类型数据2");
/*存入Integer类型数据*/
c.add(15);//发生了自动装箱
/*存入Point类型数据*/
c.add(new Point(5,6));
c.add(new Point(11,15));
/*取出一个String类型数据,必须进行强制类型转换*/
String str= (String) c.get(1);
/*取出一个Integer类型数据,必须进行强制类型转换*/
Integer i= (Integer) c.get(2);
/*取出一个Point类型数据,必须进行强制类型转换*/
Point p= (Point) c.get(3);
System.out.println(str);
System.out.println(i);
System.out.println(p);
}
}
运行结果:
String类型数据2
15
(5,6)
可以看到取出三种类型的数据的数据要进行三次强制类型转换,十分繁琐.
下面来看看使用泛型的情况,Point类直接使用.
提供泛型的类型Type,可以看到类名后使用尖括号定义了泛型.
/*泛型类型,尖括号内的字母为泛型,可以使用任意大写字母.*/
public class Type<T> {
private T t;
public Type(T t) { this.t = t; }
}
测试类TestType,定义了一个存储String类型数据的集合c:
import java.util.ArrayList;
import java.util.Collection;
public class TestType {
public static void main(String[] args) {
Type<String> c1=new Type<String>("A");
Type<Integer> c2=new Type<Integer>(3);
Type<Point> c3=new Type<Point>(new Point(2,2));
/*定义存储String类型的集合c*/
Collection<Type<String>> c=new ArrayList<>();
c.add(c1);
}
}
值得注意的是,调用ArrayList的add方法时,编译器自动检查了类型,使得非String类型的数据无法传入:
强行传入的情况:
可以看到编译器帮助我们检查了类型,防止传入错误类型的数据,有效避免了运行时出现的种种问题.
List内元素的排序
首先定义一个Integer类型的集合并输出:
import java.util.ArrayList;
import java.util.List;
public class CompareTest {
public static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
list.add(10);
list.add(7);
list.add(19);
list.add(2);
list.add(8);
System.out.println("排序之前的价格:"+list);
......
然后调用工具类Collections的sort方法进行排序并输出:
.......
Collections.sort(list);
System.out.println("排序之后的集合"+list);
运行结果:
排序之前的集合[10, 7, 19, 2, 8]
排序之后的集合[2, 7, 8, 10, 19]
可以看到是按照从小到大的顺序排的.
再定义一个String类型的集合并做如上处理:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CompareTest {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Java");
list.add("C");
list.add("12345");
list.add("Python");
list.add("abcde");
list.add("Perl");
System.out.println("排序之前的集合"+list);
Collections.sort(list);
System.out.println("排序之后的集合"+list);
}
}
运行结果:
排序之前的集合[Java, C, 12345, Python, abcde, Perl]
排序之后的集合[12345, C, Java, Perl, Python, abcde]
可以看到是按照第一个字符的ASCII顺序排列的,若第一个字符一样则按照下一个的ASCII,以此类推.
下面再看看上面定义的Point类能否进行排序:
刚刚把泛型改为Point就报错了,大概意思就是这个类未实现Comparable接口.
而Integer类与String类都实现了该接口,即重写了compareTo方法(具体可以去源码查看),所以可以进行排序操作.
下面来看看这个方法的规则,首先看看Comparable接口的此方法:
public int compareTo(T o);
返回值为int,排序的关键就是这个int返回值了,下面再来看看Integer类的此方法:
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
/*再进入compare方法*/
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
按照以上的逻辑,compare方法的int x对应compareTo方法的this.value,int y对应anotherInteger.value.
而Integer类型的集合是按照从小到大排列的,所以可以得出一个结论:
this的值减去o的值,按照升序排列.那么相反,o的值减去this的值就是降序了.
确定了顺序,就应该利用这个int返回值了:
如果大于0,返回大于0的一个数,this就排在o的后面.
如果等于0, 返回0.
如果小于0, 返回小于0的一个数,this就排在o的前面.
知道了排序规则之后,就可以尝试编写Point类的compareTo方法了,这里设定比较规则为距离原点的距离:
public class Point implements Comparable<Point>{
/*↑注意添加泛型*/
......
public int compareTo(Point o) {
return (this.x*this.x+this.y*this.y)-(o.x*o.x+o.y*o.y);
}
}
然后在测试类内添加五个点,这里使用随机数配合for循环生成:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CompareTest {
public static void main(String[] args) {
List<Point> list=new ArrayList<>();
for (int i = 0; i < 5; i++) {
/*随机生成横纵坐标*/
int x=(int)(Math.random()*20);
int y=(int)(Math.random()*20);
list.add(new Point(x,y));
}
System.out.println("排序之前的集合"+list);
Collections.sort(list);
System.out.println("排序之后的集合"+list);
}
}
其中一次的运行结果为:
排序之前的集合[(16,16), (6,12), (5,10), (8,15), (12,3)]
排序之后的集合[(5,10), (12,3), (6,12), (8,15), (16,16)]
可以看到五个点按照我们所规定的顺序排列了.
更多推荐
所有评论(0)