1、大数字操作类:BigInteger、BigDecimal
如果说现在有两个非常大的数字(超过了double范围)要进行数学的加法计算,你该怎么做?可以使用字符串保存数字,而后按照每个字符进行手工的处理数学计算。但是这样的复杂度非常的高,为此,在Java里面专门提供了一个java.math包,此包之中提供有两个大数字操作类:BigInteger(大整数操作类)、BigDecimal(大小数操作类)。
1、 大整数操作类:BigInteger
BigInteger是Number的子类,但是在使用的时候肯定不用转为Number类型,在BigInteger类之中定义的构造方法:public BigInteger(String val),因为数据量一大,肯定使用String表示;
范例:完成四则运算
package cn.mldn.demo;
import java.math.BigInteger;
public class TestDemo {
public static void main(String[] args)throws Exception {
BigInteger bigA = new BigInteger("4238903289023809238097890") ;
BigInteger bigB = new BigInteger("98234789234") ;
System.out.println(bigA.add(bigB));
System.out.println(bigA.subtract(bigB));
System.out.println(bigA.multiply(bigB));
System.out.println(bigA.divide(bigB));
BigInteger result [] = bigA.divideAndRemainder(bigB) ;
System.out.println("商:" + result[0] + "、余数:" + result[1]);
System.out.println(bigA.pow(Integer.MAX_VALUE));
}
}
以上只是针对于BigInteger类做了一个演示,但是这样的代码意义不大,而且也没使用的环境,如果你在工作之中,如果真遇见了数学问题,一定要去找数学公式第三方开发包。
2、 大小操作类:BigDecimal
此类的操作与BigInteger类基本是相同的,也提供有基本的数学计算,但是与这些数学计算相比,BigDecimal类有一个非常重要的功能。
Math类之中的round()方法进行四舍五入操作过程之中,采用的是所有小数点全部进位,不能保留小数位,但是很多时候这样的做法是不可取,例如:如果某家公司的年收入是按照亿计算,今年收获了5.321亿美金,按照Math.round()结果就成了5亿,所以Math.round()是一个不可能使用的操作,这个时候只能够利用BigDecimal类完成。
在BigDecimal类里面提供有一个除法操作:public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
· 第一个参数:被除数,此处也应该是BigDecimal类型;
· 第二个参数:保留的小数位数;
· 第三个参数:进位模式(public static final int ROUND_HALF_UP)。
范例:实现准确的四舍五入操作
package cn.mldn.demo;
import java.math.BigDecimal;
class MyMath {
public static double round(double num,int scale) {
BigDecimal bigNum = new BigDecimal(num) ; // 只有变为BigDecimal才可以调用divide()方法
BigDecimal result = bigNum.divide(new BigDecimal(1), scale,
BigDecimal.ROUND_HALF_UP);
return result.doubleValue() ;
}
}
public class TestDemo {
public static void main(String[] args)throws Exception {
System.out.println(MyMath.round(7809.652198, 2));
System.out.println(MyMath.round(7809.652198, 1));
System.out.println(MyMath.round(-13.5, 0));
}
}
此代码是在工作上使用最多的四舍五入操作模式,如果有需要代码直接使用。
2、Arrays类
“java.util.Arrays.sort()”是一个数组排序操作,实际上这一个操作就是调用了java.util包中Arrays类的sort()方法完成的,而Arrays是一个数组操作的工具类(数组一般使用较少,所以此工具类意义不大)。
范例:使用Arrays类
package cn.mldn.demo;
import java.util.Arrays;
public class TestDemo {
public static void main(String[] args)throws Exception {
int dataA[] =new int[] { 1, 2, 3 };
int dataB[] =new int[] { 1, 2, 3 };
System.out.println(Arrays.equals(dataA, dataB));
Arrays.fill(dataA, 9);
System.out.println(Arrays.toString(dataA));
}
}
随着数组的使用减少,此类的操作也越来越少。
3、比较器
在之前接触过了Arrays类,那么下面来观察在Arrays类之中存在的一个方法:
· 对象数组排序:public static void sort(Object[] a);
范例:实现排序
package cn.mldn.demo;
import java.util.Arrays;
class Person {
private String name ;
private int age ;
public Person(String name,int age) {
this.name = name ;
this.age = age ;
}
public String toString() {
return "姓名:" +this.name + ",年龄:" +this.age ;
}
}
public class TestDemo {
public static void main(String[] args)throws Exception {
Person per[] = new Person[] { new Person("张三", 20),
new Person("李四", 18),new Person("王五", 25) };
Arrays.sort(per); // 排序
for (int x = 0; x < per.length; x++) {
System.out.println(per[x]);
}
}
}
Exception in thread "main"java.lang.ClassCastException: cn.mldn.demo.Person cannot be cast to java.lang.Comparable
现在发现此时需要让Person类实现Comparable接口,而这就是一个比较器。
3.1、Comparable接口(核心)
java.lang.Comparable接口是一个最为常用的比较器,那么此接口定义如下:
public interface Comparable {
public int compareTo(T o) ;
}
在Comparable接口之中发现只有一个compareTo()方法,而此方法可以返回三种类型的数据:-1(小)、0(等)、1(大)。
在之前学习String类的时候也学习过compareTo()方法,当时的方法是可以进行大小判断的。
范例:使用比较器
package cn.mldn.demo;
import java.util.Arrays;
class Personimplements Comparable {
private String name ;
private int age ;
public Person(String name,int age) {
this.name = name ;
this.age = age ;
}
public String toString() {
return "姓名:" +this.name + ",年龄:" +this.age ;
}
@Override
public int compareTo(Person o) {
if (this.age > o.age) {
return 1 ;
} else if (this.age < o.age) {
return -1 ;
}
return 0;
}
}
public class TestDemo {
public static void main(String[] args)throws Exception {
Person per[] = new Person[] { new Person("张三", 20),
new Person("李四", 18),new Person("王五", 25) };
Arrays.sort(per); // 排序
for (int x = 0; x < per.length; x++) {
System.out.println(per[x]);
}
}
}
以后只要是一组对象的大小比较一定使用Comparable接口。
3.2、Binary Tree(了解)
既然已经知道了对象之间的大小比较操作,那么就可以利用此概念实现二叉树开发,二叉树的基本原则如下:
· 一个节点下可以保存两个节点,分别称为左子树和右子树;
· 取第一个数据作为根节点,比根节点小的数据要放在左子树上,比根节点大的数据要放在右子树上;
· 在进行输出的时候按照中序遍历(左-中-右)进行数据的取出。
范例:下面将利用Comparable实现二叉树操作
· 大小关系利用Comparable接口的compareTo()方法实现。
package cn.mldn.test;
class Personimplements Comparable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "姓名:" +this.name + ",年龄:" +this.age;
}
@Override
public int compareTo(Person o) {
if (this.age > o.age) {
return 1;
} else if (this.age < o.age) {
return -1;
}
return 0;
}
}
@SuppressWarnings("rawtypes")
class BinaryTree {
private class Node { // 一定要存在节点类
private Comparable data; // 必须排序的是Comparable接口对象
private Node left; // 左子树
private Node right; // 右子树
public Node(Comparable data) {
this.data = data;
}
@SuppressWarnings("unchecked")
public void addNode(Node newNode) {
if (this.data.compareTo(newNode.data) > 0) {
if (this.left ==null) {
this.left = newNode ;
}else {
this.left.addNode(newNode);
}
} else {
if (this.right ==null) {
this.right = newNode ;
}else {
this.right.addNode(newNode);
}
}
}
public void toArrayNode() {
if (this.left !=null) { // 有左子树
this.left.toArrayNode();
}
BinaryTree.this.retData[BinaryTree.this.foot++] =this.data;
if (this.right !=null) {
this.right.toArrayNode();
}
}
}
// ======================================
private Node root; // 根节点
private int count ; // 统计对象的保存个数
private int foot ; // 操作脚标
private Object [] retData ;
public void add(Comparable data) {
if (data ==null) {
return;
}
Node newNode = new Node(data); // 将新的数据变为一个节点
if (this.root ==null) { // 根节点没有数据
this.root = newNode ; // 新的节点将作为根节点存在
} else { // 要保存在合适的节点中
this.root.addNode(newNode);
}
this.count ++ ; // 保存个数加一
}
public Object[] toArray() {
if (this.root ==null) {
return null ;
}
this.foot = 0 ;
this.retData =new Object [this.count] ; // 以保存大小开辟数组
this.root.toArrayNode();
return this.retData ;
}
}
public class BinaryTreeDemo {
public static void main(String[] args) {
BinaryTree bt = new BinaryTree() ;
bt.add(new Person("张三",20));
bt.add(new Person("李四",18));
bt.add(new Person("王五",25));
Object [] data = bt.toArray() ;
for (int x = 0; x < data.length; x++) {
System.out.println(data[x]);
}
}
}
如果日后笔试之中有人问:请写个二叉树,李老师讲过,我不会。
3.3、挽救的比较器:Comparator(了解)
在工作之中如果使用到比较器,肯定首选的是Comparable,但是Comparable有一个特点,它必须在一个类定义的时候就实现好接口,可是如果有这样一种情况,一个类已经开发完成了,并且此类不允许再做出任何修改,此类在先期设计的时候没有考虑对象数组的排序问题,后期又提出了此问题。但是代码已经不能变更,那么这个时候如何排序呢?
范例:开发好的类
class Person {
private String name ;
private int age ;
public Person(String name,int age) {
this.name = name ;
this.age = age ;
}
public String toString() {
return "姓名:" +this.name + ",年龄:" +this.age ;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Person类已经开发完成,并且打包后交给客户使用了,但是后来需要进行对象数组排序,那么这个时候由于Person类无法修改了,那么只能够采用另外一种比较器:java.util.Comparator接口,此接口定义如下。
public interface Comparator {
public int compare(T o1, T o2) ;
public boolean equals(Object obj) ;
}
范例:定义专门的比较规则
class PersonComparatorimplements Comparator {
@Override
public int compare(Person o1, Person o2) {
if (o1.getAge() > o2.getAge()) {
return -1 ;
} else if (o1.getAge() < o2.getAge()) {
return 1 ;
}
return 0;
}
}
此类只能够为Person类服务。随后如果要排序的时候在Arrays类有如下一个方法:
· 排序:public static void sort(T[] a, Comparator
4、正则表达式
离散数学是正则的理论基础,有想弄明白的,可以去研究一下。正则是一种简化的验证手段,例如,现在完成这样的一个代码。
范例:要求判断一个字符串是否由数字组成
· 思路:将字符串变为字符数组,而后每个字符进行依次判断。
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String num = "12a3" ;
System.out.println(isNumber(num));
}
public static boolean isNumber(String str) {
char [] data = str.toCharArray() ;
for (int x = 0; x < data.length; x++) {
if (data[x] > '9' || data[x] < '0') {
return false ;
}
}
return true ;
}
}
但是这样一个非常简单或者说是简单到极点的验证写出了八行代码,如果再复杂一点呢?代码量会更多。
范例:利用正则操作
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String num = "123" ;
System.out.println(num.matches("\\d+"));
}
}
发现如果在验证操作上使用正则符号进行匹配,则代码量可以非常少,而“"\\d+"”就是正则表达式。
正则表达式最早是在Linux下发展起来的,在JDK 1.4之前,如果需要使用到正则那么要通过apache下载正则的应用包。而从JDK 1.4开始,Java正式支持了正则的开发,同时给出了一个java.util.regex开发包,提供正则的操作类。
但是需要注意的是,在java.util.regex包里面只提供有两个核心类:
· java.util.regex.Pattern:正则标记编译类;
· java.util.regex.Matcher:正则匹配操作;
而在开发之中很少去直接使用以上的两个类,一般都使用String类完成,因为从JDK 1.4之后开始,String类之中多了正则的支持,同时提供了以下支持正则的开发方法。
No.
方法名称
类型
描述
1
public boolean matches(String regex)
普通
正则验证
2
public String replaceAll(String regex, String replacement)
普通
全部替换
3
public String replaceFirst(String regex, String replacement)
普通
替换首个
4
public String[] split(String regex)
普通
全拆分
5
public String[] split(String regex, int limit)
普通
部分拆分
下面的讲解以String类之中几个操作方法为主。
4.1、正则符号(背,死了都要会)
如果要操作正则,那么必须使用一系列的正则匹配符号,而所有的正则匹配符号都在java.util.regex.Pattern类提供。
1、 表示单个字符(每出现一个只表示一位)
· x:表示只能由x组成;
· \\:表示转义字符“\”;
· \t:匹配“tab”键;
· \n:匹配换行;
2、 表示字符的选用范围(每出现一个只表示一位)
· [abc]:表示可能是a、b、c中的任意一个;
· [^abc]:表示不是a、b、c中的任意一个;
· [a-zA-Z]:表示任意的一位字母,可能是大写或小写;
· [0-9]:表示任意的一位数字;
3、 简化表达式(每出现一个只表示一位)
· .:表示任意的一位字符;
· \d:表示是一位数字,相当于“[0-9]”;
· \D:表示不是一位数字, 相当于“[^0-9]”;
· \s:表示是任意的一位空格;
· \S:表示不是任意的一位空格;
· \w:表示是大小写字母、数字、_中的任意一位,相当于“[a-zA-Z0-9_]”;
· \W:表示不使大小写字母、数字、_中的任意一位,相当于“[^a-zA-Z0-9_]”;
4、 边界匹配
· ^:写在正则之前,表示正则开始;
· $:写在正则最后,表示正则结束;
5、 数量表示:如果没有数量,每一个出现的标记只能表示一位
· 正则?:表示此正则规范只能够出现0次或1次;
· 正则*:表示此正则出现0次、1次或多次;
· 正则+:表示此正则出现1次或多次;
· 正则{n}:表示此正则出现正好n次;
· 正则{n,}:表示此正则出现n次以上;
· 正则{n,m}:表示此正则出现n ~ m次;
6、 逻辑操作符
· 正则X正则Y:表示正则X判断后执行正则Y;
· 正则X|正则Y:表示两个正则二选一;
· (正则):包含多个正则,成为一组;
4.2、通过String类来操作正则
正则的所有操作方法都通过String类完成,所以下面将通过一些代码,通过String来操作正则。
范例:字符串替换
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String num = "fajkljkl32890*()jlk3809F*)(&w(*r&)(*4379RF8SD09" ;
String regex = "[^a-zA-Z]" ;
System.out.println(num.replaceAll(regex, ""));
}
}
范例:字符串拆分
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String num = "a1b22c333d44444e5555555f66666666g" ;
String regex = "\\d+" ;
String result [] = num.split(regex) ;
for (int x = 0; x < result.length; x++) {
System.out.println(result[x]);
}
}
}
范例:现在用户名由字母、数字、_所组成,要求其范围在6~15位
· 正则:[a-zA-Z0-9_] = \w;
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String num = "hello123" ;
String regex = "\\w{6,15}" ;
System.out.println(num.matches(regex));
}
}
范例:现在某个学校的学生成绩要求按照“姓名:年龄:生日:成绩”,那么这样的数据可以出现多条,多条纪录之间使用“|”分隔,例如“SMITH:20:1990-09-15:90.9|ALLEN:19:1991-11-11:89.6|TONY:21:1989-07-28:100”。
那么下面首先要进行问题的拆分,因为这个验证之中包含有许多的小规则:
· 规则一:验证姓名,不设置长度限制(一位或多位,使用+表示);
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "SMITH" ;
String regex = "[a-zA-Z]+" ;
System.out.println(str.matches(regex));
}
}
· 规则二:验证年龄,年龄是一个数字,长度范围1 ~ 3位;
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "19" ;
String regex = "\\d{1,3}" ;
System.out.println(str.matches(regex));
}
}
· 规则三:验证生日,生日是数字组合
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "1998-08-01" ;
String regex = "\\d{4}-\\d{2}-\\d{2}" ;
System.out.println(str.matches(regex));
}
}
· 规则四:验证小数,成绩最多3位,小数位最多2位。
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "98.12" ;
String regex = "\\d{1,3}(\\.\\d{1,2})?" ;
System.out.println(str.matches(regex));
}
}
· 组合验证规则:
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "SMITH:20:1990-09-15:90.9" ;
String regex= "[a-zA-Z]+:\\d{1,3}:\\d{4}-\\d{2}-\\d{2}:\\d{1,3}(\\.\\d{1,2})?" ;
System.out.println(str.matches(regex));
}
}
· 满足于多组信息的操作;
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "SMITH:20:1990-09-15:90.9|ALLEN:19:1991-11-11:89.6|TONY:21:1989-07-28:100" ;
String regex = "([a-zA-Z]+:\\d{1,3}:"
+ "\\d{4}-\\d{2}-\\d{2}:"
+ "\\d{1,3}(\\.\\d{1,2})?\\|?)+" ;
System.out.println(str.matches(regex));
}
}
范例:验证email地址,email地址的验证规则如下:
· 用户名只能够以字母、数字、_、.组成;
· 用户名只能够以字母开头;
· 用户名的长度要求在6~20位之间;
· 域名只能是:.com、.cn、.net、.com.cn、.net.cn、.edu、.gov;
package cn.mldn.demo;
public class TestDemo {
public static void main(String[] args)throws Exception {
String str = "mldn.hello123@163.com.cn" ;
String regex = "[a-zA-Z][a-zA-Z0-9_\\.]{5,19}"
+ "@[a-zA-Z-0-9]+\\."
+ "(com|cn|net|gov|edu|com\\.cn|net\\.cn)" ;
System.out.println(str.matches(regex));
}
}
虽然从感觉上看这些符号组合比较麻烦,但是习惯了就好,可是应该知道正则的出现让代码简化了不少,尤其是针对于验证操作。
5、反射机制
我们在正常的使用过程之中只关心类产生对象,而后通过对象调用类之中的方法,可是,除了这种传统的方式外,也可以利用反射操作。
5.1、认识反射
既然有反,那么一定存在有正,正是指的通过类产生对象,而后通过对象执行操作。而反呢?通过对象找到他所在的类的信息。所有的对象都支持反这一操作,因为Object类有一个方法:public final Class
0 0