JavaEE - 09常用类3
(4)Java比较器
Comparable接口使用:String implements Comparable<String>
@Test public void test1(){ String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); //[AA, CC, DD, GG, JJ, KK, MM] }
(4.1)自然排序: java.lang.Comparable
- Comparable接口强行对实现它的每个类的对象进行整体排序。被称为类的自然排序。
- 实现Comparable的类必须实现compareTo(Object obj)方法,两个对象通过此方法的返回值来比较大小。
- 如果当前对象this大于形参对象obj,返回正整数;当前对象小于形参对象,返回负整数;等于则返回零。
- 实现Comparable接口的对象列表和数组可以通过Collections.sort或Arrays.sort进行自然排序。
- 实现此接口的对象可以用作有序映射的键或有序集合中的元素,无需指定比较器。
- 对于类C的每一个e1和e2来说,当且仅当e1.compareTo(e2)==0 与 e1.equals(e2)具有相同的boolean值时,类C的自然排序才叫做与equals一致。
- 建议最好使自然排序与equals一致。
- 像String、包装类等实现了Comparable接口,重写了compareTo()方法,进行了从小到大的排序。
按照价格从低到高排序: return Double.compare(this.price, goods.price );
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; } //指明商品比较大小的方式: 按照价格从低到高排序,再按照产品名称从高到低排序 @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; return -this.name.compareTo(goods.name); } } throw new RuntimeException("输入的数据类型不一致"); } // 省略其他代码 }
@Test public void test2(){ Goods goods1 = new Goods("Apple",2.9); Goods goods2 = new Goods("Banana",3.5); Goods goods3 = new Goods("Purple",3.2); Goods goods4 = new Goods("Perple",2.9); Goods[] arr = new Goods[]{goods1,goods2,goods3,goods4}; //[Goods{name='Apple', price=2.9}, Goods{name='Banana', price=3.5}, Goods{name='Purple', price=3.2}, Goods{name='Perple', price=2.9}] System.out.println(Arrays.toString(arr)); Arrays.sort(arr); //[Goods{name='Perple', price=2.9}, Goods{name='Apple', price=2.9}, Goods{name='Purple', price=3.2}, Goods{name='Banana', price=3.5}] System.out.println(Arrays.toString(arr)); }
(4.2)定制排序: java.util.Comparator
- 当元素的类型没有实现 java.lang.Comparable接口而又不方便更改代码,或者实现了java.lang.Comparable接口的排序规则不合适当前的操作,
- 那么可以考虑使用Comparator的对象来排序,强行对多个对象进行整体排序的比较。
- 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:返回正整数,o1大于o2;负整数,o1小于o2;零,o1等于o2。
- 可以将Comparator传递给sort方法(Collections.sort或Arrays.sort),从而允许在排序顺序上实现精确控制。
- 还可以使用Comparator来控制某些数据结构(有序set或有序映射)的顺序,或者为没有自然顺序的对象collection提供排序。
字符串数组按字母从大到小排序
@Test public void test3(){ String[] arr = new String[]{"AA","BB","AB","GG","JJ","DD"}; Arrays.sort(arr, new Comparator(){ @Override public int compare(Object o1, Object o2) { if(o1 instanceof String && o2 instanceof String){ String s1 = (String) o1; String s2 = (String) o2; return -s1.compareTo(s2); } throw new RuntimeException("输入的数据类型不一致"); } }); System.out.println(Arrays.toString(arr)); //[JJ, GG, DD, BB, AB, AA] }
按照产品名称从低到高排序,再按照价格从高到低排序
@Test public void test4(){ Goods goods1 = new Goods("Apple",2.9); Goods goods2 = new Goods("Banana",3.5); Goods goods3 = new Goods("Purple",2.2); Goods goods4 = new Goods("Purple",2.9); Goods[] arr = new Goods[]{goods1,goods2,goods3,goods4}; // 按照产品名称从低到高排序,再按照价格从高到低排序 Arrays.sort(arr,new Comparator(){ @Override public int compare(Object o1, Object o2){ if(o1 instanceof Goods && o2 instanceof Goods){ Goods g1 = (Goods) o1; Goods g2 = (Goods) o2; if(g1.getName().equals(g2.getName())){ return -Double.compare(g1.getPrice(),g2.getPrice()); }else{ return g1.getName().compareTo(g2.getName()); } } throw new RuntimeException("输入的数据类型不一致"); } }); //[Goods{name='Apple', price=2.9}, Goods{name='Banana', price=3.5}, Goods{name='Purple', price=2.9}, Goods{name='Purple', price=2.2}] System.out.println(Arrays.toString(arr)); }
(4.3)说明
- Java中的对象,正常情况下,只能进行比较: == 或 !=。不能使用 > 或 < 。
- 如果需要对多个对象进行排序,需要比较对象大小。可以使用两个接口中的任何一个: Comparable 或 Comparator。
- Comparable接口的方式一旦确定,类的对象在任何位置都可以比较大小。Comparator接口属于临时性比较。
(5)System类
- System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
- 由于该类的构造器是private的,所以无法创建该类的对象,无法实例化。其内部的成员变量和成员方法都是static的。
- 成员变量: 三个:in标准输入流(键盘输入)、out标准输出流(显示器)、err标准错误输出流(显示器)
- 成员方法
- native long currentTimeMillis():返回当前计算机时间,与GMT时间1970-01-01 00:00:00所差的毫秒数。
- void exit(int status):退出程序。0代表正常退出,非零代表异常退出。使用该方法在图形界面编程中实现程序的退出功能等。
- void gc(): 请求系统进行垃圾回收。是否立刻回收,取决于系统中垃圾回收算法的实现及系统执行时的情况。
- String getProperty(String key): 获取系统中属性名为key的属性对应的值。
- java.version / java.home / os.name / os.version / user.name / user.home / user.dir
(6)Math类
java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型。
- abs: 绝对值
- acos,asin,atan,cos,sin,tan: 三角函数
- sqrt: 平方根
- pow(double a, double b): a的b次幂
- log: 自然对数
- max(double a, double b):
- min(double a, double b):
- random(): 返回0.0 到1.0的随机数
- long round(double a): double型数据a 转换为long型(四舍五入)
- toDegress(double angrad): 弧度 -> 角度
- toRadians(double angras): 角度 -> 弧度
(7)BigDecimal与BigInteger
(7.1)BigInteger类
- Integer类作为int的包装类,能存储的最大整型值为2^31-1, Long类也是有限的,最大为2^63-1。再大就无能为力了。
- java.math包的BigInteger可以表示不可变的任意精度的整数。BigInteger提供所有Java的基本整数操作符的对应物,并提供java.lang.Math的所有相关方法。
- BigInteger还提供了以下运算: 模算术、GCD计算、质数测试、素数生成、位操作以及其他操作。
- 构造器: BigInteger(String val): 根据字符串构建BigInteger对象
@Test public void test7(){ BigInteger bi = new BigInteger("12131321111111111111111113211321321321312"); System.out.println(bi); //12131321111111111111111113211321321321312 }
(7.2)BigDecimal类
- 一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
- BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
- 构造器: public BigDecimal(String val) / public BigDecimal(double 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)
@Test public void test5(){ BigDecimal decimal1 = new BigDecimal("22.22"); BigDecimal decimal2 = new BigDecimal("11.12"); System.out.println(decimal1.add(decimal2)); //33.34 System.out.println(decimal1.subtract(decimal2)); //11.10 System.out.println(decimal1.multiply(decimal2)); //247.0864 System.out.println(decimal1.divide(decimal2,2,2)); //2.00 }
使用Double进行加减乘除计算
@Test public void test6(){ Double double1 = new Double("22.22"); Double double2 = new Double("11.12"); System.out.println(double1 + double2); //33.339999999999996 System.out.println(double1 - double2); //11.1 System.out.println(double1 * double2); //247.08639999999997 System.out.println(double1 / double2); //1.9982014388489209 }
BigDecimal divide() 保留小数位数
@Test public void test7(){ BigDecimal bd = new BigDecimal("12435.351"); BigDecimal bd2 = new BigDecimal("11"); System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP)); //1130.486 System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP)); //1130.486454545454545 }
divide 报错
System.out.println(bd.divide(bd2));Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.at java.math.BigDecimal.divide(BigDecimal.java:1693)at Test03.main(Test03.java:49)