《疯狂java讲义》学习(23):常用类
常用类
Java提供少了一些经常使用的类,如String、Math、BigDecimal等用法
Object类
Object类是所有类、数组、枚举类的父类,也就是说,Java允许把任何类型的对象赋给Object类型的变量。当定义一个类时没有使用extends关键字为它显示指定父类,则该类默认继承Object父类。
因为所有的Java类都是Object类的子类,所以任何Java对象都可以调用Object类的方法。Object类提供了如下几个常用方法。
- boolean equals(Object obj):判断指定对象与该对象是否相等。此处相等的标准是,两个对象是同一个对象,因此该equals()方法通常没有太大的实用价值。
- protected void finalize():当系统中没有引用变量引用到该对象时,垃圾回收器调用此方法来清理该对象的资源。
- Class<?> getClass():返回该对象的运行时类,该方法在以后会介绍
- int hashCode():返回该对象的hashCode值。在默认情况下,Object类的hashCode()方法根据该对象的地址来计算(即与System.identityHashCode(Object x)方法的计算结果相同)。但很多类都重写了Object类的hashCode()方法,不再根据地址来计算其hashCode()方法值。
- String toString():返回该对象的字符串表示,当我们使用System.out.println()方法输出一个对象,或者把某个对象和字符串进行连接运算时,系统会自动调用该对象的toString()方法返回该对象的字符串表示。Object类的toString()方法返回“运行时类名@十六进制hashCode值”格式的字符串,但很多类都重写了Object类的toString()方法,用于返回可以表述该对象信息的字符串。
除此之外,Object类还提供了wait()、notify()、notifyAll()几个方法,通过这几个方法可以控制线程的暂停和运行。
Java还提供了一个protected修饰的clone()方法,该方法用于帮助其他对象来实现“自我克隆”,所谓“自我克隆”就是得到一个当前对象的副本,而且二者之间完全隔离。由于Object类提供的clone()方法使用了protected修饰,因此该方法只能被子类重写或调用。
自定义类实现“克隆”的步骤如下:
- 自定义类实现Cloneable接口。这是一个标记性的接口,实现该接口的对象可以实现“自我克隆”,接口里没有定义任何方法。
- 自定义类实现自己的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); //①
// 判断u1、u2的address是否相同
System.out.println(u1.address==u2.address); //②
}
}
上面程序让User类实现了Cloneable接口,而且实现了clone()方法,因此User对象就可实现"自我克隆"——克隆出来的对象原有对象的副本。程序在①号粗体字代码处判断原有的User对象与克隆出来的User对象是否相同,程序返回false。
Object类提供的Clone机制只对对象里各实例变量进行“简单复制”,如果实例变量的类型是引用类型,Object的Clone机制也只是简单地复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例,所以上面程序在②号代码处输出true。
Object类提供的clone()方法不仅能简单地处理“复制”对象的问题,而且这种“自我克隆”机制十分高效。比如clone一个包含100个元素的int[]数组,用系统默认的clone方法比静态copy方法块近2倍。
需要指出的是,Object类的clone()方法虽然简单、易用,但它只是一种“浅克隆”——它只克隆该对象的所有Field值,不会对引用类型的Field值所引用的对象进行克隆。如果开发者需要对对象进行“深克隆”,则需要开发者自己进行“递归”克隆,保证所有引用类型的Field值所引用的对象都被复制了。
String、StringBuffer和StringBuilder类
字符串就是一连串的字符序列,Java提供了String和StringBuffer两个类来封装字符串,并提供了一系列方法来操作字符串对象。
String类时不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符序列时不可改变的,直至这个对象被销毁。
StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
StringBuilder类,也代表字符串对象。实际上,StringBuilder和StringBuffer基本相似,两个类的构造器和方法也基本相同。不同的是,StringBuffer是线程安全的,而StringBuilder则没有实现线程安全功能,所以性能略高。因此在通常情况下,如果需要创建一个内容可变的字符串对象,则应该优先考虑使用StringBuilder类。
String类提供了大量构造器来创建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, int offset, int count):将指定的字符数组从offset开始、长度为count的字符元素连缀成字符串。
- String(String original):根据字符串直接量来创建一个String对象。也就是说,新创建的String对象是该参数字符串的副本。
- String(StringBuffer buffer):根据StringBuffer对象来创建对应的String对象。
- String(StringBuilder builder):根据StringBuilder对象来创建对应的String对象。
+类也提供了大量方法来操作字符串对象,下面详细介绍这些常用方法。 - char charAt(int index):获取字符串中指定位置的字符。其中,参数index指的是字符串的序数,字符串的序数从0开始到length()-1。如下代码所示:
String s=new String("abcdefghijklmnopqrstuvwxyz");
System.out.println("s.charAt(5): " + s.charAt(5) );
结果为:
s.charAt(5): f
- int compareTo(String anotherString):比较两个字符串的大小。如果两个字符串的字符序列相等,则返回 0;不相等时,从两个字符串第 0个字符开始比较,返回第一个不相等的字符差。另一种情况,较长字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。
String s1=new String("abcdefghijklmn");
String s2=new String("abcdefghij");
String s3=new String("abcdefghijalmn");
System.out.println("s1.compareTo(s2): " + s1.compareTo(s2) );//返回长度差
System.out.println("s1.compareTo(s3): " + s1.compareTo(s3) );//返回'k'-'a'的差
结果为:
s1.compareTo(s2):4
s1.compareTo(s3):10
- String concat(String str):将该String对象与str连接在一起。与Java提供的字符串连接运算符“+”的功能相同。
- boolean contentEquals(StringBuffer sb):将该String对象与StringBuffer对象sb进行比较,当它们包含的字符序列相同时返回true。
- static String copyValueOf(char[] data):将字符数组连缀成字符串,与String[char[] content]构造器的功能相同。
- static String copyValueOf(char[] data, int offset, int count):将char数组的子数组中的元素连缀成字符串,与String(char[] value, int offset, int count)构造器的功能相同。
- boolean endsWith(String suffix):返回该String对象是否以suffix结尾。
String s1=new String("abcdefghij");
String s2=new String("ghij");
System.out.println("s1.endsWith(s2): " + s1.endsWith(s2) );
结果为:
s1.endsWith(s2):true
- boolean equals(Object anObject):将该字符串与指定对象比较,如果二者包含的字符序列相等,则返回true;否则返回false。
- boolean equalsIgnoreCase(String str):与前一个方法基本相似,只是忽略字符的大小写。
- byte[] getBytes():将该String对象转换成byte数组。
- void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):该方法将字符串中从srcBegin开始,到srcEnd结束的字符复制到dst字符数组中,其中dstBegin为目标字符数组的起始复制位置。
char[] s1={'I',' ','l','o','v','e',' ','j','a','v','a'}; //s1=I love java
String s2=new String("ejb");
s2.getChars(0,3,s1,7); //s1=I love ejba
System.out.println( s1 );
- 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开始后第一次出现的位置:
String s=new String("write once, run anywhere!");
String ss=new String("run");
System.out.println("s.indexOf('r'): " + s.indexOf('r') );
System.out.println("s.indexOf('r',2): " + s.indexOf('r',2) );
System.out.println("s.indexOf(ss): " + s.indexOf(ss) );
- 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替换成newChar。
- boolean startsWith(String prefix):该String对象是否以prefix开始。
- boolean startsWith(String prefix, int toffset):该String对象从toffset位置算起,是否以prefix开始:
String s=new String("write once, run anywhere!");
String ss=new String("write");
String sss=new String("once");
System.out.println("s.startsWith(ss): " + s.startsWith(ss) );
System.out.println("s.startsWith(sss,6): " + s.startsWith(sss,6) );
- 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对象的方法。
StringBuilder提供了一系列插入、追加、改变该字符串里包含的字符序列的方法。而StringBuffer与其用法完全相同,只是StringBuffer是线程安全的。
StringBuilder、StringBuffer有两个属性:length和capacity,其中length属性表示其包含的字符序列的长度。与String对象的length不同的是,StringBuilder、StringBuffer的length是可以改变的,可以通过length()、setLength(int len)方法来访问和修改其字符序列的长度。capacity属性表示StringBuilder的容量, capacity通常比length大,程序通常无须关心capacity属性。如下程序示范了StringBuilder类的用法:
public class StringBuilderTest
{
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);
}
}
上面程序中粗体字部分示范了StringBuilder类的追加、插入、替换、删除等操作,这些操作改变了StringBuilder里的字符序列,这就是StringBuilder与String之间最大的区别:StringBuilder的字符序列时可变的。从程序开到StringBuilder的length()方法返回其字符序列的长度,而capacity()返回值则比length()返回值大。
Math类
Java提供了基本的+、-、*、/、%等基本算术运算的运算符,但对于更复杂的数学运算,例如,三角函数、对数运算、指数运算等则无能为力。Java提供了Math工具类来完成这些复杂的运算,Math类是一个工具类,它的构造器被定义成private的,因此无法创建Math类的对象;Math类中的所有方法都是类方法,可以直接通过类名来调用它们。Math类除了提供了大量静态方法之外,还提供了两个静态Field:PI和E,正如它们名字所暗示的,它们的值分别等于π和e。
Math类的所有方法名都明确标识了该方法的作用,读者可自行查阅API来了解Math类各方法的说明。下面程序示范了Math类的用法:
public class MathTest
{
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());
}
}
上面程序中关于Math类的用法几乎覆盖了Math类的所有数学计算功能,读者可参考上面程序来学习Math类的用法。
ThreadLocalRandom与Random类
Random类专门用于生成一个伪随机数,它有两个构造器:一个构造器使用默认的种子(以当前时间作为种子),另一个构造器需要程序员显式传入一个long型整数的种子。
ThreadLocalRandom类,它是Random的增强版。在并发访问的环境下,使用ThreadLocalRandom来代替Random可以减少多下称资源竞争,最终保证系统具有较好的性能。
ThreadLocalRandom类的用法与Random类的用法基本相似,它提供了一个静态的current()方法来获取ThreadLocalRandom对象,获取该对象之后即可调用各种nextXxx()方法来获取伪随机数了。
ThreadLocalRandom与Random都比Math的random()方法提供了更多的方式来生成各种伪随机数,可以生成浮点类型的伪随机数,也可以生成整数类型的伪随机数,还可以指定生成随机数的范围:
import java.util.*;
public class RandomTest {
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.0~1.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可以提供很多选项来生成伪随机数。
Random使用一个48位的种子,如果这个类的两个实例时用同一个种子创建的,对他们以同样的顺序调用方法,则他们会产生相同的数字序列。
下面就对上面的介绍做一个实验,可以看到当两个Random对象种子相同时,他们会产生相同的数字序列。指的指出的,当使用默认的种子构造Random对象时,它们属于同一个种子:
import java.util.*;
public class SeedTest {
public static void main(String[] args){
Random r1=new Random(50);
System.out.println("第一个种子为50的Random对象");
System.out.println("r1.nextBoolean():\t" + r1.nextBoolean());
System.out.println("r1.nextInt():\t\t" + r1.nextInt());
System.out.println("r1.nextDouble():\t" + r1.nextDouble());
System.out.println("r1.nextGaussian():\t" + r1.nextGaussian());
System.out.println("---------------------------");
Random r2=new Random(50);
System.out.println("第二个种子为50的Random对象");
System.out.println("r2.nextBoolean():\t" + r2.nextBoolean());
System.out.println("r2.nextInt():\t\t" + r2.nextInt());
System.out.println("r2.nextDouble():\t" + r2.nextDouble());
System.out.println("r2.nextGaussian():\t" + r2.nextGaussian());
System.out.println("---------------------------");
Random r3=new Random(100);
System.out.println("种子为100的Random对象");
System.out.println("r3.nextBoolean():\t" + r3.nextBoolean());
System.out.println("r3.nextInt():\t\t" + r3.nextInt());
System.out.println("r3.nextDouble():\t" + r3.nextDouble());
System.out.println("r3.nextGaussian():\t" + r3.nextGaussian());
}
}
从上面运行结果来看,如果两个Random对象的种子相同,而且方法的调用顺序也相同,则他们会产生相同的数字序列。也就是说,Random产生的数字并不是真正随机的,而是一种伪随机,为了避免两个Random对象产生相同的数字序列,通常推荐使用当前时间作为Random对象的种子,如下代码所示:
Random rand=new Random(System.currentTimeMillis());
在多线程环境下使用ThreadLocalRandom的方式与使用Random基本类似,如下程序片段示范了ThreadLocalRandom的用法:
ThreadLocalRandom rand=ThreadLocalRandom.current();
// 生成一个4~20之间的伪随机整数
int val1=rand.nextInt(4 , 20);
// 生成一个2.0~10.0之间的伪随机浮点数
int val2=rand.nextDouble(2.0, 10.0);
java实例练习
高精度的运算
为了弥补虚拟机在高精度计算方面的不足,Java推出了BigInteger类,BigDecimal类,它可以用来完成任意精度的整数运算。本实例将演示其基本的四则运算:
高精度浮点运算
新建项目MathBigInteger,并在其中创建一个MathBigInteger.java文件。在该类的主方法中创建两个MathBigInteger对象,并演示基本的四则运算:
package MathBigInteger;
import java.math.BigInteger;
public class MathBigInteger {
public static void main(String[] args){
BigInteger number1 = new BigInteger("123456"); //声明高精度整数number1
BigInteger number2 = new BigInteger("654321"); //声明高精度整数number2
BigInteger addition = number1.add(number2); //计算number1加number2
BigInteger subtraction = number1.subtract(number2); //计算number1减number2
BigInteger multiplication = number1.multiply(number2); //计算number1乘number2
BigInteger division = number1.divide(number2); //计算number1除number2
System.out.println("高精度整数number1:" + number1);
System.out.println("高精度整数number2:" + number2);
System.out.println("高精度整数加法:" + addition);
System.out.println("高精度整数减法:" + subtraction);
System.out.println("高精度整数乘法:" + multiplication);
System.out.println("高精度整数除法:" + division);
}
}
BigInteger类可以表示不变的、任意精度的整数。所有操作中,都以二进制补码形式表示BigInteger。BigInteger提供了所有Java的基本整数类型操作符的对应物,并提供了java.lang.Math的所有相关方法。本实例中使用BigInteger类的add()、subtract()、multiply()和divide()方法实现了加、减、乘、除四则运算。
高精度浮点运算
新建项目MathBigDecimal,并在其中创建一个MathBigDecimal.java文件。在该类的主方法中创建两个MathBigDecimal对象,并演示基本的四则运算:
import java.math.BigDecimal;
import java.math.RoundingMode;
public class MathBigDecimal {
public static void main(String[] args) {
BigDecimal number1 = new BigDecimal(3.1415); //声明高精度浮点数number1
BigDecimal number2 = new BigDecimal(1.2345); //声明高精度浮点数number2
BigDecimal addition = number1.add(number2); // 计算number1加number2
BigDecimal subtraction = number1.subtract(number2); // 计算number1减number2
BigDecimal multiplication = number1.multiply(number2);
// 计算number1乘number2
// 以四舍五入的方式获得高精度除法运算的结果
BigDecimal division = number1.divide(number2, RoundingMode.HALF_UP);
System.out.println("高精度浮点数number1:" + number1);
System.out.println("高精度浮点数number2:" + number2);
System.out.println("高精度浮点数加法:" + addition);
System.out.println("高精度浮点数减法:" + subtraction);
System.out.println("高精度浮点数乘法:" + multiplication);
System.out.println("高精度浮点数除法:" + division);
}
}
运行上面程序,结果如下:
高精度浮点数number1:3.141500000000000181188397618825547397136688232421875
高精度浮点数number2:1.2344999999999999307220832633902318775653839111328125
高精度浮点数加法:4.3760000000000001119104808822157792747020721435546875
高精度浮点数减法:1.9070000000000002504663143554353155195713043212890625
高精度浮点数乘法:3.8781817500000000060405014323805391527821713030086874448250692203055134399392045452259480953216552734375
高精度浮点数除法:2.544754961522884048184463311690970190997595968556798
BigDecimal表示不可变的、任意精度的有符号十进制数。Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。本实例中使用BigDecimal类的add()、subtract()、multiply()和divide()方法实现了加、减、乘、除四则运算。
使用BigDecima类虽然能大幅度提高运算的精度,但是这是建立在牺牲计算机性能的基础上的。因此,对于普通运算我们也不推荐使用BigDecimal类。另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。
不重复的进行随机数组排序
随机数组就是在指定长度的数组中用随机数字为每个元素赋值,这常用于需要不确定数值的环境,如拼图游戏需要随机数组来打乱图片排序。可随机数的重复问题也同时存在,利用TreeSet集合实现不重复的数列,并自动完成元素的排序,然后生成数组:
1.
新建项目NoRepeatRandom,并在其中创建一个NoRepeatRandom.java文件。在该类的主方法中创建TreeSet对象,再创建Random随机数,然后通过计数器控制循环生成随机数并添加到集合对象中,最后通过集合对象提取数组并显示在控制台中:
package NoRepeatRandom;
import java.util.*;
public class NoRepeatRandom {
public static void main(String[] args){
TreeSet<Integer> set=new TreeSet<Integer>(); //创建TreeSet集合对象
Random ran = new Random(); //创建随机对象
int count=0; // 定义随机数计数器
while (count < 10){ //循环生成随机数
boolean succeed = set.add(ran.nextInt(100)); //为集合添加数字
if (succeed) // 累加成功添加到集合中数字的数量
count++;
}
int size = set.size(); //获取集合大小
Integer[] array = new Integer[size]; //创建同等大小的数组
set.toArray(array); //获取集合中的数组
System.out.println("生成的重复随机数组内容如下:");
for (int value : array){ //遍历输出数组内容
System.out.print(value + " ");
}
}
}
集合又称为容器,简单地说,它是一个对象,能将具有相同性质的多个元素汇聚成一个整体。集合被用于存储、获取、操纵和传输聚合的数据。
Java集合框架提供了有效的数据结构和算法,因此程序员不需要自己编写代码实现这些功能。而且结合框架对各个接口的实现是可以互换的,因此很容易转换接口。这样就提高了软件的复用性。Java平台提供了一个全新的集合框架。集合框架的核心接口为Collection、List(列表)、Set(集合)和Map(映射)。