一、包装类
Java 是一种面向对象语言,但在 Java 中不能定义基本数据类型的对象,为了能将基本数据类型视
为对象进行处理,Java 提出了包装类的概念,它主要是将基本数据类型封装在包装类中,如int 型的包装类 Integer、 boolcan 的类 Boolean 等,这样便可以把这些基本数据类型转换为对象进行处理。Java 中的包装类及其对应的基本数据类型如表 11.1 所示。
说明: Java是可以直接处理基本数据类型的,但在有些情况下需要将其作为对象来处理,这时就需将其转换为包装类了,这里的包装类相当于基本数据类型与对象类型之间的一个桥梁。由于包装类和基本数据类型间的转换,引入了装箱和拆箱的概念:装箱就是将基本数据类型转换为包装类,而拆箱就是将包装类转换为基本数据类型,这里只需要简单了解这两个概念即可。
11.1.1 Integer类
java.lang 包中的 Integer 类、Byte 类、Short 类和 Long 类,分别将基本数据类型 int、byte、 short和long 封装成一个类,由于这些类都是 Number 类的子类,区别就是封装不同的数据类型,其包含的方法基本相同,所以本节以 Imteger 类为例讲解整数包装类。
Integer 类在对象中包装了一个基本数据类型 int 的值,该类的对象包含一个 int 类型的字段。此外,该类提供了多个方法,能在 int 类型和 String 类型之间瓦相转换,同时还提供了其他一些处理 int类型时非常有用的常量和方法。Integer 类的常用方法如表 11.2 所示 。
下面通过一个实例演示 Integer 类的常用方法的使用。
【[例11.1】Integer 类的常用方法
package Package11;
public class IntegerDemo {
public static void main(String[] args) {
int num = Integer.parseInt("456");//将字符串转换为int类型
Integer iNum = Integer.valueOf("456");//创建一个Integer对象
System.out.println("int数据与Integer对象的比较:"+iNum.equals(num));
String str2 = Integer.toBinaryString(num);//获取数字的二进制表示
String str3 = Integer.toHexString(num);//获取数字的十六进制表示
String str4 = Integer.toOctalString(num);//获取数字的八进制表示
String str5 = Integer.toString(num,15);//获取数字的十五进制表示
System.out.println("456的二进制表示为:"+str2);
System.out.println("456的十六进制表示为:"+str3);
System.out.println("456的八进制表示为:"+str4);
System.out.println("456的十五进制表示为:"+str5);
}
}
结果:
Integer 类提供了以下4个常量:
MAX VALUE: 表示 int 类型可取的最大值,即 2的31次方-1。
MIN VALUE:表示 int 类型可取的最小值,即-2的31次方。
SIZE:用来以二进制补码形式表示 int 值的位数。
TYPE: 表示基本类型 int的 Class 实例。
【例11.2】查看 Integer 类的常量值
package Package11;
public class GetCon {
public static void main(String[] args) {
int maxint = Integer.MAX_VALUE;//获取Integer类的常量
int minint = Integer.MIN_VALUE;
int intsize = Integer.SIZE;
System.out.println("int类型可取的最大值:"+maxint);//将常量值输出
System.out.println("int类型可取的最小值:"+minint);
System.out.println("int类型二进制位数是:"+intsize);
}
}
结果:
11.1.2 Double 类
Double 类和 Float类是对 double、float 基本类型的封装,它们都是 Number 类的子类,都是对浮点数进行操作,所以常用方法基本相同,本节将对 Double 类进行讲解。对于 Float 类,可以参考 Double类的相关内容。
Double 类在对象中包装一个基本类型为 double 的值,每个 Double 类的对象都包含一个 double类型的字段。此外,该类还提供多个方法,可以将 double 类型转换为 String 类型,将 String 类型转换为 double类型,也提供了其他一些处理 double 类型时有用的常量和方法。Double 类的常用方法如表 11.3 所示。
下面通过一个实例演示 Double 类的常用方法的使用。
【例11.3】 Double类的常用方法
package Package11;
public class DoubleDemo {
public static void main(String[] args) {
Double dNum = Double.valueOf("3.14");//创建一个Double对象
//判断是否为非数字值
System.out.println("3.14是否为非数字值:"+Double.isNaN(dNum.doubleValue()));
System.out.println("3.14转换为int值为:"+dNum.intValue());//转换为int类型
//判断大小
System.out.println("值为3.14的Double对象与3.14的比较结果:"+dNum.equals(3.14));
//转换为十六进制
System.out.println("3.14的十六进制表示为:"+Double.toHexString(dNum));
}
}
结果:
Double 类主要提供了以下常量:
MAX EXPONENT:返回it 值,表示有限 double 变量可能具有的最大指数。
MIN EXPONENT:返回 int 值,表示标准化 double 变量可能具有的最小指数。
NEGATIVE INFINITY:返回 double 值,表示保存 double 类型的负无穷大值的常量。
POSITIVE INFINITY:返回 double 值,表示保存 double 类型的正无穷大值的常量。
11.13 Boolean类
Boolean 类将基本类型为 boolean 的值包装在一个对象中。一个 Boolean 类型的对象只包含一个类型为 boolean 的字段。此外,此类还为 boolean 类型和 String 类型的相互转换提供了许多方法,并提供了处理 boolean 类型时非常有用的其他一些常量和方法。Boolean 类的常用方法如表 11.4 所示。
【例11.4]】Boolean 类的常用方法
package Package11;
public class BooleanDemo {
public static void main(String[] args) {
Boolean b1 = Boolean.valueOf("true");//创建Boolean对象
Boolean b2 = Boolean.valueOf("ok");
System.out.println("b1:"+b1.booleanValue());
System.out.println("b2:"+b2.booleanValue());
}
}
结果:
11.1.4 Character 类
Character 类在对象中包装一个基本类型为 char 的值,该类提供了多种方法,以确定字符的类别(小写字母、数字等),并可以很方便地将字符从大写转换成小写,反之亦然。Character 类提供了很多方法来完成对字符的操作,常用的方法如表 11.5 所示。
下面通过实例来演示 Character 类的大小写转换方法的使用,其他方法的使用与其类似。
【例11.5】Character 类的常用方法
package Package11;
public class UpperOrLower {
public static void main(String[] args) {
Character mychar1 = Character.valueOf('A');
Character mychar2 = Character.valueOf('a');
if(Character.isUpperCase(mychar1)) {//判断是否为大写字母
System.out.println(mychar1 + "是大写字母");
//转换为小写并输出
System.out.println("转换为小写字母的结果:" + Character.toLowerCase(mychar1));
}
if(Character.isLowerCase(mychar2)) {//判断是否为小写字母
System.out.println(mychar2 + "是小写字母");
//转换为大写并输出
System.out.println("转换为大写字母的结果:" + Character.toUpperCase(mychar2));
}
}
}
结果:
Character 类提供了大量表示特定字符的常量,例如:
CONNECTOR PUNCTUATION:返回 bvte 型值,表示 Unicode 规范中的常规类别“Pc”。
UNASSIGNED:返回 byte 型值,表示 Unicode 规范中的常规类别“Cn”。
TITLECASE_LETTER: 返回 byte 型值,表示 Unicode 规范中的常规类别“Lt”。
说明:Character 类提供的常量有很多,详细列表可查看 Java API文档。
11.1.5Number 类
前面介绍了 Java 中的包装类,对于数值型的包装类,它们有一个共同的父类一Number 类,该类是一个抽象类,它是 Bvte、Integer、Short、Long、Float 和 Double 类的父类,其子类必须提供将表示的数值转换为 bvteint、short、long、flat 和 double 的方法。例如,doubleValue0方法返回双精度浮点值,floatValue0方法返回单精度浮点值,这些方法如表 11.6 所示。
Number 类的方法分别被其各子类所实现,也就是说,在 Number 类的所有子类中都包含以上这几种方法。
二、数字处理
在Java 语言中,提供了一个执行数学基本运算的 Math 类,该类包括常用的数学运算方法,如三角函数方法、指数函数方法、对数函数方法、平方根函数方法等一些常用数学函数方法。除此之外还提供了一些常用的数学常量,如 PI、E 等。本节将讲解 Math 类以及其中的一些常用方法。
在实际开发中,随机数的使用是很普遍的,所以要掌握生成随机数的操作。在 Java 中主要提供了两种生成随机数的方式,分别为调用 Math 类的 random0方法生成随机数和调用 Random 类生成各种据类型的随机数。
在Java 中,还提供了大数字的操作类,即 java,mathBigInteger 类与 javamath.BigDecimal类。这两个类用于高精度计算,其中 BigInteger 类是针对大整数的处理类,而 BigDecimal类则是针对大小数的处理类。
11.2.1数字格式化
数字格式化在解决实际问题时应用非常普遍,如表示某超市的商品价格,需要保留两位有效数字,数字格式化操作主要针对的是浮点型数据,包括 double 型和 float 型数据。在 Java 中使用 java.text.DecimalFormat 格式化数字,本节将着重讲解 DecimalFormat 类。
在 Java 中,没有格式化的数据遵循以下原则:
如果数据绝对值大于 0.001 并且小于 10000000,使以常规小数形式表示.
如果数据绝对值小于 0.001 或者大于 10000000,使用科学记数法表示。
由于上述输出格式不能满足解决实际问题的要求,通常将结果格式化为指定形式后输出。在 Java中,可以使用 DecimalFormat 类进行格式化操作。
DecimalFormat 类是 NumberFormat 的一个子类,用于格式化十进制数字。它可以将一些数字格式化为整数、浮点数、百分数等。通过使用该类可以为要输出的数字加上单位或控制数字的精度。一般情况下,可以在实例化 DecimalFormat 对象时传递数字格式,也可以通过 DecimalFormat 类中applyPattemn0方法来实现数字格式化。
当格式化数字时,可在 DeimalFormat 类中使用一些特殊字符构成一个格式化模板,使数字按照一定的特殊字符规则进行匹配。表 11.7 列举了格式化模板中的特殊字符及其所代表的含义.
下面以实例说明数字格式化的使用。
【例11.6】DecimalFormat类的常用方法
package Package11;
import java.text.DecimalFormat;
public class DecimalFormatSimpleDemo{
static public void SimgleFormat(String pattern,double value) {
DecimalFormat myFormat = new DecimalFormat(pattern);//实例化DecimalMformat对象
String output = myFormat.format(value);//将数字进行格式化
System.out.println(value +""+ pattern +""+ output);
}
static public void UseApplyPatternMethodFormat(String pattern,double value) {
DecimalFormat myFormat = new DecimalFormat();//实例化DecimalFormat对象
myFormat.applyPattern(pattern);//调用applyPattern()方法设置格式化模板
System.out.println(value +""+ pattern +""+ myFormat.format(value));
}
public static void main(String[] args) {
SimgleFormat("###,###.###",123456.789);//调用静态SimgleFormat()方法
SimgleFormat("00000000.###kg",123456.789);//在数字后加上单位
//按照格式模板格式化数字,不存在的位以0显示
SimgleFormat("000000.000",123.78);
//调用静态UseApplyPatternMethodFormat()方法
UseApplyPatternMethodFormat("#.###%",0.789);//将数字转换为百分数形式
UseApplyPatternMethodFormat("###.##",123456.789);//将小数点后格式化为两位
UseApplyPatternMethodFormat("0.00\u2023",0.789);//将数字转换为千分数形式
}
}
结果:
在本实例中可以看到。代码的第一行使用import关键字将java.text.DecimalFormat这个类导入。这是告知系统下面的的代码将使用到DecimalFormat()类。然后定义了两个格式化数字的方法,这两个方法的参数都为两个,分别代表数字格式化模板和具体需要格式化的数字。虽然这两个方法都可以实现数字的格式化,但采用的方式有所不同,SimgleFormat()方法是在实例化DecimalFormat对象时设置数字格式化模板,而UseAppplyPatternMethodFormat()方法是在实例化DecimalFormat对象后调用applyPatteern()方法设置数字格式化模板。最后,在主方法中根据不同形式模板格式化数字。在结果中可以看到以“0”特殊字符构成的模板进行格式化时,当数字某位不存在时,将显示0;而以“#”特殊字符构成的模板进行格式化操作时,格式化后的数字位数与数字本身的位数一致。
在DecimalFormat类中,除了通过格式化模板来格式化数字,还可以使用一些特殊方法对数字进行格式化设置。例如:
DecimalFormat myFormat = new DecimatlFormat(); //实例化DecimalFormat类对象
myFormat.setGroupingSize(2); //设置将数字分组的大小
myFormat.setGroupingUsed(false); //设置是否支持分组
在上述代码中,setGroupingSize()方法设置格式化数字的分组大小,setGroupUsed()方法设置是否可以对数字进行分组操作。实例
package Package11;
import java.text.DecimalFormat;
public class DecimalMethod {
public static void main(String[] args) {
DecimalFormat myFormat = new DecimalFormat();
myFormat.setGroupingSize(2);//设置将数字分组为2
String output = myFormat.format(123456.789);
System.out.println("将数字以每两个数字分组"+output);
myFormat.setGroupingUsed(false);//设置不允许数字进行分组
String output2 = myFormat.format(123456.789);
System.out.println("不允许数字分组"+output2);
}
}
结果:
11.2.2 Math类
Math 类提供了众多数学函数方法,主要包括三角函数方法,指数函数方法,取整函数方法,取最大值、最小值,以及平均值函数方法。这些方法都被定义为static形式,所以在程序中应用比较简便。可以使用以下形式调用:
Math.数学方法
在 Math 类中,除函数方法外还存在一些常用数学常量,如 PI、E 等。这些数学常量作为 Math 类的成员变量出现,调用起来也很简单。可以使用如下形式调用:
Math.PI
Math.E
Math 类中的常用数学运算方法较多,大致可以将其分为四大类别,分别为三角函数方法,指数函数方法,取整函数方法,以及取最大值、最小值和绝对值函数方法。
1.三角函数方法
Math 类中包含的三角函数方法如下:
public static double sin(double a): 返回角的三角正弦
public static double cos(double a): 返回角的三角余弦
public static double tan(double a): 返回角的三角正切
public static double asin(double a): 返回一个值的反正弦
public static double acos(double a):返回一个值的反余弦
public static double atan(double a): 返回一个值的反正切
public static double toRadians(double angdeg): 将角度转换为弧度
public static double toDegrees(double angrad): 将弧度转换为角度
以上每个方法的参数和返回值都是 double 型的。将这些方法的参数的值设置为 double 型是有一定道理的,参数以弧度代替角度来实现,其中 1°等于Π/180 弧度,所以180°可以使用Π弧度来表示。除了可以获取角的正弦、余弦、正切、反正弦、反余弦、反正切,Math 类还提供了角度和弧度相互转换的方法 toRadians()和 toDegrees()。但需要注意的是,角度与弧度的转换通常是不精确的。
【例11.7】在Java代码中进行三角函数运算
package Package11;
public class TrigonometricFunction {
public static void main(String[] args) {
System.out.println("90度的正弦值:"+Math.sin(Math.PI/2));//取90°的正弦
System.out.println("o度的余弦值:"+Math.cos(0));//取0°的余弦
System.out.println("60度的正切值:"+Math.tan(Math.PI/3));//取60°的正切
//取2的平方根与2商的反正弦
System.out.println("2的平方根与2的商色反正弦值:"+Math.asin(Math.sqrt(2)/2));
//取2的平方根与2商的反余弦
System.out.println("2的平方根与2的商色反余弦值:"+Math.acos(Math.sqrt(2)/2));
System.out.println("1的反正切值:"+Math.atan(1));//取1的反正切
System.out.println("120度的弧度值:"+Math.toRadians(120.0));//取120°的弧度值
System.out.println("Π/2的角度值:"+Math.toDegrees(Math.PI/2));//取Π/2的角度
}
}
结果:
通过运行结果可以看出,90°的正弦值为1,0°的余弦值为1,60°的正切与Math.sqrt(3)的值应该时一致的,也就是取3的平方根。在结果中可以看到,第4~6行的值是基本相同的,这个值换算后正是45°,也就是获取的Math.sqrt(2)/2反正弦、反余弦值与1的反正弦值都是45°。最后两行打印语句实现的是角度和弧度的转换,其中:Math.toRadians(120.0) 语句是获取120°的弧度值,而Math。toDegrees(Math.PI/2)语句是获取Π/2的角度值。Π是一个近似值,不能做到十分精确。
2.指数函数方法
Math类中与指数相关的函数方法如下:
public static double exp(double a):用于获取e的a次方
public static double log(double a):用于获取自然对数,即取lna的值
public static double log10(double a):用于取底数为10的a的对数
public static double sqrt(double a):用于取a的平方根,其中a的值不能为负值
public static double cbrt(double a):用于取a的立方根
public static double pow(double a,double b):用于取a的b次方
指数运算包括求方根、取对数以及求n次方的运算。
【例11.8】在Java代码中进行指数函数运算
package Package11;
public class ExponentFunction {
public static void main(String[] args) {
System.out.println("e的平方根:"+Math.exp(2));//取e的2次方
System.out.println("以e为底2的对数值:"+Math.log(2));//取以为底2的对数
System.out.println("以10为底2的对数值:"+Math.log10(2));//取10为底2的对数
System.out.println("4的平方根值:"+Math.sqrt(4));//取4的平方根
System.out.println("8的立方根值:"+Math.cbrt(8));//取8的立方根
System.out.println("2的2次方值:"+Math.pow(2,2));//取2的2次方
}
}
结果:
在本实例中可以看到,使用Math类中的方法比较简单,直接使用Math类名调用相应的方法即可。3取整函数方法
在具体的问题中,取整操作使用也很普遍,所以Java在Math类中添加了数字取整法。Math类中包括以下几种取整方法:
public static double ceil(double a):返回大于等于参数的最小整数。
public static double floor(double a):返回小于等于参数的最小整数。
public static double rint(double a):返回与参数最接近的整数,如果存在两个同样接近的整数,则结果取偶数。
public static double round(double a):将参数加上0.5后返回与参数接近的整数。
public static double round(double a):将参数加上0.5后返回与参数接近的整数,然后强制转换为长整型。
注意:由于数1.0和数2.0距离数1.5都是0.5个单位长度,因此Math.rint(1.5)返回偶数2.0.
【例11.9】各场景下取整函数的运算结果
package Package11;
public class IntFunction {
public static void main(String[] args) {
System.out.println("使用ceil()方法取整:"+Math.ceil(5.2));//返回一个大于等于参数的整数
System.out.println("使用floor()方法取整:"+Math.floor(2.5));//返回一个小于等于参数的整数
System.out.println("使用rint()方法取整:"+Math.rint(2.7));//返回与参数最接近的整数
System.out.println("使用rint()方法取整:"+Math.rint(2.5));//返回与参数最接近的整数
//将参数加上0.5后返回最接近的整数
System.out.println("使用found()方法取整:"+Math.round(3.4f));
//将参数加上0.5后返回最接近的整数,并将结果强制转换为长整型
System.out.println("使用round()方法取整:"+Math.round(2.5));
}
}
结果:
使用round()方法取整:3
使用round()方法取整:3
4.取最大值、最小值、绝对值函数方法
在程序中最常用的力法就是敢展大值、最小值、绝对值等,Math 类中包括的操作方法如下:
public static double max(double a.double b): 取a与b之间的最大值。
public static int min(int a,int b): 取a与b之间的最小值,参数为整型。
public static long min(long a,long b): 取a与b之间的最小值,参数为长整型。
public static float min(foat a,foat b): 取a与b之间的最小值,参数为单精度浮点
public static double min (double a,double b): 取a与b之间的最小值,参数为双精度浮点型
public static int abs(int a): 返回整型参数的绝对值。
public static long abs(long a): 返回长整型参数的绝对值。
public static float abs(floata): 返回单精度浮点型参数的绝对值。
public static double abs(double a): 返回双精度浮点型参数的绝对值。
【例11.10】 取最大值、最小值、绝对值的方法
package Package11;
public class AnyFunction {
public static void main(String[] args) {
System.out.println("4和8较大者:"+Math.max(4,8));//取两个参数的最大值
System.out.println("4.4和4较小者:"+Math.min(4.4,4));//取两个参数的最小值
System.out.println("-7的绝对值:"+Math.abs(-7));//取参数的绝对值
}
}
结果:
11.2.3 Random类
Random 类是JDK 中的随机数生成器类,可以通过实例化一个 Random 对象创建一个随机数生成器,语法如下:
Random r = new Random();
以这种方式实例化对象时,Java 编译器将以系统当前时间作为随机数生成器的种子。因为每时每刻的时间不可能相同,所以产生的随机数不同。但是如果运行速度太快,也会产生两个运行结果相同的随机数。
用户也可以在实例化 Random 类对象时,设置随机数生成器的种子。语法如下:
Random r = new Random(seedValue):
r: Random 类对象
seedValue: 随机数生成器的种子
Random 类中,提供了获取各种数据美型随机数的方法,下面列举几个常用的方法
public int nextInt():返回一个随机整数
public int nextint(int n): 返回大于等于0且小于n的随机整数
public long nextLong(): 返回一个随机长整型值
public boolean nextBoolean(): 返回一个随机布尔型值。
public float nextFloat(): 返回一个随机单精度浮点型值。
public double nextDouble(): 返回一个随机双精度浮点型值
public double nextGaussian(): 返回一个概率密度为高斯分布的双精度浮点型值。
【例11.11】获取不同取值范围、不同类型的随机数
package Package11;
import java.util.Random;
public class RandomDemo {
public static void main(String[] args) {
Random r = new Random();//实例化一个Random类
//随机产生一个整数
System.out.println("随机产生一个整数:"+r.nextInt());
//随机产生一个大于等于0且小于10的整数
System.out.println("随机产生一个大于0小于10的整数:"+r.nextInt(10));
//随机产生一个布尔型的值
System.out.println("随机产生一个布尔型的值:"+r.nextBoolean());
//随机产生一个双精度浮点型的值
System.out.println("随机产生一个双精度浮点型的值:"+r.nextDouble());
//随机产生一个单精度浮点型的值
System.out.println("随机产生一个单精度浮点型的值:"+r.nextFloat());
//随机产生一个概略密度为高斯分布的双精度浮点型的值
System.out.println("随机产生一个概略密度为高斯分布的双精度浮点型的值:"+r.nextGaussian());
}
}
结果:
注意: random()方法返回的值实际上是伪随机数,它通过复杂的运算而得到一系列的数。该方法是通过当前时间作为随机教生成器的参数,所以每次执行程序都会产生不同的随机数。
11.2.4 Biglnteger类
Biglnteger类的数学范围较Integer类的数字围要大得多。前文介绍过Ingteger类是int的包装类。int的最大值为2的31次方-1,如果 要计算更大的数字,使用Integer类就无法实现了,所以Java中提供了BigInteger类来处理更大的数字。BigInteger类支持任意精度的整数,也就是说,在运算中BigInteger类可以准确的表示任何大小的整数值而不会丢失信息。
在BigInteger类中封装了多种操作,除了基本的加、减、乘、除操作,还提供了绝对值、相反数、最大公约数以及判断是否为质数等操作。
使用BigInteger类,可以实例化一个BigInteger对象,并自动调用相应的构造函数。BigInteger类具有很多构造函数,但最直接的一种方式是参数以字符串形式代表要处理的数字。
例如,将2转换为BigInteger类型,可以使用以下语句进行初始化操作:
BigInteger twoInstance = new BigInteger("2");
注意:参数2的双引号不能省略,因为参数是以字符串的形式存在的。
一但创建了对象实例,就可以调用 Biglnteger 类中的一些方法进行运算操作,包括基本的数学运算和位运算以及一些取相反数、取绝对值等操作。下面列举了 BigInteger 类中常用的几种运算方法:
public BigInteger add(BigInteger val): 做加法运算。
public BigInteger subtract(BigInteger val): 做减法运算
public BigInteger multiply(BigInteger val): 做乘法运算
public BigInteger divide(BigInteger val): 做除法运算。
public BigInteger remainder(BigInteger val): 做取余操作。
public BigIntegerll divideAndRemainder(BigInteger val): 用数组返回余数和商,结果数组中第一
个值为商,第二个值为余数。
public BigInteger pow(int exponent): 进行取参数的 exponent 次方操作
public BigInteger negate0: 取相反数
public BigInteger shiftLeft(int n): 将数字左移n位,如果 n为负数,做右移操作
public BigInteger shiftRight(intn): 将数字右移n位,如果n为负数,做左移操作仅
public BigInteger and(BigInteger val); 做与操作。
public BigInteger or(BigInteger val): 做或操作
public int compareTo(BigInteger val): 做数字比较操作
public boolean equals(Object x): 当参数是 BigInteger 类型的数字并日数值与对象实例的数值相等时,返回 true。
public BigInteger min(BigInteger val): 返回较小的数值
public BigInteger max(BigInteger val): 返回较大的数值。
【例11.12】使用BingInteger类进行数学运算
package Package11;
import java.math.BigInteger;
public class BiglntegerDemo {
public static void main(String[] args) {
BigInteger b1 = new BigInteger("987654321987654321");//第1个大数字
BigInteger b2 = new BigInteger("123456789123456789");//第2个大数字
System.out.println("加法操作:"+b1.add(b2));//加法运算
System.out.println("减法操作:"+b1.subtract(b2));//减法运算
System.out.println("乘法操作:"+b1.multiply(b2));//乘法运算
System.out.println("除法操作:"+b1.divide(b2));//除法运算
System.out.println("取商:"+b1.divideAndRemainder(b2)[0]);//取商运算
System.out.println("取余数:"+b1.divideAndRemainder(b2)[1]);//取余运算
System.out.println("做2次方操作:"+b1.pow(2));//2次方运算
System.out.println("取相反数操作:"+b1.negate());//相反数运算
}
}
结果:
误区警示:在本实例中需要注意的是,divideAndRemainder0方法做除法操作,以数组的形式返回,数组中第一个值为做除法的商,第二个值为做除法的余数。
11.2.5 BigDecimal类
BigDecimal类和BigInteger类都能实现大数字的运算,不同的是BigDecimal类加入了小数概念。一般的float型和double型数据只可以用来做科学计算或工程计算,但由于商业计算中要求数字精度比较高,所以要用到BifDecimal类。BigDecimal类支持任何精度的定点数,可以用它来精确计算货币值,在BifDecimal类中,常用的两个构造方法如表11.8所示。
BigDecimal 类型的数字可以用来做超大的浮点数的运算,如加、减、乘、除等,但是在所有的运算中除法是最复杂的,因为在除不尽的情况下商小数点后的末位的处理是需要考虑的。BigDecimal类实现的加、减、乘、除的方法如表11.9所示:
在上述方法中,BigDecimal 类中divide()方法有多种设置,用于返回商小数点后的末位的处理,这些模式的名称与含义如表 11.10 所示。
下面设计一个类,这个类包括任意两个 BigDecimal类型数字的加、减、乘、除运算方法。
【例11.13】使用 BigDecimal类进行数学运算
package Package11;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo {
public static void main(String[] args) {
BigDecimal b1 = new BigDecimal("0.00987654321987654321");//第1个大小数
BigDecimal b2 = new BigDecimal("0.00123456789123456789");//第2个大小数
System.out.println("两个数字相加结果:"+b1.add(b2));//加法运算
System.out.println("两个数字相减结果:"+b1.subtract(b2));//减法运算
System.out.println("两个数字相乘结果:"+b1.multiply(b2));//乘法运算
//除法运算,商小数点后保留9位,并将结果进行四舍五入操作
System.out.println("两个数字相除,保留小数点后9位:"+b1.divide(b2,9,RoundingMode.HALF_UP));//
}
}
结果:
三、System 类
System 类是JDK 中提供的系统类,该类是用 fial修饰的,所以不允许被继承。System 类提供了很多系统层面的操作方法,并且这些方法全部都是静态的。Svstem 类提供的较常用方法如表 11.11 所示。本节重点讲解利用 System 类控制台输出和计时这两个操作。
11.3.1 控制台输出字符
System 类提供了标准输入、标准输出和错误输出流,也就是说,System 类提供了3 个静态对象:in、out 和err。本书中的代码多次使用了这些对象,最常见的就是 out 对象。在控制台输出字符串,输出的方法有两种,下面分别进行讲解。
1.不会自动换行的 print()方法
print0方法的语法如下;
System.out.print("Hellol");
此方法输出“Hello”文字,输出完毕后,光标会停留在“Hello”文字末尾,不会自动换行
2.可以自动换行的 printin()方法
printin()方法在print后面加上了“In”后缀 (就是line 的简写),语法如下:
System.out.println(“书籍是人类进步的阶梯!”);
此方法输出“书籍是人类进步的阶梯!”后会自动换行。光标停留在下一行的开头。print()方法与 println()方法输出的对比效果如表11.12所示
综上所述,Java 输出换行的方法有以下两种:
System.out.print("\n"); //利用换行符n实现换行
System.out.println(); //空参数即可实现换行
误区警告: 使用这两个输出方法时还要注意以下两点:
(1)“System.outprintln("\n")”会打印两个空行
(2)“System.out.print0();”无参数会报错
11.3.2 计时
System.currentTimeMillis0方法可以获取自 1970年1月1日零点至的毫秒数。虽然 Date日期类也有类似的方法,但代码会比 System 类多,所以 System.currentTimeMillis0方法是为获取当前毫秒数最常用的方法。因为该方法的返回值精确到毫秒,所以可以利用该方法来记录程序的运行时间。【例11.14】查看执行一万次字符串拼接所消耗的时间
package Package11;
public class SystemTemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();//程序开始记录时间
String str = null;//创建null字符串
for(int i = 0;i < 10000;i++) {//循环一万次
str += i;//字符串与循环变量拼接
}
long end = System.currentTimeMillis();//记录循环结束时间
System.out.println("循环用时:"+(end - start)+"毫秒");
}
}
结果:
四、Scanner 类
与C 语言不同,Java 从控制台中读出用户输入的值,用到的不是一行可以直接使用的代码,而是由一个叫 Scanner 的类来实现的。Scanner 英文直译就是扫描仪,它的用途就和现实生活的扫描仪一样,可以把数字化信息流转为人类可识别的文字。控制台输出内容用到了 System.out 就表示向控制台输出System.in 就表示从控制台输入,让 Scanner 扫描 Svstem.in 就可以获取用户输入的值了。
使用 Scanner 类首先要引入该类,其语法如下:
import java.util.Scanner; //引入 Scanner类
Scanner 类提供了如表 11.13 所示的几种常用的方法,通过这些方法可以获取控制台中输入的不同类型的值。
误区警告:nextLine()方法扫描的内容是从第一个字符开始到换行符为止,而 next()、nextInt()等方法扫描的内容是从第一个字符开始到这段完整内容结束。
使用Scanner类扫描控制台的代码如下:
Scanner sc = new Scanner(System.in);
System.in 表示控制台输入流,在创建 Scanner 对象时把 System.in 作为参数,这样创建出的扫描器对象扫描的目标就是用户在控制台中输入的内容,再通过表 11.13 中列出的方法将用户输入的内容转为Java的数据类型,就可以对数据进行加工、显示了。
【例11.15】猜数字游戏
package Package11;
import java.util.Random;
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
Random r = new Random();//随机数对象
int num = r.nextInt(100);//从1~99取值
int input = -1;;//记录用户输入的值
Scanner sc = new Scanner(System.in);//扫描器扫描控制台输入
while(true) {
System.out.println("猜一猜随机数是多少?");
input = sc.nextInt();//获取用户输入的一个整数
if(input>num) {//如果大于随机数
System.out.println("你输入的数字大了!");
}else if(input<num) {//如果小于随机数
System.out.println("你输入的数字小了!");
}else if(input==num) {//如果等于随机数
break;//结束循环
}else {
System.out.println("您的输入有误!");
}
}
System.out.println("恭喜你答对了!");
sc.close();//关闭扫描器
}
}
结果:
五、日期时间类
在程序开发中,经常需要处理日期时间,Java 中提供了专门的日期时间类来处理相应的问题,本节将对 Java 中的日期时间类进行详细讲解。
11.5.1 Date类
Date 类用于表示日期时间,使用该类表示时间需要使用其构造方法创建对象,其构造方法及其说明如表11.14所示。
例如,使用 Date 类的第2 种构造方法创建一个 Date 类的对象,代码如下:
long timeMillis = System.currentTimeMillis(): //当前系统时间所经历的毫秒数
Date date = new Date(timeMillis);
上述代码中的 System 类的 currentTimeMillis0方法主要用来获取当前系统时间距标准基准时间的毫秒数。另外,这里需要注意的是,创建 Date 对象时使用的是 long 型整数,而不是 double 型,这主要是因为 double 类型可能会损失精度。Date 类的常用方法及其说明如表 11.15 所示。
【例11.16】获取当前的日期和时间
package Package11;
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
Date date = new Date();//创建现在的日期
long value = date.getTime();//获得毫秒数
System.out.println("日期:"+date);
System.out.println("到现在所经历的毫秒数为:"+value);
}
}
结果:
误区警告:(1)本节介绍的Date 类在java.util 包下,但java.sql包下也有一个 Date 类,不要将两者搞混(2)因为代码执行的时间不同,所以每次“获取的当前时间”得到的结果都不会一样。
11.52日期时间格式化
如果在程序中直接输出 Date 对象,显示的是“Mon Feb 29 17:39:50CST2016”这种格式的日期时间,那么应该如何将其显示为“2016-02-29”或者“17:39:50”这样的日期时间格式呢? Java 中提供了DateFormat 类来实现类似的功能。
DateFormat 类是日期时间格式化子类的抽象类,可以按照指定的格式对日期或时间进行格式化。DateFormat 类提供了很多类方法,以获得基于默认或给定语言环境和多种格式化风格的默认日期时间Formatter,格式化风格主要包括 SHORT、MEDIUM、LONG和FULL4种:
SHORT:完全为数字,如 12.13.52或3:30pm。
MEDIUM:较长,如Jan 12,1952。
LONG:更长,如 January 12,1952 或 3:30:32pm。
FULL:完全指定,如Tuesday、April 12、1952AD或3:30:42pm PST。
另外,使用 DateFormat类还可以自定义日期时间的格式。要格式化一个当前语言环境下的日期,首先需要创建 DateFormat 类的一个对象,由于它是抽象类,因此可以使用其静态方法getDateInstance()进行创建,语法如下:
DateFormat df = DateFormat.getDatelnstance();
使用 getDateInstance()方法获取的是所在国家或地区的标准日期格式。另外,DateFormat 类还提供了一些其他静态方法。例如,使用 getTimeInstance()方法可获取所在国家或地区的时间格式,使用getDateTimeInstance()方法可获取日期和时间格式。DateFormat 类的常用方法及其说明如表 11.16所示。
例如,将当前日期按照 DateFormat 类默认格式输出:
DateFormat df = DateFormat.getlnstance():
System.out.println(df.format(new Date()));
结果如下: 2021/2/19上午9:59
输出长类型格式的当前时间:
DateFormat df = DateFormat.getTimelnstance(DateFormat.LONG);
System.out.println(df.format(new Date())):
结果如下: CST 上午 10:00:33
输出长类型格式的当前日期:
DateFormat df = DateFormatgetDatelnstance(DateFormat.LONG);
System.out.println(df.formatnew Date()));
结果如下:2021年2月19日
输出长类型格式的当前日期和时间:
DateFormat df = DateFormat.getDate Timelnstance(DateFormat.LONG, DateFormat.LONG);
System.out.println(df.format(new Date()));
结果如下:2021年2月19日CST 上午10:01:12
由于 DateFormat 类是一个抽象类,不能用 new 创建实例对象。因此,除了使用 getXXXInstance()方法创建其对象,还可以使用其子类,如 SimpleDateFormat 类,该类是一个以与语言环境相关的方式来格式化和分析日期的具体类,它允许进行格式化 (日期一文本)、分析(文本一日期)和规范化。
SimpleDateFormat 类提供了19 个格式化字符,可以让开发者随意编写日期格式,这19个格式化字符如表 11.17 所示.
通常表 11.17 中的字符出现的数量会影响数字的格式。例如,yyyy 表示 4 位年份,这样输入会显示2021:表示两位,这样输入就会显示为21;只有一个y的话,会按照yyyy 显示;如果超过4个y,如yyyyyy,会在4位年份左侧补 0,结果为 02021。些常用的日期时间格式如表 11.18 所示.
【例11.17】以中文形式打印当前的日期和时间
package Package11;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatDemo {
public static void main(String[] args) {
DateFormat df = new SimpleDateFormat("yyy年MM月dd日EEEEE HH时mm分ss秒");
System.out.print("各位观众大家好,现在是");
System.out.print(df.format(new Date()));
System.out.println(", 欢迎收看新闻。");
}
}
结果:
DateFormat类提供的 Date parse(String source)方法可以将字符串转为其字面日期对应的Date对象。整个过程相当于日期格式化的逆操作。
例如,将“2021-02-19”这个字符串转成Date 对象,可以使用如下代码:
DateFormat sdf = new SimpleDateFormat(yyyy-MM-dd");
Date date = sdf.parse("2021-02-19");
注意: 如果日期字符串不符合格式,则会抛出iava.text.ParseException异常。
11.5.3 Calendar 类
打开JavaAPI文档可以看到iavautilDate 类提供的大部分方法都已经过时了,因为 Date类在设计之初没有考虑到国际化,而且很多方法也不能满足用户需求,比如需要获取指定时间的年月日时分秒信息,或者想要对日期时间进行加减运算等复杂的操作,Date 类已经不能胜任,因此JDK提供了新的时间处理类--Calendar 日历类。
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH_DAY OF MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(如获得下星期的日期)提供了一些方法。另外,该类还为实现包范围外的具体日历系统提供了其他字段和方法,这些字段和方法被定义为 protected。
Calendar 提供了一个类方法 getInstance(),以获得此类型的一个通用的对象。Calendar 类的getInstance()方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化,其使用方法如下:
Calendar rightNow = Calendar.getlnstance();
说明:由于 Calendar 类是一个抽象类,不能用new创建实例对象,因此除了使用 getInstance()方法创说明建其对象,如果需要创建其对象,必须使用其子类,如GregorianCalendar 类。
Calendar 类提供的常用字段及其说明如表 11.19 所示。
Calendar 类提供的常用方法及其说明如表 11.20 所示。
从表 11.20 可以看到,add()方法和 roll()方法都用来为给定的日历字段添加或减去指定的时间量,它们的主要区别在于:使用 add()方法时会影响大的字段,像数学里加法的进位或错位,而使用 roll()方法设置的日期字段只是进行增加或减少,不会改变更大的字段。
【例11.18】今天离中华人民共和国成立100 周年差多少天
package Package11;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class CountDown {
public static void main(String[] args) {
System.out.println("——————————————中华人民共和国成立100周年倒计时——————————————");
Date date = new Date();//当前时间
//创建SimpleDateFormat对象,指定目标格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy年MM月dd日");
//创建format方法,格式化时间,转换为指定格式
String today = simpleDateFormat.format(date);
System.out.println("今天是"+today);//输出当前日期
//获取自1970年1月1日至当前时间所经过的毫秒数
long time1 = date.getTime();
//使用默认时区和语言环境得一个日历calendar
Calendar calendar = Calendar.getInstance();
//设置日历calendar中的年、月和日的值。因为月份是从0开始计算的,所以这里要减一
calendar.set(2049,10-1,1);
//计算自1970年1月1日至2049年10月1日所经过的毫秒数
long time2 = calendar.getTimeInMillis();
//计算2049年10月1日距离当前时间的天数
long day = (time2 - time1)/(1000*60*60*24);
System.out.println("距离2049年10月1日还有"+day+"天!");
}
}
结果:
最后对 Calendar 类的使用做出几点总结:
c.set(CalendarDAY_OF_MONTHO)获取的是上个月的最后一天,所以调用前需要将月份往后加一个月。
Calendar.MONTH 的第一个月是使用0记录的,所以在获得月份数字后要加1。年和日是从14开始记录的,不需要加 1。
CalendarDAY_OF_WEEK 的第一天是周日,周一是第二天,周六是最后一天。
六、Runtime 类
Runtime 类是JDK 提供的运行时类,该类为Java 程序提供了与当前运行环境相连接的一个通道Java 程序可以利用该类对当前的运行环境执行一些简单的操作。Runtime 类不能使用 new 关键字创实例,只能通过 RuntimegetRuntime()方法获取实例。
Runtime 类的常用方法如表 11.21所示,本节将重点讲解利用 Runtime 类执行本地命令和查看Java虚拟机所占内存这两个操作。
11.6.1执行本地命令
本地命令指的是操作系统的命令。例如,在 Linux 系统下就表示 shell 命令,在 Windows 系统下就表示 cmd 命令。
Runtime 类提供exec0方法让Java 代码可以执行系统的命令,exec0方法有很多重载的形式,例如:
Process exec(String command)
Process exec(String[] cmdarray)
command:要执行的系统命令,字符串类型。
cmdarray:要执行的命令和相应的命令参数,字符串数组类型。
其实这两个重载方式很类似,如执行“javac hellojava”这行命令,使用第一种重载方式的代码如下:
Runtime.getRuntime().exec("javac hello.java");
使用第二种重载方式的代码如下:
String command[] = { "javac", "hello.java"} ;
Runtime.getRuntime().exec(command);
exec()方法会返回一个 Process 对象。Process 类是 Java 中进程类,该类是抽象类,不能使用new关键字创建实例。Process 类的常用方法如表 11.22所示,开发可以使用 etlnputStream()方法获取进程返回的信息。
【例11.19】让Java程序执行 Windows 系统的 help 命令
package Package11;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class RuntimeExecDemo {
public static void main(String[] args) {
Runtime r= Runtime.getRuntime();//获取本地 Runtime 对象
try {
Process p = r.exec("help");
InputStream is = p.getInputStream();//获取本地 Runtime 对象
//将字节输入流转换为字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = null;//创建 null 字符串
while ((str = br.readLine()) != null) {//如果字符流中可以获取非空内容
System.out.println(str);//打印获取的内容
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
结果:
11.6.2 查看内存
Runtime 类可以通过 freeMemory()方法查看当前Java 虚拟机可用内存的剩余量。如果程序能够实时监控内存剩余量,就可以尽量控制程序对内存的占用,从而避免出现“内存溢出”的情况。同样,也可以用来对测试程序性能,检验程序算法是否导致内存紧张。
【例11.20】监控虚拟机内存使用情况
package Package11;
public class MemoryDemo {
public static void main(String[] args) {
Runtime r= Runtime.getRuntime();//获取本地 Runtime对象
Integer ints[] = new Integer[10000];//创建长度为10000的整型数组
long before = r.freeMemory();//获取当前空闲内存数
System.out.println("赋值前空闲内存字节数:"+before);
for (int i = 0, length = ints.length;i < length; i++) {//循环为整型数组赋值
ints[i] = i;//赋值
}
long after = r.freeMemory();//获取当前空闲内存数
System.out.println("赋值后空闲内存字节数:"+after);
System.out.println("数组用掉的内存字节数:" +(before - after));//输出数组用掉的内存量
}
}
结果:
注意:freeMemory()方法得到的剩余内存量是近似值。