Java类库就是Java API(应用程序接口),是系统提供的已实现的标准类集合,使用Java类库可以完成涉及字符串处理、图形、网络等多方面的操作
API概念
API (Application Programming Interface)就是应用程序编程接口。
假设现在要编写一个机器人程序,去控制一个机器人踢足球,程序需要向机器人发出向前跑、向后转、射门、拦截等命令,没有编过程序的人很难想象如何编写这样的程序。但对于有编程经验的人来说,就知道机器人厂商一定会提供一些控制这些机器人的Java类,该类中就有操纵机器人的各种动作的方法,只需要为每个机器人安排一个该类的实例对象,再调用这个对象的各种方法,机器人就会去执行各种动作。这个Java类就是机器人厂家提供的应用程序编程的接口,厂家就可以对这些Java类美其名曰:Xxx Robot API(也就是Xxx厂家的机器人API)。好的机器人厂家不仅会提供Java程序用的Robot API,也会提供Windows编程语言(如VC++)用的Robot API,以满足各类编程人员的需要。
基本数据类型的包装类
Java对数据既提供基本数据的简单类型,也提供了相应的包装类。使用基本数据类型,可以改善系统的性能,也能够满足大多数的应用需求。但基本数据类型不具有对象的特性,不能满足某些特殊的需求。从JDK中可以知道,Java中的很多类的很多方法的参数类型都是Object,即这些方法接收的参数都是对象,同时,又需要用这些方法来处理基本数据类型的数据,这时就要用到包装类。比如,用Integer类来包装整数。
大家从前面的文章中应该已经了解到Java中的基本数据类型共有8种,那么与之相对应的基本数据类型包装类也同样有8种,表中列出了其对应关系。
使用包装类(IntegerDemo.java)
第5行定义一个字符串。
第6行通过Integer类将字符串a包装为整数i。
第7行在原有的基础上加1,第8行输出i的值。
本程序使用Integer类中的parseInt()方法,将一个字符串转换成基本数据类型。
装箱与拆箱
所谓装箱,就是把基本类型用它们相对应的引用类型包起来,使它们可以具有对象的特质,例如我们可以把int型包装成Integer类的对象,或者把double包装成Double等。
所谓拆箱,就是跟装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为值类型的数据。
JDK1.5之前使用手动方式进行装箱和拆箱的操作,JDK1.5之后可自动进行装箱和拆箱的操作。
使用包装类(Int Integer.java)。
第5行将基本类型变为包装类即装箱操作。第6行将包装类变为基本类型即拆箱操作。第7行输出temp与temp的乘积。
装箱操作:将基本数据类型变为包装类,利用各个包装类的构造方法完成;
拆箱操作:将包装类变为基本数据类型,利用Number类的xxxValue()方法完成。
基本数据类型与字符串的转换
使用包装类有一个最大的操作特点:可以将字符串变为指定的基本类型,使用的方法如下(以部分为例)。
是以上的操作方法形式对于Character是不存在的,因为String类有一个charAt()方法可以取得指定索引的字符。将字符串变为double型数据(DoubleDemo.java)
第5行定义一个字符串。
第6行通过Double类中的parseDouble方法将字符串str来包装为double型。
第7行输出x的值。
提示
在将字符串变为数值型数据时需要注意,字符串的组成必须全部由数字组成。
将字符串变为boolean型数据(BooleanDemo.java)
第5行定义一个字符串。
第6行通过Boolean类中的parseBoolean方法将字符串str来包装为Boolean型。
第7~13行判断flag的值为true还是false并输出相应的提示信息。
如果此时的字符串内容不是true或false,那么程序也不会出错,会按照false的情况进行处理。
通过以上的操作可以将字符串变为基本数据类型,那么反过来,如何将一个基本类型变为字符串呢?为此在Java之中提供了两种做法完成。
(1) 任何的基本数据类型遇见String之后自动变为字符串。
(2) 利用String类之中提供的一系列valueOf()方法完成。
将基本类型变为字符串(ToString.java)。
第5行定义整型数x。
第6行通过将x与字符串相加从而将x转换为字符串类型。
第7行将str输出。
这种方式必须使用一个字符串,所以一定会产生垃圾,不建议使用。
将基本类型变为字符串(ToString02.java)
第5行定义整型数x。
第6行通过String.valueOf(x)将整型变量x转换成字符串型。
第7行将str输出。
很明显,该例中的做法更方便使用,所以在日后开发中如遇见基本类型变为String的操作建议使用方式二完成。
System类与Runtime类
System类
Java不支持全局方法和变量,Java设计者将一些系统相关的重要方法和变量收集到了一个统一的类中,这就是System类。System类中的所有成员都是静态的,而要引用这些变量和方法,可直接使用System类名作为前缀。在前面已经使用到了标准输入和输出的in和out变量,下面再介绍System类中的几个方法,其他的方法大家可以参阅JDK文档资料。
exit(int status)方法,提前终止虚拟机的运行。对于发生了异常情况而想终止虚拟机的运行,传递一个非零值作为参数。若在用户正常操作下终止虚拟机的运行,则传递零值作为参数。
CurrentTimeMillis方法,返回自1970年1月1日0点0分0秒起至今的以毫秒为单位的时间,这是一个long类型的大数值。在计算机内部只有数值,没有真正的日期类型及其他各种类型,也就是说,平常用到的日期实质上就是一个数值,但通过这个数值,能够推算出其对应的具体日期时间。
getProperties方法是获得当前虚拟机的环境属性。每一个属性都是变量与值以成对的形式出现的。
样的道理,Java作为一个虚拟的操作系统,它也有自己的环境属性。Properties是Hashtable的子类,正好可以用于存储环境属性中的多个“变量/值”对格式的数据,getProperties方法返回值是包含了当前虚拟机的所有环境属性的Properties类型的对象。下面的例子演示打印出当前虚拟机的所有环境属性的变量和值。
打印当前虚拟机的所有环境属性的变量和值(SystemInfo.java)。
第6行通过getProperties方法获得当前虚拟机的环境属性。
第7行获取环境变量的所有“变量/值”。
第9~13行循环输出当前虚拟机的所有环境属性的变量和值。
Runtime类
Runtime表示的是运行时在每一个JVM进程之中都会存在唯一的一个Runtime类的实例化对象。这个类是一个明显的单例设计模式,此类将构造方法私有化了,既然是单例设计模式,那么一定会在类的内部提供一个static定义的方法,用于取得本类的实例化对象。
取得Runtime类对象:public static Runtime getRuntime();
取得了Runtime类的实例化对象之后,可以利用以下的方法取得一些内存的相关信息。
那么如果在程序之中出现了过多的垃圾,则一定会影响性能,那么此时可以利用Runtime类的如下方法清除垃圾:public void gc()。取得内存值(GetMemorySize.java)。
第5行通过静态方法Runtime.getRuntime获得正在运行的Runtime对象的引用。
第6行定义了一个字符串。
第7~10行通过一个循环产生垃圾。
第11~13行调用Runtime中的方法获取内存的使用情况,并输出。
第14行清除垃圾,然后在16~18行输出清除垃圾后内存的使用情况。
日期操作类
由于历史上设计的原因, Java中有关时间的API比较混乱,在最早的java.util.Date之后,Java提供了jdbc中使用的java.sql.Date,以及随后增加用于本地化时间的Calendar类。解决原先的时间API令人迷惑,不够易用的问题,Java8中引入了java.time包来彻底改变这个让人讨厌的时间API。需要注意的是新的时间类都是不可改变并且线程安全的。那么现在来看一下如何表示日期、时间。
日期类
日期类及其说明如下表所示
上面的类可以由下面的类组合。Year:表示年份,Month表示月份,YearMonth表示年月, MonthDay表示月日,DayOfWeek存储星期的一天。取得当前的日期时间(GetDatetime.java)。
第6行新建了一个LocalDateTime对象用于存储当前时间。
第7行直接输出这个时间对象。
使用过java7的人可以知道此处输出的结果相较于java 7 中的java.util.Date更加清晰易懂。符合国人习惯。
Java8在java.time中提供了许多实用方法。如判断是否闰年、同月日关联到另一年份等。
判断是否闰年(LeapYear.java)。
第6~11行指定一个具体的时间点。
第14行用isLeapYear()方法判断该年份是否为闰年。
第17~21行将2月29日对应到非润年的2014年的对应日期。
Java.time的API提供了大量相关的方法。
日期格式化类
在某些情况下,开发者可能要对日期对象进行转换。譬如,程序中用的另外一个类的方法要求一个LocalDate类型的参数。有时,要将用LocalDate对象表示的日期以指定的格式输出,或是将用特定格式显示的日期字符串转换成一个LocalDate对象,java.time.format包是专门用来格式化输出时间/日期的。
将时间对象格式化为字符串(DateFormatDemo.java)。
第8行获取当前时间。
第10行指定格式化规则。
第12行将日期按照指定的规则格式化为字符串,第13行将指定格式的时间输出。
正则表达式
经过一系列的分析,可以得出结论。String是一个非常万能的数据类型,但是在进行String类的操作之中,除了String类本身所具备的若干方法之外,String也可以利用正则完成一些更为复杂的操作以及验证。
正则的引出
在具体讲解正则操作之前,首先来看一下下面的程序,判断一个字符串是否由数字组成。
判断字符串是否由数字组成(JudgeString.java)
第5~11行用方法isNumber判断字符串“123”是否由数字组成,并输出相应的结果。
第13~24行定义了一个方法:isNumber。
第15行将接收的字符串转化为Char数组。
第16行循环遍历数组,第18行判断数组中的元素是否是由数字组成,如果不是返回false,否则返回true。
对于上面的例子有一个问题,这只是一个非常简单的验证,但是发现却写了11行代码,如果是一些更为复杂的验证,那么所需要编写的代码肯定更多。所以此时,代码可以简化为如下形式。
应用正则表达式(RegExp.java)。
在程序之中出现的“\d+”实际上就属于正则表达式的概念,发现使用正则可以简化不少的程序。在JDK 1.4之前,Java本身是不具备正则的操作支持的,如果需要使用正则,则需要通过apache下载一个正则的开发包。而到了JDK 1.4之后,Java开始支持了正则,同时给出了java.util.regex开发包,此包提供了正则的操作类,在这个包之中只提供了两个操作类:Pattern、Matcher,可是在一般的开发之中很少去直接使用这两个类。在JDK 1.4之后对于String类进行了大量的修改,里面增加了与正则有关的操作方法,有如下几个方法是可以支持正则操作的。
而如果要想操作这些方法,那么就必须首先清楚正则标记。
正则标记
在正则操作之中,使用一系列的标记符号是一件非常重要的任务,不光是Java,只要是支持正则操作的程序,例如:JavaScript标记都是统一的。所有的标记都在java.util.regex.Pattern类提供,下面给出一些核心的正则标记。
(1) 字符,表示单个字符,只能出现1位。
x:表示是一个指定的一位字符,例如:编写一个a,表示是字母a;
\:表示一位字符“\”,但是由于“\”有个数含义,所以使用“\”表示一位“\”;
\n:匹配换行;
(2) 字符范围,在指定的字符范围之中选1位,只能出现1位。
[abc]:表示可以是a、b、c中的任意一位;
[^abc]:表示不是a、b、c中的任意一位;
[a-zA-Z]:表示是任意一位字母(大写或小写);
[0-9]:表示是任意一位数字。
(3) 简洁表达式,表示1位。
.:表示任意的一位字符;
\d:表示一位数字,等价于“[0-9]”;
\D:表示一位非数字,等价于“[^0-9]”;
\s:表示一位空格,等价于“[ \t\n\x0B\f\r]”;
\S:表示一位非空格,等价于“[…… \t\n\x0B\f\r]”;
\w:表示一位字母、数字、,等价于“[a-zA-Z0-9]”;
\W:表示一位非字母、数字、,等价于“[^a-zA-Z0-9]”;
(4) 边界匹配,Java用不上。
^:表示正则的开头;
$:表示正则的结尾。
(5) 数量表示,之前的正则每个符号只表示一位,如果要表示多位,则必须使用以下的数量关系。
正则?:表示此正则可以出现0次或1次;
正则+:表示此正则可以出现1次或多次;
正则*:表示此正则可以出现0次、1次或多次;
正则{n}:表示此正则出现正好n次;
正则{n,}:表示此正则出现n次以上;
正则{n,m}:表示此正则出现n ~ m次。
(6) 逻辑操作。
正则1正则2:正则1之后紧跟正则2操作;
正则1|正则2:表示或的关系,有一套正则标记匹配即可;
(正则):表示按照一组来使用。
利用String进行正则操作
在String类中提供了与正则直接有关的操作方法,下面将使用这些方法进行正则标记的验证。
字符串替换(SubString.java)
第5行定义一个字符串str。
第6行利用正则表达式去除所有的数字只剩下字母。
第8行将转化后的字符串输出。
对于“[0-9]”的这个标记,实际上也可以使用“\d”表示,如第7行所示。
验证邮箱格式(EmailValidation.java)
第5行定义一个字符串str。
第6行利用正则表达式验证该字符串是否符合邮箱格式。
第8行输出验证结果。
Math与Random类
看到Math第一个反应是数学类,在Math类中提供了大量的数学计算方法。Math类包含了所有用于几何和三角的浮点运算方法,这些方法都是静态的,每个方法的使用都非常简单,读者一看JDK文档就能明白。
如:四舍五入:public static long round(double a);
Round()是将小数点之后的所有小数位四舍五入,最后只剩下整数部分。
(1) 如果参数为正数,且小数点后第一位>=5,运算结果为参数的整数部分+1。
(2) 如果参数为负数,且小数点后第一位>=5(小数第一位等于5,小数位数多于1),运算结果为参数的整数部分-1。
(3) 如果参数为正数,且小数点后第一位<5;或者参数为负数,且小数点后第一位<=5(小数仅有一个5),运算结果为参数的整数部分。
Random类是一个随机数产生器,随机数是按照某种算法产生的,一旦用一个初值创建Random对象,就可以得到一系列的随机数。但如果用相同的初值创建Random对象,得到的随机数序列是相同的,也就是说,在程序中看到的“随机数”是固定的那些数,起不到“随机”的作用。针对这个问题, Java设计者在Random类的Random()构造方法中使用当前的时间来初始化Random对象,因为没有任何时刻的时间是相同的,所以就可以减少随机数序列相同的可能性。
下面的程序就是利用Random类来产生5个0~100之间的随机整数。
利用Random类来产生5个0~100之间的随机整数(RandomDemo.java)。
第6行new一个Random对象用于生成随机数。
第7~10行利用for循环输出5个随机数。
利用Random随机产生一组数列,这种方式得到的结果事先是未知的。因此在以后编写验证码的时候可以利用此类完成。
大数字操作类
现在思考一个问题,如果说现在要对一个非常大的数字进行操作,并且这个数字已经超过了double的范畴,那么该如何做呢?
这个时候如果要想解决问题,唯一的做法是将数字变为字符串,之后按位进行手工的计算,自己处理进位是不是很麻烦?而在Java里面为了简化此类操作专门提供了两大数字操作类:java.math. BigInteger、java.math.BigDecimal。
大型整数操作类BigInteger
观察超过double的计算(BigNum.java)。
通过上例可以看出如果数字超过该类型的最大范围则会提示“Infinity”。在BigInteger类的构造方法(public BigInteger(String val))里面已经清楚的描述出了,如果数据过大,则只能利用字符串保存,而后在BigInteger类之中提供了若干个基本的数学操作。下面看一下BigInteger的四则运算。BigInteger的四则运算(BigNumDemo01.java)。
第6、7行定义两个BigInteger类的对象,可以看出在类中数字是以字符串的形式保存的。
第8~11行分别对这两个数进行加、减、乘、除操作并输出相应的结果。
第13行用bigA除以bigB并将商与余数保存在result数组中。
大型浮点数操作类BigDecimal
BigDecimal的实现用到了BigInteger,不同的是BigDecimal加入了小数的概念。一般的float型和Double型数据只可以用来做科学计算或者是工程计算,由于在商业计算中,要求的数字精度比较高,所以要用到java.math.BigDecimal类,它支持任何精度的定点数,可以用它来精确计算货币值。下面给出BigDecimal的一些主要方法。
BigDecimalDemo的四则运算(CalculateBigDecimal.java)。
第6、7行定义两个BigDecimal类的对象,可以看出在类中数字是以字符串的形式保存的。
第8~11行分别对这两个数进行加、减、乘、除操作,其中第11行BigDecimal.ROUND_DOWN指定商保留1位小数并输出相应的结果。
第12行将两个数的乘积按照进一法保留1位小数,并输出。
ROUND_DOWN表示舍弃一位,ROUND_UP表示进一位,ROUND_HALF_UP表示四舍五入,对于Math而言无法实现准确的位数操作,所以处理位数较大的数必须实现准确位的操作用户只有通过BigDecimal实现。
Integer类
我们都知道用int可以表示一个整型数,现在我们介绍另一种表示整型数的类型:Integer类。
在Java中数据类型分为基本数据类型和复杂数据类型,int属于基本数据类型,而Integer属于后者。
Integer类在对象中包装了一个基本类型int的值。Integer类型的对象包含一个int类型的字段。
此外,该类提供了多个方法,能在int类型和String类型之间互相转换,还提供了处理int类型时非常有用的其他一些常量和方法。
提示
当需要往ArrayList,HashMap中放东西时,像int这种内建类型是放不进去的,因为容器都是装object的,但是jdk1.5引入了自动装箱和自动拆箱,会自动的转化为内建类型的外覆类。
Integer类的三种创建方法(UseInteger.java)。
第5行利用new关键字新建一个Integer对象并实例化。
第6行利用Integer类中的valueOf创建Integer对象。
第7行直接将一个int类型的整数赋给Integer对象,利用java的自动装箱进行类型的转化。
Boolean类
java.lang.Boolean类与Integer一样是在对象中封装了一个基本布尔型的值。Boolean类型的对象包含在一个单一的字段中,其类型为布尔值。与Integer一样Boolean类也有三种生成的方式。此外Boolean类中还内置了一些实用的方法。
Boolean类的具体使用(CompareBoolean.java)。
第5行创建两个Boolean类型的变量b1、b2。
第6、7行分别给b1、b2赋值“true”、“false”。
第9行调用compareTo方法对b1、b2进行比较并将结果赋给res,如果仅b1为真则res大于零,如果仅b2为真则res小于零,否则res等于零。
Byte类
Byte 类将基本类型 byte 的值包装在一个对象中。一个Byte类型的对象只包含一个类型为 byte 的字段。此外,该类还为byte和String的相互转换提供了几种方法,并提供了处理byte时非常有用的其他一些常量和方法。
Byte类的基本使用方法(ByteFun.java)。
第5~7行利用三种不同的方法创建了三个Byte对象并实例化。
第8~10行作为一个int返回Byte的值。
第16行将string参数分析为有符号的十进制byte。
第18、19行分别对两个Byte对象进行比较。
1. 包装类型不能够随便使用关系运算符比较大小
下面以Integer为例针对三种创建对象的方法进行说明。
首先,对于new关键字创建的包装类对象,两次new得到的对象引用地址是不同的,不能使用“= =”关键字做大小比较。而使用“<”和“>”等运算符时,包装类型会调用valueOf方法,将运算符两边的对象都转换为基本类型后再做比较。这就是为何“= =”不能使用而“<”、“>”、“<=”、“>=”这几个符号可以使用的原因。
其次,使用valueOf方法创建的Integer对象,使用“==”符号时,运行结果有时候正确,有时候不正确。查看valueOf方法的源码,如下。
通过看源码能够知道,整数类型在-128~127之间时,会使用缓存,如果已经创建了一个相同的整数,使用valueOf创建第二次时,不会使用new关键字,而用已经缓存的对象。所以使用valueOf方法创建两次对象,若对应的数值相同,且数值在-128~127之间时,两个对象都指向同一个地址。
最后,使用Integer i = 400这样的方式来创建Integer对象,与valueOf方法的效果是一样的,不再赘述。
总之,包装类对象不可使用“==”符做比较运算,如果要进行比较运算时,最好使用java类库中的compareTo方法。
Java—解读Java中的String类