比较器
Java中有一些比较运算符,如>、=、<=、instanceof、equals,不过其中大部分只能比较基本数据类型,引用数据类型除了==、instanceof、equals之外,>、
所以,为了满足对象排序的需求,java提供了两个接口实现对象排序。
Java实现对象排序的方式有两种:
自然排序:java.lang.Comparable
定制排序:java.util.Comparator
自然排序 Comparable接口
首先,看一下Comarable的典型例子,String类的比较。像String类或者包装类中都实现了Comparable接口,重写了compareTo()方法,在重写的方法体中给出了比较两个对象大小的方式。
如,String类中的compareTo方法中是按照字符串中字符的Unicode值进行从小到大的比较。
@Test
public void testComparable(){
String[] arr = new String[]{"EE","FF","CC","BB","DD","AA"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // 打印:[AA, BB, CC, DD, EE, FF]
}
对于自然排序来说,重写compareTo(obj)方法的规则如下:
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数
如果当前对象this等于形参对象obj,则返回零。
对于自定义类,如果需要排序,那么可以让自定义类实现Comparable接口,并重写CompareTo方法在CompareTo中,指明如何对对象进行排序。
下面进行举例:
假如,有一个商品类,有商品价格和商品名称的属性,现在需要根据商品的价格高低对多个对象进行排序。
public class Goods implements Comparable{
private String name; // 商品名称
private double price; // 商品价格
public Goods() {
}
public Goods(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
// 重写toString方法
@Override
public String toString() {
return "name:"+ name + ",price:"+ price;
}
// 指明如何进行排序,比如按照商品的价格从低到高进行排序
@Override
public int compareTo(Object o) {
if (o instanceof Goods){
Goods goods = (Goods)o;
if(this.price > goods.price){
return 1;
}else if(this.price < goods.price){
return -1;
}else{
return 0;
}
}
throw new RuntimeException("传入的数据类型不一致!");
}
}
测试,创建Goods对象数组,存储四个商品,然后使用Arrays.sort进行排序,再进行输出,代码如下:
@Test
public void testGoods(){
Goods[] arr = new Goods[4];
arr[0] = new Goods("Rapoo",189.9);
arr[1] = new Goods("Logitech",239.5);
arr[2] = new Goods("Razer",100.5);
arr[3] = new Goods("Dell",79.9);
System.out.println("排序前: " + Arrays.toString(arr));
Arrays.sort(arr);
System.out.println("排序后: " + Arrays.toString(arr));
}
运行结果:
排序前: [name:Rapoo,price:189.9, name:Logitech,price:239.5, name:Razer,price:100.5, name:Dell,price:79.9]
排序后: [name:Dell,price:79.9, name:Razer,price:100.5, name:Rapoo,price:189.9, name:Logitech,price:239.5]
这样,输出的对象数组就会按照商品的价格从低到高进行排序。
总结一下:使用自然排序来比较自定义类的对象大小,先让自定义实现Comparable接口,然后重写compareTo()方法,在方法体内写具体要根据什么逻辑来比较对象的大小。
定制排序 Comparator接口
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用Comparator的对象来排序,强行对多个对象进行整体排序的比较。
同样,实现类需要重写接口的方法compare(),compare方法的重写规则如下:
对于方法compare(Object o1,Object o2),比较o1和o2的大小:
如果方法返示回正整数,则表示o1大于o2 ;
如果返回0,表示相等;
返回负整数,表示o1 小于o2。
示例,还是使用上面Goods.class代码为例:
@Test
public void testGoods2(){
Goods[] arr = new Goods[4];
arr[0] = new Goods("Rapoo",189.9);
arr[1] = new Goods("Logitech",239.5);
arr[2] = new Goods("Razer",100.5);
arr[3] = new Goods("Dell",79.9);
Arrays.sort(arr, new Comparator() {
// 指明商品比较大小的方式:按照商品名称从低到高排序,如果是相同价格的就按照价格从高到低排序
@Override
public int compare(Object o, Object t1) {
if (o instanceof Goods && t1 instanceof Goods){
Goods g1 = (Goods)o;
Goods g2 = (Goods)t1;
if (g1.getName().equals(g2.getName())){
return -Double.compare(g1.getPrice(),g2.getPrice());
}else{
return g1.getName().compareTo(g2.getName());
}
}
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
}
除此之外,可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
示例:
@Test
public void testComparator(){
String[] arr = new String[]{"EE","FF","CC","BB","DD","AA"};
Arrays.sort(arr,new Comparator(){
// 定制规则,让字符串从大到小进行排序
@Override
public int compare(Object o, Object t1) {
if (o instanceof String && t1 instanceof String){
String s1 = (String)o;
String s2 = (String)t1;
return -s1.compareTo(s2);
}
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
}
还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的
顺序,或者为那些没有自然顺序的对象 collection 提供排序。
常用类之System类
System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便的进行调用。
成员变量
System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
成员方法
native long currentTimeMillis(): :
该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
void exit(int status)
该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表异常退出。 使用该方法可以在图形界面编程中实现程序的退出功能等。
void gc()
该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
String getProperty(String key)
该方法的作用是获得系统中属性名为key的属性对应的值。系统中常见的属性名以及属性的作用如下表所示:
属性名
说明
java.version
Java运行环境的版本
java.home
Java安装目录
os.name
操作系统名称
os.version
操作系统版本
user.name
用户名称
user.home
用户的主目录
user.dir
用户当前工作目录
示例:
@Test
public void testSystem(){
String javaVersion = System.getProperty("java.version");
System.out.println("java的version:" + javaVersion);
String javaHome = System.getProperty("java.home");
System.out.println("java的home:" + javaHome);
String osName = System.getProperty("os.name");
System.out.println("os的name:" + osName);
String osVersion = System.getProperty("os.version");
System.out.println("os的version:" + osVersion);
String userName = System.getProperty("user.name");
System.out.println("user的name:" + userName);
String userHome = System.getProperty("user.home");
System.out.println("user的home:" + userHome);
String userDir = System.getProperty("user.dir");
System.out.println("user的dir:" + userDir);
}
常用类之Math类
java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double类型。常用方法如下:
abs:求绝对值
acos,asin,atan,cos,sin,tan:三角函数
sqrt:求平方根
pow(double a,doble b):求a的b次幂
log:求自然对数
exp:e为底指数
max(double a,double b):求a,b的最大值
min(double a,double b):求a,b的最小值
random():返回0.0 到1.0 的随机数
long round(double a) :double型数据a 转换为long 型(四舍五入)
toDegrees(double angrad):弧度—> 角度
toRadians(double angdeg) :角度—> 弧度
常用类之BigInteger类和BigDecimal类
BigInteger类
Integer类作为int的包装类,能存储的最大整型值为2^31 -1,Long类也是有限的,最大为2^63 -1。如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
java.math包的BigInteger可以表示不可变的任意精度的整数。BigInteger提供所有Java的基本整数操作符的对应物,并提供java.lang.Math的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
BigDecimal类
一般的Float类和Double类可以用来做科学计算或工程计算,但在 商业计算中,到 要求数字精度比较高,故用到java.math.BigDecimal类。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
构造器
public BigDecimal(double val)
public BigDecimal(String val)
常用方法
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)