java中的Comparator和Comparable比较器+单例模式
java中的Comparator和Comparable比较器的用法
Comparable和Comparator都是用来实现集合中的排序的,Comparator位于包java.util下,而Comparable位于包java.lang下,Comparable是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作),是内部定义的排序;而后者在一个独立的类中实现比较,是外部实现的排序。 如果一个类没有实现Comparable接口,或是这个对象不支持自比较或者自比较函数不能满足你的要求时,可以通过Comparator来实现比较算法进行排序,并且为了使用不同的排序标准做准备,比如:升序、降序。所以,如想实现排序,就需要让类对象自身实现Comparable接口,重写其中的compareTo(T o)方法;或在外部定义比较器实现Comparator接口,重写其compare(T o1,T o2)方法。前者只有一个参数,后者有两个参数。排序时可以调用java.util.Arrays.sort()来排序对象数组,或是调用集合中的sort()方法就可以按照相应的排序方法进行排序。方法返回一个基本类型的整型,返回负数表示o1小于o2,返回0表示o1和o2相等,返回正数表示o1大于o2。
用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了Comparator接口的对象来实现控制它的排序就行了。
例子:
import java.util.Arrays; import java.util.Comparator;
class Person implements Comparable<Person>{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public int getAge() { return this.age; } @Override public String toString() { return ""+this.name+" "+this.age; } @Override public int compareTo(Person o) { if (this.getName().compareTo(o.getName()) != 0) return this.getName().compareTo(o.getName()); else if (this.getAge() < o.getAge()) return -1; else if (this.getAge() > o.getAge()) return 1; else return 0; } } } class Cmp implements Comparator { @Override public int compare(Object arg0, Object arg1) { Person a = (Person) arg0; Person b = (Person) arg1; if (a.getName().compareTo(b.getName()) != 0) return a.getName().compareTo(b.getName()); else if (a.getAge() < b.getAge()) return -1; else if (a.getAge() > b.getAge()) return 1; else return 0; } } } public class Main { public static void main(String[] args) { Person[] p = new Person[4]; p[0] = new Person("ZZZ",19); p[1] = new Person("AAA", 109); p[2] = new Person("AAA", 19); p[3] = new Person("YYY",100); // Arrays.sort(p);//调用自有的排序 Arrays.sort(p, new Cmp());//调用Comparator定义的排序 System.out.println(Arrays.toString(p)); } }
2.对复合数据类型的数据的排序
函数原型: (1)public static<T> void sort(T[] a,Comparator c) 根据指定比较器产生的顺序对指定对象数组进行排序。
(2)public static<T> void sort(T[] a,int fromIndex,int toIndex,Comparator c) 根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。
说明:这个两个排序算法是“经过调优的合并排序”算法。
代码实例:
import java.util.Arrays;
import java.util.Arrays;
import java.util.Comparator;
class Point{
int x;
int y;
}
//比较器,x坐标从小到大排序;x相同时,按照y从小到大排序
class MyComprator implements Comparator {
public int compare(Object arg0, Object arg1) {
Point t1=(Point)arg0;
Point t2=(Point)arg1;
if(t1.x != t2.x)
return t1.x>t2.x? 1:-1;
else
return t1.y>t2.y? 1:-1;
}
}
public class Arraysort {
Point[] arr;
Arraysort(){
arr=new Point[4]; //定义对象数组arr,并分配存储的空间
for(int i=0;i<4;i++)
arr[i]=new Point();
}
public static void main(String[] args) {
Arraysort sort=new Arraysort();
sort.arr[0].y=1; //初始化,对象数组中的数据
sort.arr[0].x=2;
sort.arr[1].x=2;
sort.arr[1].y=2;
sort.arr[2].x=1;
sort.arr[2].y=2;
sort.arr[3].x=0;
sort.arr[3].y=1;
Arrays.sort(sort.arr, new MyComprator()); //使用指定的排序器,进行排序
for(int i=0;i<4;i++) //输出排序结果
System.out.println("("+sort.arr[i].x+","+sort.arr[i].y+")");
}
}
执行输出:
单例模式的实现的两种方式,如下所示:
1、懒汉式,线程不安全
是否 Lazy 初始化:是
是否多线程安全:否
实现难度:易
描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
代码实例:
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2、懒汉式,线程安全
是否 Lazy 初始化:是
是否多线程安全:是
实现难度:易
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
代码实例:
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、饿汉式
是否 Lazy 初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。
代码实例:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}