一个初出茅庐的小子与大家共享一些关于Number和Math的使用,因水平有限,难免有写的不完善的地方,嘻嘻。看完之后,希望可以留下你珍贵的指导意见。
The Numbers Classes
在写代码的时候,也许会使用到java 各种的基本数据类型,如下:
int i = 500;
float gpa = 3.65f;
byte mask = 0xff;
然而,在面向对象开发的过程,我们更倡导你使用对象来代替各种的基本数据类型,而java也为各种基本数据类型提供了wrapper class(包装类)——这些wrapper class封装了对应的基本数据。通常,编译器会为我们完成这种封装——换句话说就是,如果一个方法需要Object类型的参数,而实际提供的值确实2、3等数值,这时编译器会把2、3等数值封装成对应的wrapper class;类似,如果一个方法需要基本数据类型的参数,而实际提供的却似Object类型,这时编译器会Object类型的参数拆成几本数据类型——而这就所为的“自动拆装箱原理”。
接着给出一个自动拆装箱的demo:
1
2
3
4
|
Integer x, y;
x =
12
;
y =
15
;
System.out.println(x+y);
|
以上为x、y变量赋int 值,编译器会自动将x、y封装成Integer对象类型;在println()里,为了进行基本的算术处理,编译器会自动将x、y变量拆成int的基本数据类型。
所有基本数据的wrapper class都是抽象类Number的子类
附:在这里,有四个Number的子类并没有讨论。BigDecimal 和 BigInteger 是用于高精度的运算;AtomicInteger 和 AtomicLong 用于多线程程序里。
下面给出使用wrapper class 而不使用基本数据类型的理由:
1、可用在需要Object类型参数的方法里(常用于操作集合的数据)
2、在类里可使用各种常量(如MIN_VALUE
和MAX_VALUE),可以提供各种数据的上下界限(范围)。
3、可以使用wrapper class的对象方法,进行各种值与基本数据类型的相互转换,如String类型的相互转换,还可以与各种进制的数据进行相互装换(二进制binary、八进制octal、十进制decimal、十六进制hexadecimal)
下表列出了各个wrapper class都具有的方法(Number 类的方法)
Methods Implemented by all Subclasses of Number |
|
方法 |
描述 |
byte byteValue() |
将Number对象转换成对应的基本数据类型 |
int compareTo(Byte anotherByte) |
将Number对象的值与参数anotherXxx的值进行比较 |
boolean equals(Object obj) |
判断Number对象和参数Object是否相同。 当两个对象不为空且数据类型和值都一致的情况下,才返回true。 如果判断的是Double和Float类型,则还需要一些额外的参数,详情可参考java API的官方文档。 |
对于与String类型的数据与及各种进制数据之间的装换,每个Number类(在这指其子类)都有着相对应的方法。下表列出了Integer对象与String数据和进制之间相互转换的方法。其他的Number类都与之类似。
Integer类的转换方法 |
|
方法 |
描述 |
static Integer decode(String s) |
将String解码为Integer。String数据可以是十进制、八进制或者十六进制。 |
static int parseInt(String s) |
返回一个int值,String只能是十进制的数据。 |
static int parseInt(String s, int radix) |
将指定进制的String数据转换成int值。参数radix指多少进制(可以是2、8、10或者16) |
String toString() |
将Integer数据转成String类型 |
static String toString(int i) |
返回一个指定整数的String对象 |
static Integer valueOf(int i) |
返回一个表示指定的int值的Integer实例。 |
static Integer valueOf(String s) |
返回String数据的Integer对象 |
static Integer valueOf(String s, int radix) |
将指定进制的String数据转换为Integer类型。如当s=”333”,radix=8时,会返回数据为219的Integer实例。 |
格式化输出各种数据
一直以来,也许你都是在使用标准输出(System.out)输出各种数据,之所以可以这样做,是因为所有Number数据都可以转换成String类型。然而,有时候你可能需要更好地控制数据的输出,则需要使用java提供的其他方法。
printf()和format()方法
在java.io包里,有一个PrintStream类,此类提供了两个方法(printf()和format())来取代print()和println()。printf和format方法除了名字不一样之外,其余用法一致。同时因为System.out本事是一个PrintStream对象,所以你可以在原来使用print()和println()的位置用printf()或者format()方法来代替——System.out.format(.....);
其方法原型如下:
public PrintStream format(String format, Object... args);
public PrintStream printf(String format, Object... args);
参数format指定输出的格式(字符窜的格式),而args则是输出格式里的数据(参数列表)。
为了说明它的用法,可以看一下这个简单的例子:
1
2
|
System.out.format(
"The value of "
+
"the float variable is "
+
"%f, while the value of the "
+
"integer variable is %d, "
+
"and the string is %s"
, floatVar, intVar, stringVar);
|
格式说明由“%+转换符”组成,转换符是一个指定输出数据类型的字符。同时,你可以在“%”和转换符之间有选择地添加其他标记。想了解更多关于转换符标记的信息,可以参阅java.util.Formatter。下面给出一个基本用法的例子:
1
2
|
int
i =
461012
;
System.out.format(
"The value of i is: %d%n"
, i);
|
“%d”代表了十进制数据(在这里值i),“%n”代表了输出换行,所以其输出如下:
The value of i is: 461012
为了适应各地语言的使用习惯,java重载了printf和format方法,如下:
public PrintStream format(Locale l, String format, Object... args)
如在法国,输出的带有小数的数据时,是用“,”划分整数和小数的,如下面的代码:
1
2
3
4
5
|
float
floatVar =
123
.37f;
int
intVar =
123
;
StringstringVar =
"123"
;
System.out.format(Locale.FRANCE,
"The value of the float "
+
"variable is %f, while the "
+
"value of the integer variable "
+
"is %d, and the string is %s%n"
, floatVar, intVar, stringVar);
|
其输出如下:
The value of the float variable is 123,370003, while the value of the integer variable is 123, and the string is123
Demo:格式化输出
在这个Demo里,使用到各种常用的转化符和flags,具体解释如下表:(更多格式可参阅java.util.Formatter)
Converters and Flags Used indemo.java |
||
转换符 |
Flag |
说明 |
d |
十进制数据 |
|
f |
浮点数据 |
|
n |
换行符。注意是用“%n”,而不是“\n”. |
|
tB,tb |
‘t’指日期/时间的转换(下同),’B’指月份全称(如January),’b’指月份的简称(如Jan) |
|
ty, tY |
格式年份,‘y’指格式化时带前导零的两位数,即00 – 99;’Y’指格式化时带前导零的四位数(至少),如0096或者2013。 |
|
tm |
格式月份,’m’指格式时带前导零的两位数,即01 ~ 13. |
|
td, te |
‘t’指日期/时间的转换,’d’指一个月中的天数,在格式化时带前导零的两位数,即01 – 31;‘e’指格式化为两位数,即1 – 31。 |
|
tl,tk |
格式小时数,’l’指12小时制(1 ~ 12),’k’指24小时制(0 ~ 23)。 |
|
tM |
格式分钟数,’M’指格式化时带前导零的两位数,即00 ~ 59。 |
|
tS |
格式化秒,格式化时带前导零的两位数,即00 - 60("60" 是支持闰秒所需的一个特殊值)。 |
|
tp |
特定于语言环境的上午或下午,标记以小写形式表示,例如 "am" 或 "pm"。 |
|
tD |
A date & time conversion—date as %tm%td%ty |
|
08 |
8个字符宽度,宽度不足在头部以“0”填充 |
|
+ |
包含符号位(正数+或负数—) |
|
, |
组分隔符 |
|
- |
左对齐(默认是右对齐) |
|
.3 |
保留3位小数 |
|
10.3 |
表示10个字符宽度,保留三位小数(默认右对齐) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import
java.util.Calendar;
import
java.util.Locale;
public
class
IntegerText {
public
static
void
main(String[] args) {
long
n =
461012
;
System.out.format(
"%d%n"
, n);
// --> "461012"
System.out.format(
"%08d%n"
, n);
// --> "00461012"
System.out.format(
"%+8d%n"
, n);
// --> " +461012"
System.out.format(
"%,8d%n"
, n);
// --> " 461,012"
System.out.format(
"%+,8d%n%n"
, n);
// --> "+461,012"
double
pi = Math.PI;
System.out.format(
"%f%n"
, pi);
// --> "3.141593"
System.out.format(
"%.3f%n"
, pi);
// --> "3.142"
System.out.format(
"%10.3f%n"
, pi);
// --> " 3.142"
System.out.format(
"%-10.3f%n"
, pi);
// --> "3.142"
System.out.format(Locale.FRANCE,
"%-10.4f%n%n"
, pi);
// --> "3,1416"
Calendar c = Calendar.getInstance();
System.out.format(
"%tB %te, %tY%n"
, c, c, c);
// --> "May 29, 2006"
System.out.format(
"%tl:%tM %tp%n"
, c, c, c);
// --> "2:34 am"
System.out.format(
"%tD%n"
, c);
// --> "05/29/06"
}
}
|
TheDecimalFormat Class
可以使用java.text.DecimalFormat格式化十进制数字的输出,包括前/后导零、前后缀、组分隔符、小数点。尽管使用DecimalFormat可以灵活控制输出的格式,另一面它也增加了代码的复杂度。
如下:通过模式patten构造DecimalFormat的对象myFormatter,接着调用format()方法(从NumberFormat继承过来的),格式化输出字符串。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
java.text.*;
public
class
DecimalFormatDemo {
static
public
void
customFormat(String pattern,
double
value) {
DecimalFormat myFormatter =
new
DecimalFormat(pattern);
String output = myFormatter.format(value);
System.out.println(value +
" "
+ pattern +
" "
+ output);
}
static
public
void
main(String[] args) {
customFormat(
"###,###.###"
,
123456.789
);
//-->123456.789 ###,###.### 123,456.789
customFormat(
"###.##"
,
123456.789
);
//-->123456.789 ###.## 123456.79
customFormat(
"00.000"
,
123.7876
);
//-->123.7876 00.000 123.788
customFormat(
"$###,###.###"
,
12345.67
);
//-->12345.67 $###,###.### $12,345
}
}
|
|
|||
数值 |
Pattern |
输出 |
说明 |
123456.789 |
###,###.### |
123,456.789 |
‘#’ 代表了一个阿拉伯数字,‘,’为组分隔符,‘.’用于分割整数和小数 |
123456.789 |
###.## |
123456.79 |
数值有三位小数,而模式里只用两个,会通过四舍五入保留两位小数 |
123.78 |
000000.000 |
000123.780 |
‘0’代表了一个阿拉伯数字,位数不足需要在前或后一零补充,注意其与‘#’的区别。 |
12345.67 |
$###,###.### |
$12,345.67 |
以美元符号‘$’开头,保留三位小数,且组分割为3 |
tips:组分隔符“,”通常用于千位,但是在某些国家/地区中回用于分隔万位(如中国)。分组大小是分组字符之间的固定数字位数,例如100,000,000 是 3,而 1,0000,0000 则是 4。如果使用具有多个分组字符的模式,则最后一个分隔符和整数结尾之间的间隔才是使用的分组大小。所以 "#,##,###,####" == "######,####" =="##,####,####"。 即“123456.789”的模式为“###,#,##.###”,其输出为“12,34,56.789”。
基本算数运算之外
java除了支持各种基本的算术运算(+, -, *, /, 和 %)之外,也为各种复杂的数学运算提供了工具类Math。通过Math类可以完成指数、对数、反三角函数等复杂的运算。
由于Math类的方法都是静态的,你可以在类里直接调用Math类的方法,如下:
Math.cos(angle);
tips:可以使用static import静态导入Math类,如此便不用在每个方法下上Math;import static java.lang.Math.*;
接着就可以直接在方法体里通过Math类的方法名调用Math类对应的方法:
cos(angle);
常量与基本算术方法
在Math类里包含两个常量:
-
Math.E, 自然底数e
-
Math.PI,圆周率
Math类包含了超过40个的静态方法,为了分类来谈,先列出Math里的基本算术方法:
Math的基本算术方法 |
|
方法 |
描述 |
double abs(double d) |
返回参数的绝对值 |
double ceil(double d) |
取得大于或等于参数的最小整数,并以double类型返回 |
double floor(double d) |
取得小于或等于参数的最大整数,并以double类型返回 |
double rint(double d) |
取得最接近参数的某一整数(类似于四舍五入),并以double类型返回 |
long round(double d) |
返回最接近参数的 |
double min(double arg1, double arg2) |
返回两个数中较小的那一个 |
double max(double arg1, double arg2) |
返回两个数中较大的那一个 |
BasicMathDemo演示了如何去使用Math的基本算术方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public
class
BasicMathDemo {
public
static
void
main(String[] args) {
double
a = -
191.635
;
double
b =
43.74
;
int
c =
16
, d =
45
;
System.out.printf(
"The absolute value "
+
"of %.3f is %.3f%n"
,
a, Math.abs(a));
//-->The absolute value of -191.635 is 191.635
System.out.printf(
"The ceiling of "
+
"%.2f is %.0f%n"
,
b, Math.ceil(b));
//-->The ceiling of 43.74 is 44
System.out.printf(
"The floor of "
+
"%.2f is %.0f%n"
,
b, Math.floor(b));
//-->The floor of 43.74 is 43
System.out.printf(
"The rint of %.2f "
+
"is %.0f%n"
,
b, Math.rint(b));
//-->The rint of 43.74 is 44
System.out.printf(
"The max of %d and "
+
"%d is %d%n"
,
c, d, Math.max(c, d));
//-->The max of 16 and 45 is 45
System.out.printf(
"The min of of %d "
+
"and %d is %d%n"
,
c, d, Math.min(c, d));
//-->The min of of 16 and 45 is 16
}
}
|
Math里指数与对数运算:
下表列出了在Math里关于指数与对数运算的方法:
指数、对数运算的方法 |
|
方法 |
描述 |
double exp(double d) |
返回自然底数e的d次方幂的值 |
double log(double d) |
返回 |
double pow(double base, double exponent) |
返回base的exponent次方的值 |
double sqrt(double d) |
返回d的算术平方根 |
Demo:ExponentialDemo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
ExponentialDemo {
public
static
void
main(String[] args) {
double
x =
11.635
;
double
y =
2.76
;
System.out.printf(
"The value of "
+
"e is %.4f%n"
,
Math.E);
//-->The value of e is 2.7183
System.out.printf(
"exp(%.3f) "
+
"is %.3f%n"
,
x, Math.exp(x));
//-->exp(11.635) is 112983.831
System.out.printf(
"log(%.3f) is "
+
"%.3f%n"
,
x, Math.log(x));
//-->log(11.635) is 2.454
System.out.printf(
"pow(%.3f, %.3f) "
+
"is %.3f%n"
,
x, y, Math.pow(x, y));
//-->pow(11.635, 2.760) is 874.008
System.out.printf(
"sqrt(%.3f) is "
+
"%.3f%n"
,
x, Math.sqrt(x));
//-->sqrt(11.635) is 3.411
}
}
|
Math里三角函数运算
下表列出了Math里关于三角函数的方法,需要注意的是,这些方法的参数都是以弧度制来表示的——换句话说就是,你需要将角度转换为弧度。可以使用方法toRadians(),将角度转换为弧度。
三角函数运算的方法 |
|
方法 |
描述 |
double sin(double d) |
返回角的三角正弦值 |
double cos(double d) |
返回角的三角余弦值 |
double tan(double d) |
返回角的三角正切值 |
double asin(double d) |
返回一个值的反正弦值;返回的角度范围在 -pi/2 到pi/2 之间。 |
double acos(double d) |
返回一个值的反余弦值;返回的角度范围在 0.0 到pi之间。 |
double atan(double d) |
返回一个值的反正切值;返回的角度范围在 -pi/2 到pi/2 之间。 |
double atan2(double y, double x) |
将矩形坐标 ( |
double toDegrees(double d) |
角度和与弧度的相互转换方法 |
Demo:TrigonometricDemo, 计算45度角的三角函数值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public
class
TrigonometricDemo {
public
static
void
main(String[] args) {
double
degrees =
45.0
;
double
radians = Math.toRadians(degrees);
System.out.format(
"The value of pi "
+
"is %.4f%n"
,Math.PI);
//-->The value of pi is 3.1416
System.out.format(
"The sine of %.1f "
+
"degrees is %.4f%n"
,
degrees,Math.sin(radians));
//-->The sine of 45.0 degrees is 0.7071
System.out.format(
"The cosine of %.1f "
+
"degrees is %.4f%n"
,
degrees, Math.cos(radians));
//-->The cosine of 45.0 degrees is 0.7071
System.out.format(
"The tangent of %.1f "
+
"degrees is %.4f%n"
,
degrees, Math.tan(radians));
//-->The tangent of 45.0 degrees is 1.0000
System.out.format(
"The arcsine of %.4f "
+
"is %.4f degrees %n"
,
Math.sin(radians), Math.toDegrees(Math.asin(Math.sin(radians))));
//-->The arcsine of 0.7071 is 45.0000 degrees
System.out.format(
"The arccosine of %.4f "
+
"is %.4f degrees %n"
,
Math.cos(radians), Math.toDegrees(Math.acos(Math.cos(radians))));
//-->The arccosine of 0.7071 is 45.0000 degrees
System.out.format(
"The arctangent of %.4f "
+
"is %.4f degrees %n"
,
Math.tan(radians), Math.toDegrees(Math.atan(Math.tan(radians))));
//-->The arctangent of 1.0000 is 45.0000 degrees
}
}
|
随机数
Math类的random()方法可以产生大于等于0.0
且小于1.0
的(伪)随机数(0 <= Math.random()<1),如此,你便能利用这个函数产生各中范围的随机数,如
要产生0~9的随机数:
1
|
int
number = (
int
)(Math.random() *
10
);
//(0 <= number < 10)
|
如产生5~9的随机数:
1
|
int
number = (
int
)(Math.random() *
5
) +
5
;
|
附:使用Math.random()可以产生一个随机数。如果需要产生一系列随机数,可以创建 java.util.Random的对象,并调用对应的方法。