java类库的基本介绍
与用户互动
运行Java程序的参数
main()方法分析
public
修饰符:Java类由JVM调用,为了让JVM可以自由调用这个main()方法,所以使用public修饰符把这个方法暴露出来static
修饰符:JVM调用这个主方法时,不会先创建该类的对象,然后通过对象来调用该主方法。JVM直接通过该类来调用主方法,因此用static修饰该主方法void
返回值:因为主方法被JVM调用,该方法的返回值将返回给JVM,这没有任何意义,因此main()方法没有返回值
使用Scanner获取键盘输入
Scanner类可以获取键盘输入,是一个基于正则表达式的文本扫描器,可以从文件、输入流、字符串中解析出基本类型值和字符串值
Scanner主要提供以下两个方法来扫描输入:
hasNextXxx()
:是否还有下一个输入项(hasNest()
)nextXxx()
:获取下一个输入项
在默认情况下,Scanner使用空白(包括键盘、Tab空白、回车)作为多个输入项之间的分隔符
Scanner使用useDelimiter(String pattern)作为分隔符设置
Scanner提供以下两个方法逐行读取:
boolean hasNextLine()
:返回输入源中是否还有下一个行String nextLine()
:返回输入源中下一行的字符串
public static void main(String[] args){ // System.in代表标准输入,就是键盘输入 Scanner sc = new Scanner(System.in); // 增加下面一行将只把回车作为分隔符 // sc.useDelimiter("\n"); // 判断是否还有下一个输入项 while(sc.hasNext()){ // 输出输入项 System.out.println("键盘输入的内容是:" + sc.next()); } }
同时Scanner还可以读取文件输入,只需要传入File对象作为参数即可
public static void main(String[] args)throws Exception{ // 将一个File对象作为Scanner的构造器参数,Scanner读取文件内容 Scanner sc = new Scanner(new File("ScannerFileTest.java")); System.out.println("ScannerFileTest.java文件内容如下:"); // 判断是否还有下一行 while(sc.hasNextLine()){ // 输出文件中的下一行 System.out.println(sc.nextLine()); } }
系统相关
System类
System类代表当前Java程序的运行平台,程序不能创建System类的对象,System类提供了一些类变量和类方法,允许直接通过System类来调用这些类变量和类方法。可以获取依稀系统相关信息
public static void main(String[] args) throws Exception{ // 获取系统所有的环境变量 Map<String,String> env = System.getenv(); for (String name : env.keySet()){ System.out.println(name + " ---> " + env.get(name)); } // 获取指定环境变量的值 System.out.println(System.getenv("JAVA_HOME")); // 获取所有的系统属性 Properties props = System.getProperties(); // 将所有系统属性保存到props.txt文件中 props.store(new FileOutputStream("props.txt"), "System Properties"); // 输出特定的系统属性 System.out.println(System.getProperty("os.name")); }
System的计时方法:
currentTimeMillis()
(毫秒)和nanoTime()
(纳秒),相对于1970年System的输入输出:
in
,out
,err
,提供了setInt()
、setOut()
、setErr()
方法System类提供一个
identityHashCode(Object x)
,返回指定对象的精确hash Code值,根据对象地址的到,可以唯一标识一个对象public static void main(String[] args){ // 下面程序中s1和s2是两个不同对象 String s1 = new String("Hello"); String s2 = new String("Hello"); // String重写了hashCode()方法——改为根据字符序列计算hashCode值, // 因为s1和s2的字符序列相同,所以它们的hashCode方法返回值相同 System.out.println(s1.hashCode() + "----" + s2.hashCode()); // s1和s2是不同的字符串对象,所以它们的identityHashCode值不同 System.out.println(System.identityHashCode(s1) + "----" + System.identityHashCode(s2)); String s3 = "Java"; String s4 = "Java"; // s3和s4是相同的字符串对象,所以它们的identityHashCode值相同 System.out.println(System.identityHashCode(s3) + "----" + System.identityHashCode(s4)); }
Runtime类
Runtime类代表Java程序的运行时环境,每个Java程序都有一个与之对应的Runtime实例。应用程序不能创建自己的Runtime实例,但是可以通过
getRuntime()
方法获取与之关联的Runtime对象与System类似,Runtime提供了
gc()
和runFinalization()
,并提供了load(String filename)
和loadLibrary(String libname)
来加载文件和动态链接库Runtime可以访问JVM的相关信息:
public static void main(String[] args){ // 获取Java程序关联的运行时对象 Runtime rt = Runtime.getRuntime(); System.out.println("处理器数量:" + rt.availableProcessors()); System.out.println("空闲内存数:" + rt.freeMemory()); System.out.println("总内存数:" + rt.totalMemory()); System.out.println("可用最大内存数:" + rt.maxMemory()); }
Runtime来可以直接单独启动一个进程来运行操作系统命令
public static void main(String[] args) throws Exception{ Runtime rt = Runtime.getRuntime(); // 运行记事本程序 rt.exec("notepad.exe"); }
常用类
Object类
Object是所有类,数组,枚举类的父类。也就是说Java允许把任何类型的变量赋给Object类型的变量
Object提供了如下几个常用方法:
boolean equals(Object obj)
:判断指定对象与该对象是否相等protected void finalize()
:当系统中没有引用变量引用到该对象时,垃圾回收器调用此方法来清理该对象的资源Class<?> getClass()
:返回该对象的运行时类int hashCode()
:返回该对象的hashCode值String toString()
:返回该对象的字符串表示wait()
,notify()
,notifyAll()
Object还提供了protected修饰的clone()方法,用于得到一个当前对象的副本,而且二者之间完全隔离。实现“自我克隆”的步骤如下:
自定义类实现Coneable接口,此为标记行接口,里面没有定义任何方法
自定义类实现自己的clone()方法
实现clone()方法时通过
super.clone()
;调用Object实现的clone()方法来得到该对象的副本,并返回该副本class Address{ String detail; public Address(String detail){ this.detail = detail; } } // 实现Cloneable接口 class User implements Cloneable{ int age; Address address; public User(int age){ this.age = age; address = new Address("广州天河"); } // 通过调用super.clone()来实现clone()方法 public User clone() throws CloneNotSupportedException{ return (User)super.clone(); } } public class CloneTest{ public static void main(String[] args) throws CloneNotSupportedException{ User u1 = new User(29); // clone得到u1对象的副本。 User u2 = u1.clone(); // 判断u1、u2是否相同 System.out.println(u1 == u2); //false // 判断u1、u2的address是否相同 System.out.println(u1.address == u2.address); //true } }
Java7新增的Object类
若不确定一个对象是否为null就用
toString()
则可能引起空指针异常,而Object提供的toString(Object o)
则不会,若为空,则返回null
字符串// 定义一个obj变量,它的默认值是null static ObjectsTest obj; public static void main(String[] args) { // 输出一个null对象的hashCode值,输出0 System.out.println(Objects.hashCode(obj)); // 输出一个null对象的toString,输出null System.out.println(Objects.toString(obj)); // 要求obj不能为null,如果obj为null则引发异常 System.out.println(Objects.requireNonNull(obj , "obj参数不能是null!")); }
String、StringBuffer和StringBuilder类
字符串就是一连串的字符序列
String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象的字符序列是不可改变的,直到这个对象销毁。
StringBuffer对象代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的
append()
、insert()
、reverse()
、setCharAt()
、setLength()
等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成最终想要的字符串,就可以调用它的toString()
方法将其转化成一个String对象StringBuilder从JDK1.5开始使用,与StringBuffer类似,不同的是StringBuffer是线程安全的,而StringBuilder没有线程安全,性能略高。通常考虑StringBuilder类
String类提供的构造器
String()
:创建一个包含0个字符串序列的String对象(并不是返回null)String(byte[] bytes , Charset charset)
:使用指定的字符集将指定的byte[]数组解码成一个新的String对象String(byte[] bytes,int offset,int length)
:使用平台的默认字符集将指定的byte[]数组从offset开始,长度为length的子数组解码成一个新的String对象String(byte[] bytes,int offset,int length,String charsetName)
:使用指定的字符集将指定的byte[]数组从offset开始,长度为length的子数组解码成一个新的String对象String(byte[] bytes , String charsetName)
:使用指定的字符集将指定的byte[]数组解码成一个新的String对象String(char[] value)
:将字符数组转换成字符串String(char[] value,int offset,int count)
:将指定的字符数组从offset开始、长度为count的字符元素连缀成字符串String(String original)
:根据字符串直接量来创建一个String对象。即新创建的String对象是该参数字符串的副本String(StringBuffer buffer)
:根据StringBuffer对象来创建对应的String对象String(StringBuilder builder)
:根据StringBuilder对象来创建对应的String对象
String类提供的字符串操作方法
char charAt(int index)
:获取字符串中指定位置的字符int compareTo(String anotherString)
:比较两个字符串的大小(大小差)String concat(String str)
:将该String对象与str连接在一起boolean contentEquals(StringBuffer sb)
:将该String对象与StringBuffer对象sb进行比较,当他们的字符序列相同时返回truestatic String copyValueOf(char[] data)
:将字符数组连缀成字符串static String copyValueOf(char[] data,int offset,int count)
:将char数组的子元素中的元素连缀成字符串boolean endsWith(String suffix)
:返回该String对象是否以suffix结尾boolean equals(Object anObject)
:将该字符串与指定对象对比,若二者包含的字符序列相等,则返回trueboolean equalsIgnoreCase(String str)
:忽略大小写的比较byte[] getByte()
:将该String对象转化成byte数组void getChars(int srcBegin,int srcEnd,char[] dst,int dstBegin)
:该方法将字符串中从srcBegin开始到srcEnd结束的字符复制到dst字符数组中int indexOf(int ch)
:找出ch字符在该字符串中第一次出现的位置int indexOf(int ch,int fromIndex)
:找出ch字符串在该字符串中从fromIndex开始后第一次出现的位置。int indexOf(String str)
:找出str子字符串在该字符串中第一次出现的位置int indexOf(String str,int fromIndex)
:找出str子字符串在该字符串中从fromIndex开始后第一次出现的位置int lastIndexOf(int ch)
:找出ch字符在该字符串中最后一次出现的位置int lastIndexOf(int ch,int fromIndex)
:找出ch字符串在该字符串中从fromIndex开始后最后一次出现的位置。int lastIndexOf(String str)
:找出str子字符串在该字符串中最后一次出现的位置int lastIndexOf(String str,int fromIndex)
:找出str子字符串在该字符串中从fromIndex开始后最后一次出现的位置int length()
:返回当前字符串的长度String replace(char oldChar,char newChar)
:将字符串中的第一个oldChar替换成newCharboolean startWith(String prefix)
:该Strng对象是否以prefix开始boolean startWith(String prefix,int toffset)
:该String对象从toffset位置算起,是否以prefix开始String substring(int beginIndex)
:获取从beginIndex位置开始到结束的字串String substring(int beginIndex,int endIndex)
:获取从beginIndex开始到endIndex位置的字串char[] toCharArray()
:将该String对象转化成char数组String toLowerCase()
:将字符串转化成小写String toUpperCase()
:将字符串转化成小写static String valueOf(X x)
:一系列用于将基本数据类型转化成String对象的方法
StringBuffer、StringBuilder有两个属性:
length
和capacity
。前者表示其包含的字符序列的长度。可用length()
、setLength()
访问修改。后者表示其容量,一般不用关心public static void main(String[] args){ StringBuilder sb = new StringBuilder(); // 追加字符串 sb.append("java");//sb = "java" // 插入 sb.insert(0 , "hello "); // sb="hello java" // 替换 sb.replace(5, 6, ","); // sb="hello, java" // 删除 sb.delete(5, 6); // sb="hellojava" System.out.println(sb); // 反转 sb.reverse(); // sb="avajolleh" System.out.println(sb); System.out.println(sb.length()); // 输出9 System.out.println(sb.capacity()); // 输出16 // 改变StringBuilder的长度,将只保留前面部分 sb.setLength(5); // sb="avajo" System.out.println(sb); }
Math类
Java提供Math工具完成复杂的运算,Math是一个工具类,其构造器修饰符为private,因此无法创建对象。提供了大量静态方法和
PI
、E
public static void main(String[] args){ /---------下面是三角运算---------/ // 将弧度转换角度 System.out.println("Math.toDegrees(1.57):" + Math.toDegrees(1.57)); // 将角度转换为弧度 System.out.println("Math.toRadians(90):" + Math.toRadians(90)); // 计算反余弦,返回的角度范围在 0.0 到 pi 之间。 System.out.println("Math.acos(1.2):" + Math.acos(1.2)); // 计算反正弦;返回的角度范围在 -pi/2 到 pi/2 之间。 System.out.println("Math.asin(0.8):" + Math.asin(0.8)); // 计算反正切;返回的角度范围在 -pi/2 到 pi/2 之间。 System.out.println("Math.atan(2.3):" + Math.atan(2.3)); // 计算三角余弦。 System.out.println("Math.cos(1.57):" + Math.cos(1.57)); // 计算值的双曲余弦。 System.out.println("Math.cosh(1.2 ):" + Math.cosh(1.2 )); // 计算正弦 System.out.println("Math.sin(1.57 ):" + Math.sin(1.57 )); // 计算双曲正弦 System.out.println("Math.sinh(1.2 ):" + Math.sinh(1.2 )); // 计算三角正切 System.out.println("Math.tan(0.8 ):" + Math.tan(0.8 )); // 计算双曲正切 System.out.println("Math.tanh(2.1 ):" + Math.tanh(2.1 )); // 将矩形坐标 (x, y) 转换成极坐标 (r, thet)); System.out.println("Math.atan2(0.1, 0.2):" + Math.atan2(0.1, 0.2)); /---------下面是取整运算---------/ // 取整,返回小于目标数的最大整数。 System.out.println("Math.floor(-1.2 ):" + Math.floor(-1.2 )); // 取整,返回大于目标数的最小整数。 System.out.println("Math.ceil(1.2):" + Math.ceil(1.2)); // 四舍五入取整 System.out.println("Math.round(2.3 ):" + Math.round(2.3 )); /---------下面是乘方、开方、指数运算---------/ // 计算平方根。 System.out.println("Math.sqrt(2.3 ):" + Math.sqrt(2.3 )); // 计算立方根。 System.out.println("Math.cbrt(9):" + Math.cbrt(9)); // 返回欧拉数 e 的n次幂。 System.out.println("Math.exp(2):" + Math.exp(2)); // 返回 sqrt(x2 +y2) System.out.println("Math.hypot(4 , 4):" + Math.hypot(4 , 4)); // 按照 IEEE 754 标准的规定,对两个参数进行余数运算。 System.out.println("Math.IEEEremainder(5 , 2):" + Math.IEEEremainder(5 , 2)); // 计算乘方 System.out.println("Math.pow(3, 2):" + Math.pow(3, 2)); // 计算自然对数 System.out.println("Math.log(12):" + Math.log(12)); // 计算底数为 10 的对数。 System.out.println("Math.log10(9):" + Math.log10(9)); // 返回参数与 1 之和的自然对数。 System.out.println("Math.log1p(9):" + Math.log1p(9)); /---------下面是符号相关的运算---------/ // 计算绝对值。 System.out.println("Math.abs(-4.5):" + Math.abs(-4.5)); // 符号赋值,返回带有第二个浮点数符号的第一个浮点参数。 System.out.println("Math.copySign(1.2, -1.0):" + Math.copySign(1.2, -1.0)); // 符号函数;如果参数为 0,则返回 0;如果参数大于 0, // 则返回 1.0;如果参数小于 0,则返回 -1.0。 System.out.println("Math.signum(2.3):" + Math.signum(2.3)); /---------下面是大小相关的运算---------/ // 找出最大值 System.out.println("Math.max(2.3 , 4.5):" + Math.max(2.3 , 4.5)); // 计算最小值 System.out.println("Math.min(1.2 , 3.4):" + Math.min(1.2 , 3.4)); // 返回第一个参数和第二个参数之间与第一个参数相邻的浮点数。 System.out.println("Math.nextAfter(1.2, 1.0):" + Math.nextAfter(1.2, 1.0)); // 返回比目标数略大的浮点数 System.out.println("Math.nextUp(1.2 ):" + Math.nextUp(1.2 )); // 返回一个伪随机数,该值大于等于 0.0 且小于 1.0。 System.out.println("Math.random():" + Math.random()); }
Java7的ThreadLocalRandom与Random
Random类专门用于生成一个伪随机数,拥有两个构造器:一个构造器使用默认种子(以当前时间作为种子),另一个构造器显式传入一个long型整数的种子
ThreadLocalRandom类是Java7新增的一个类,是Random的增强版。在并发访问的环境下,使用
ThreadLocalRandom
来代替Random可以减少线程资源竞争,最终保证系统具有更好的线程安全性。与Random用法类似。提供了一个静态的current()
方法获取ThreadLocalRandom
对象,获取到该对象之后即可调用各种nextXxx()
方法来获取伪随机数ThreadLocalRandom
与Random都比Math的random()
方法提供了更多的方式生成各种伪随机数,可以生成浮点类型的伪随机数,也可以生成整数类型的伪随机数,还可以指定生成随机数的范围public static void main(String[] args){ Random rand = new Random(); System.out.println("rand.nextBoolean():" + rand.nextBoolean()); byte[] buffer = new byte[16]; rand.nextBytes(buffer); System.out.println(Arrays.toString(buffer)); // 生成0.0
1.0之间的伪随机double数 System.out.println("rand.nextDouble():" + rand.nextDouble()); // 生成0.01.0之间的伪随机float数 System.out.println("rand.nextFloat():" + rand.nextFloat()); // 生成平均值是 0.0,标准差是 1.0的伪高斯数 System.out.println("rand.nextGaussian():" + rand.nextGaussian()); // 生成一个处于int整数取值范围的伪随机整数 System.out.println("rand.nextInt():" + rand.nextInt()); // 生成0~26之间的伪随机整数 System.out.println("rand.nextInt(26):" + rand.nextInt(26)); // 生成一个处于long整数取值范围的伪随机整数 System.out.println("rand.nextLong():" + rand.nextLong()); }一般使用时间作为种子
Random rand = new Random(System.currentTimeMillis());
ThreadLocalRandom用法实例:
ThreadLocalRandom rand = ThreadLocalRandom.current(); //生成一4
20之间的伪随机数 int val1 = rand.nextInt(4,20); //生成一个2.010.0的伪随机数 int val2 = rand.nextDouble(2.0,10.0);
BigDecimal类
浮点数的精确计算,使用String而不是double
public static void main(String[] args){ BigDecimal f1 = new BigDecimal("0.05"); BigDecimal f2 = BigDecimal.valueOf(0.01); BigDecimal f3 = new BigDecimal(0.05); System.out.println("使用String作为BigDecimal构造器参数:"); System.out.println("0.05 + 0.01 = " + f1.add(f2)); System.out.println("0.05 - 0.01 = " + f1.subtract(f2)); System.out.println("0.05 * 0.01 = " + f1.multiply(f2)); System.out.println("0.05 / 0.01 = " + f1.divide(f2)); System.out.println("使用double作为BigDecimal构造器参数:"); System.out.println("0.05 + 0.01 = " + f3.add(f2)); System.out.println("0.05 - 0.01 = " + f3.subtract(f2)); System.out.println("0.05 * 0.01 = " + f3.multiply(f2)); System.out.println("0.05 / 0.01 = " + f3.divide(f2)); }
public class Arith{ // 默认除法运算精度 private static final int DEF_DIV_SCALE = 10; // 构造器私有,让这个类不能实例化 private Arith() {} // 提供精确的加法运算。 public static double add(double v1,double v2){ BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.add(b2).doubleValue(); } // 提供精确的减法运算。 public static double sub(double v1,double v2){ BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.subtract(b2).doubleValue(); } // 提供精确的乘法运算。 public static double mul(double v1,double v2){ BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.multiply(b2).doubleValue(); } // 提供(相对)精确的除法运算,当发生除不尽的情况时. // 精确到小数点以后10位的数字四舍五入。 public static double div(double v1,double v2){ BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.divide(b2 , DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue(); } public static void main(String[] args){ System.out.println("0.05 + 0.01 = " + Arith.add(0.05 , 0.01)); System.out.println("1.0 - 0.42 = " + Arith.sub(1.0 , 0.42)); System.out.println("4.015 * 100 = " + Arith.mul(4.015 , 100)); System.out.println("123.3 / 100 = " + Arith.div(123.3 , 100)); } }
Java8的日期、时间表
Date类(尽量少用)
Java提供了Date类来处理时间、日期,Date既包含日期也包含时间
Date提供了了六个构造器,其中四个已经不再推荐使用,剩下两个如下:
Date()
:生成一个代表当前日期时间的Date对象,改构造器底层调用System.currentTimeMillis()
获得long整数作为日期参数Date(long date)
:根据指定的long型整数来生成一个Date对象
Date的大部分方法也已经不再推荐使用
boolean after(Date when)
:测试该日期是否在指定日期when之后boolean before(Date when)
:测试该日期是否在指定日期when之前long getTime()
:返回该时间对应的long型整数void setTime(long time)
:设置该Date对象的时间public static void main(String[] args){ Date d1 = new Date(); // 获取当前时间之后100ms的时间 Date d2 = new Date(System.currentTimeMillis() + 100); System.out.println(d2); System.out.println(d1.compareTo(d2)); System.out.println(d1.before(d2)); }
Calendar类
为了弥补Date设计上的缺陷,Java提供了Calendar类
Calendar是一个抽象类,所以不能用构造器来创建Calendar对象。但是提供了几个静态
getInstance()
方法来获取Calendar对象,这些方法根据TimeZone、Locale类来获取特定的Calender。如果不指定TimeZone、Locale,则使用默认的TimeZone、Locale来创建Calendar//创建一个默认的Calendar对象 Calendar calendar = Calendar.getInstance(); //从Calendar对象中取出Date对象 Date date = calendar.getTime(); //通过Date对象获得对应的Calendar对象 //因为Calendar/GregorianCalendar没有构造器方法可以接收Date对象 //所以必须先获得一个Calendar实例,然后再调用其setTime()方法 Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date);
Calendar提供了大量访问、修改日期时间的方法:
void add(int field,int amount)
:根据日历的规则,为给定的日历字段添加或减去指定的时间量int get(int field)
:返回指定日历字段的值int getActualMaximum(int field)
:返回指定日历字段可能拥有的最大值int getActualMinimum(int field)
:返回指定日历字段可能拥有的最小值void roll(int field,int amount)
:与add()方法类似,区别在于加上amount后超过了该字段所能表示的最大范围时,也不会向上一个字段进位void set(int filed,int value)
:将给定的日历字段设置为给定值void set(int filed,int month,int date)
:设置Calenser对象的年、月、日三个字段的值void set(int year,int month,int date,int hourOfDay,int minute,int second)
:设置Calendar对象的年、月、日、时、分、秒6个字段的值
public static void main(String[] args){ Calendar c = Calendar.getInstance(); // 取出年 System.out.println(c.get(YEAR)); // 取出月份 System.out.println(c.get(MONTH)); // 取出日 System.out.println(c.get(DATE)); // 分别设置年、月、日、小时、分钟、秒 c.set(2003 , 10 , 23 , 12, 32, 23); //2003-11-23 12:32:23 System.out.println(c.getTime()); // 将Calendar的年前推1年 c.add(YEAR , -1); //2002-11-23 12:32:23 System.out.println(c.getTime()); // 将Calendar的月前推8个月 c.roll(MONTH , -8); //2002-03-23 12:32:23 System.out.println(c.getTime()); }
add与roll的区别
add(int field,int amount)
主要用于改变Calendar的特定字段的值。如果要增加,则amount为正数,减少则为负数当被修改的字段超出它的允许范围时,会发生进位,即上一级字段也会增大。
Calendar cal1 = Calendar.getInstance(); cal1.set(2003, 7, 23, 0, 0 , 0); // 2003-8-23 cal1.add(MONTH, 6); //2003-8-23 => 2004-2-23 System.out.println(cal1.getTime());
如果下一字段也需要改变,那么该字段会修正到变化最小的值
Calendar cal2 = Calendar.getInstance(); cal2.set(2003, 7, 31, 0, 0 , 0); // 2003-8-31 // 因为进位到后月份改为2月,2月没有31日,自动变成29日 cal2.add(MONTH, 6); // 2003-8-31 => 2004-2-29 System.out.println(cal2.getTime());
roll()
规则与add()
的处理规则不同:当被修改的字段超出它的允许范围时,上一级不会增大。
Calendar cal3 = Calendar.getInstance(); cal3.set(2003, 7, 23, 0, 0 , 0); //2003-8-23 // MONTH字段“进位”,但YEAR字段并不增加 cal3.roll(MONTH, 6); //2003-8-23 => 2003-2-23 System.out.println(cal3.getTime());
下一级字段的处理规则与add()相似
Calendar cal4 = Calendar.getInstance(); cal4.set(2003, 7, 31, 0, 0 , 0); //2003-8-31 // MONTH字段“进位”后变成2,2月没有31日, // YEAR字段不会改变,2003年2月只有28天 cal4.roll(MONTH, 6); //2003-8-31 => 2003-2-28 System.out.println(cal4.getTime());
设置Calendae的兼容性
当传入一个非法的参数设置值的时候可以用
setLenient(false)
关闭容错性,让其进行严格的参数检查public static void main(String[] args){ Calendar cal = Calendar.getInstance(); // 结果是YEAR字段加1,MONTH字段为1(二月) cal.set(MONTH , 13); //① System.out.println(cal.getTime()); // 关闭容错性 cal.setLenient(false); // 导致运行时异常 cal.set(MONTH , 13); //② System.out.println(cal.getTime()); }
set()方法延迟修改
set(f,value)
方法将日历字段f改为value,此外还设置了一个内部成员变量,以指示日历字段f已经被更改。f的修改时立即更改的,但该Calendar所代表的时间却不会立即修改,知道下次调用get()
、getTime()
、getTimeInMillis()
、add()
或roll()
时才会重新计算日历的时间。这称之为set()
方法的延迟修改。也就不会因多次调用set()而产生多次计算public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.set(2003 , 7 , 31); //2003-8-31 // 将月份设为9,但9月31日不存在。 // 如果立即修改,系统将会把cal自动调整到10月1日。 cal.set(MONTH , 8); // 下面代码输出10月1日 //System.out.println(cal.getTime()); //不使之生效 // 设置DATE字段为5 cal.set(DATE , 5); //② System.out.println(cal.getTime()); //2003-9-5 }
Java8新增的日期、时间包
Java8专门新增了一个java.time包,该包包含了如下的常用类
Clock
:用于获取指定时区的当前日期、时间Duration
:代表持续时间Instant
:代表一个精确时刻,可以精确到纳秒。静态方法new()
,new(Clock clock)
,minusXxx()
,plusXxx()
LocalDate
:代表不带时区的日期。静态方法new()
,new(Clock clock)
,minusXxx()
,plusXxx()
LocalTime
:代表不带时区的时间。静态方法new()
,new(Clock clock)
,minusXxx()
,plusXxx()
LocalDateTime
:代表不带时区的日期、时间。静态方法new()
,new(Clock clock)
,minusXxx()
,plusXxx()
MonthDay
:仅代表月日。静态方法new()
,new(Clock clock)
Year
:仅代表年。静态方法new()
,new(Clock clock)
,minusYears()
,plusYears()
YearMonth
:仅代表月年。静态方法new()
,new(Clock clock)
,minusXxx()
,plusXxx()
ZonedDateTime
:代表一个时区化的日期、时间ZoneId
:代表一个时区DayOfWeek
:定义了周日到周六的枚举类Month
:定义了一月到十二月的枚举类public static void main(String[] args){ // -----下面是关于Clock的用法----- // 获取当前Clock Clock clock = Clock.systemUTC(); // 通过Clock获取当前时刻 System.out.println("当前时刻为:" + clock.instant()); // 获取clock对应的毫秒数,与System.currentTimeMillis()输出相同 System.out.println(clock.millis()); System.out.println(System.currentTimeMillis()); // -----下面是关于Duration的用法----- Duration d = Duration.ofSeconds(6000); System.out.println("6000秒相当于" + d.toMinutes() + "分"); System.out.println("6000秒相当于" + d.toHours() + "小时"); System.out.println("6000秒相当于" + d.toDays() + "天"); // 在clock基础上增加6000秒,返回新的Clock Clock clock2 = Clock.offset(clock, d); // 可看到clock2与clock1相差1小时40分 System.out.println("当前时刻加6000秒为:" +clock2.instant()); // -----下面是关于Instant的用法----- // 获取当前时间 Instant instant = Instant.now(); System.out.println(instant); // instant添加6000秒(即100分钟),返回新的Instant Instant instant2 = instant.plusSeconds(6000); System.out.println(instant2); // 根据字符串中解析Instant对象 Instant instant3 = Instant.parse("2014-02-23T10:12:35.342Z"); System.out.println(instant3); // 在instant3的基础上添加5小时4分钟 Instant instant4 = instant3.plus(Duration .ofHours(5).plusMinutes(4)); System.out.println(instant4); // 获取instant4的5天以前的时刻 Instant instant5 = instant4.minus(Duration.ofDays(5)); System.out.println(instant5); // -----下面是关于LocalDate的用法----- LocalDate localDate = LocalDate.now(); System.out.println(localDate); // 获得2014年的第146天 localDate = LocalDate.ofYearDay(2014, 146); System.out.println(localDate); // 2014-05-26 // 设置为2014年5月21日 localDate = LocalDate.of(2014, Month.MAY, 21); System.out.println(localDate); // 2014-05-21 // -----下面是关于LocalTime的用法----- // 获取当前时间 LocalTime localTime = LocalTime.now(); // 设置为22点33分 localTime = LocalTime.of(22, 33); System.out.println(localTime); // 22:33 // 返回一天中的第5503秒 localTime = LocalTime.ofSecondOfDay(5503); System.out.println(localTime); // 01:31:43 // -----下面是关于localDateTime的用法----- // 获取当前日期、时间 LocalDateTime localDateTime = LocalDateTime.now(); // 当前日期、时间加上25小时3分钟 LocalDateTime future = localDateTime.plusHours(25).plusMinutes(3); System.out.println("当前日期、时间的25小时3分之后:" + future); // 下面是关于Year、YearMonth、MonthDay的用法示例----- Year year = Year.now(); // 获取当前的年份 System.out.println("当前年份:" + year); // 输出当前年份 year = year.plusYears(5); // 当前年份再加5年 System.out.println("当前年份再过5年:" + year); // 根据指定月份获取YearMonth YearMonth ym = year.atMonth(10); System.out.println("year年10月:" + ym); // 输出XXXX-10,XXXX代表当前年份 // 当前年月再加5年,减3个月 ym = ym.plusYears(5).minusMonths(3); System.out.println("year年10月再加5年、减3个月:" + ym); MonthDay md = MonthDay.now(); System.out.println("当前月日:" + md); // 输出--XX-XX,代表几月几日 // 设置为5月23日 MonthDay md2 = md.with(Month.MAY).withDayOfMonth(23); System.out.println("5月23日为:" + md2); // 输出--05-23 }
正则表达式
正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作。String类里也提供了如下特殊方法:
boolean matches(String regex)
:判断该字符串是否匹配指定的正则表达式String replaceAll(String regex,String replacement)
:将该字符串中所有匹配regex的子串替换成replacementString replaceFirst(String regex,String replacement)
:将该字符串中第一个匹配regex的子串替换成replacement
创建正则表达式
- 创建正则表达式实质上就是创建一个特殊的字符串。
- 正则表达式支持的合法字符有如下几种,特殊字符也有一些
字符
解释
x
字符x
(x
可代表任意合法字符)
\0mnn
八进制数0mnn
所表示的字符
\xhh
十六进制值0xhh
所表示的数
\uhhhh
十六进制值0xhhhh
所表示的Unicode字符
\t
制表符('\u0009'
)
\n
新行(换行)符('\u000A'
)
\r
回车符('\u000D'
)
\f
换页符('\u000C'
)
\a
报警(bell)符('\u0007'
)
\e
Escape符('\u001B'
)
\cx
x对应的控制符(e.g \cM 匹配Ctrl+M
)
特殊字符
说明
匹配本身
$
匹配一行的结尾
\$
^
匹配一行的开头
\^
( )
标记子表达式的开始和结束位置
\( \)
[ ]
用于确定中括号表达式的开始和结束位置
\[ \]
{ }
用于标记前面子表达式的出现频率
\{ \}
*
指定前面子表达式可以出现零次或多次
\*
+
指定前面子表达式可以出现一次或多次
\+
?
指定前面子表达式可以出现零次或一次
\?
.
匹配除换行符\n之外的任何单字符
\.
\\
用于转义下一个字符,或指定八进制,十六进制字符
\\
|
指定两项之间任选一项
|
将上面的多个字符拼接起来,就可以创建一个正则表达式了。
e.g:"\u0041\\" //匹配A\
"\u0061\t" //匹配a<制表符>
"\?\[" //匹配?[
以上正则表达式只能匹配单个字符,正则表达式还有通配符,也就是预定义字符,用来匹配多个字符
预定义字符
说明
.
可以匹配任意字符
\d
匹配0~9的所有数字
\D
匹配非数字
\s
匹配所有的空白字符,包括空格,制表符,回车符,换页符,换行符等
\S
匹配所有的非空白符
\w
匹配所有的单词字符,包括0~9所有数字,26个英文字母和下划线( _ )
\W
匹配所有的非单词字符
- 记忆诀窍:d-digit,代表数字。s-space,代表空白。w-word,代表单词
比之前更加强大的表达式得以创建
e.g.c\wt //可以匹配cat,cbt,cct,c0t,c9t等一批字符串
\d\d\d-\d\d\d-\d\d\d\d //匹配如000-000-0000形式的电话号码
为了匹配字母段,以及非字母段,就需要适用方括号表达式了
方括号表达式
说明
表示枚举
[abc]
表示a、b、c其中的任意一个字符
表示范围:-
[a-d]
表示ad范围内的任意字符,可以和枚举一起使用,`[a-fx-z]`表示af、x-z范围的任意字符
表示求否:^
[^abc]
表示非a、b、c的任意字符,[^a-f]
表示非a~f范围内的任意字符
表示“与”运算:&&
[a-z&&[def]
表示a~z与[def]
的交集,表示d、e或f,[a-z&&[^bc]]
即为[ad-z]
表示“并”运算
并运算与枚举类似,[a-d[m-p]]
即为[a-dm-p]
圆括号表达式:用于将多个表达式组成一个子表达式,圆括号中可用或运算符(|
)e.g."((a)|(b)|(c))"
边界匹配符
边界匹配付
说明
^
行的开头
$
行的结尾
\b
单词的边界
\B
非单词的边界
\A
输入的开头
\G
前一个匹配的结尾
\Z
输入的结尾,仅用于最后的结束符
\z
输入的结尾
正则表达式的数量标识符,贪婪模式(Greedy):一直匹配。勉强模式(Reluctant),用问号后缀(?)表示,只会匹配最少的字符。占有模式(Possessive),用加号后缀(+)表示
使用正则表达式
一旦程序中定义了正则表达式,就可以使用Pattern和Matcher来使用正则表达式。Pattern对象是正则表达式编译后在内存中的表现形式,故正则表达式会被先编译为Pattern对象,然后利用该Pattern对象创建对应的Matcher对象,执行匹配所涉及的结果保留在Matcher对象中,多个Matcher对象可共享同一个Pattern对象,Pattern是不可变类,可供多个并发线程安全使用。由此得到典型的调用顺序如下:
//将一个字符串编译成Pattern对象 Pattern p = Pattern.compile("a*b"); //使用Pattern对象创建Matcher对象 Matcher m = p.matcher("aaaaab"); boolean b = m.matches(); //返回true
以上定义的Pattern对象可以多次重复使用,若只使用一次,可以调用Pattern类的静态方法matcher()
boolean b = Pattern.matches("a*b","aaaaab"); //返回true
Matcher类提供了如下几个常用方法:
find()
:返回目标字符串中是否包含与Pattern匹配的字串find(int i)
:从索引i处向下搜索,返回目标字符串中是否包含与Pattern匹配的字串group()
:返回上一次与Pattern匹配的字串start()
:返回上一次与Pattern匹配的字串在目标字符串中的开始位置end()
:返回上一次与Pattern匹配的字串在目标字符串中的结束位置+1lookingAt()
:返回目标字符串前面部分与Pattern是否匹配matches()
:返回整个目标字符串与Pattern是否匹配reset()
:将现有的Matcher对象应用于一个新的字符序列
public class FindGroup{ public static void main(String[] args){ // 使用字符串模拟从网络上得到的网页源码 String str = "我想求购一本《疯狂Java讲义》,尽快联系我13500006666" + "交朋友,电话号码是13611125565" + "出售二手电脑,联系方式15899903312"; // 创建一个Pattern对象,并用它建立一个Matcher对象 // 该正则表达式只抓取13X和15X段的手机号, // 实际要抓取哪些电话号码,只要修改正则表达式即可。 Matcher m = Pattern.compile("((13\d)|(15\d))\d{8}").matcher(str); // 将所有符合正则表达式的子串(电话号码)全部输出 while(m.find()){ System.out.println(m.group()); } } }
public class StartEnd{ public static void main(String[] args){ // 创建一个Pattern对象,并用它建立一个Matcher对象 String regStr = "Java is very easy!"; System.out.println("目标字符串是:" + regStr); Matcher m = Pattern.compile("\w+").matcher(regStr); while(m.find()){ System.out.println(m.group() + "子串的起始位置:"+ m.start() + ",其结束位置:" + m.end()); } } }
public class MatchesTest{ public static void main(String[] args){ String[] mails ={ "kongyeeku@163.com" , "kongyeeku@gmail.com", "ligang@crazyit.org", "wawa@abc.xx"}; String mailRegEx = "\w{3,20}@\w+\.(com|org|cn|net|gov)"; Pattern mailPattern = Pattern.compile(mailRegEx); Matcher matcher = null; for (String mail : mails){ if (matcher == null){ matcher = mailPattern.matcher(mail); }else{ matcher.reset(mail); } String result = mail + (matcher.matches() ? "是" : "不是")+ "一个有效的邮件地址!"; System.out.println(result); } } }