Java常用类知识概括

字符串相关的类

String简介:

  • String类:代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作 为此类的实例实现。
  • String是一个final类,代表不可变的字符序列。
  • 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
  • String对象的字符内容是存储在一个字符数组value[]中的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0

String在JVM中:

  • 字符串常量存储在字符串常量池,目的是共享。字符串非常量对象存储在堆中。
  • 结论:
    常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。 只要其中有一个是变量,结果就在堆中。
    如果拼接的结果调用intern()方法,返回值就在常量池中。

String常用方法:

  • int length():返回字符串的长度: return value.length

  • char charAt(int index): 返回某索引处的字符return value[index]

  • boolean isEmpty():判断是否是空字符串:return value.length == 0

  • String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写

  • String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写

  • String trim():返回字符串的副本,忽略前导空白和尾部空白

  • boolean equals(Object obj):比较字符串的内容是否相同

  • boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写

  • String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”

  • `int compareTo(String anotherString):``比较两个字符串的大小

  • String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。

  • String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

  • boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束

  • boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始

  • boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始

  • boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true

  • int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引

  • int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始

  • int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引

  • int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
    ①注:indexOf和lastIndexOf方法如果未找到都是返回-1

  • String replace(char oldChar, char newChar):返回一个新的字符串,它是 通过用 newChar替换此字符串中出现的所有 oldChar 得到的。

  • String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。

  • String replaceAll(String regex, String replacement) : 使用给定的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

  • String replaceFirst(String regex, String replacement) : 使用给定的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。

  • boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。

  • String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
    ①String有个方法是分割字符串 .split()。但是有写字符串是需要转义才能分割,不然就会出错。
    ②需要转义的字符串:. $ | ( ) [ { ^ ? * + \ 共12个特殊字符,遇到以这些字符进行分割字符串的时候,需要在这些特殊字符前加双反斜杠 \

  • String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

  • String format(String fmt, Object...args):该方法使用指定的字符串格式和参数生成格式化的新字符串。 新字符串始终使用本地语言环境

  • String format(Locale locale, String fmt, Object... args):该方法使用指定的语言环境、字符串格式和参数生成一个格式化的新字符串。新字符串始终使用指定的语言环境。

Java格式化输出:

  • 在javaSE 5.0 沿用了C语言的格式化输出printf()方法,可以用的方法有:
    ①String的format()方法
    ②System.out的println()方法
  • 常用的格式化符号:
    ①%s: 字符串类型,如:“ljq”
    ②%b: 布尔类型,如:true
    ③%d: 整数类型(十进制),如:99
    ④%f: 浮点类型,如:99.99
    ⑤%%: 百分比类型,如:%
    ⑥%n: 换行符
  • 链接:Java格式化输出用法

String的底层结构

  • String的底层结构是一个final类型的char数组。这意味着一旦创建了这个String实例,底层的char数组就不可以再指向别的引用,也不可以扩容。但是我们创建的String对象还是可以指向别的引用的。但是为什么String是不可变的呢,因此String类没有提供修改器方法。那我们可以通过继承String类手动实现修改器方法么,不可以。因此String类是final的,即不可继承的。
  • 另外当我们创建一个String对象时,如String str = “hello”,内存不会在堆中创建对象,而是在方法区中的常量池寻找,有没有相同对象,若没有,则在常量池中创建一个。只有显示地调用构造器方法 String s1 = new String( “hello”);。内存才会在堆中创建一个对象,但是内存中的对象还是指向常量池中的同名对象。(相当于在给予这个对象在堆中一个新地址)
  • 最后当我们String str = “hello”+“world”时返回的对象还是在常量池中,但我们String str = “hello”,String world = str+“world”时返回的对象则会在堆中创建一个对象。但如果最后我们调用intern()方法,返回的对象就在常量池中。

String与字节数组与字符数组

简介:

  • 字符数组→ 字符串
    ①String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
  • 字符串→字符数组
    ①public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。
    ②public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
  • 字节数组→ 字符串
    ①String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。 ②String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象。
  • 字符串→ 字节数组
    ①public byte[] getBytes() :使用平台的默认字符集将此 String 编码为byte 序列,并将结果存储到一个新的 byte 数组中。
    ②public byte[] getBytes(String charsetName) :使用指定的字符集将此String编码到 byte 序列,并将结果存储到新的 byte 数组。

注意:

  • 当把String转换成字节数组时,这种过程叫编码(就是把人类看得懂的编码成机器语言)
  • 当把字节数组转换成String时, 这种过程叫解码(就是把机器语言解码成人类看得懂的)
  • 在这里面涉及编码集----------charset,此外码是针对计算机而言。

String编码,解码总结:

  • jsp以get方式url传递数据的时候,因为Tomcat默认是以ISO8859-1形式传递的,若中文传递到servlet,我们直接request.getParameter()得到的字符串会乱码。因为中间Tomcat会把我们的url以ISO8859-1编码进行urlEncode,我们后台得到数据后再以ISO8859-1解码,我们request.getParameter()得到的字符串对象就不我们想要的东西。这个时候只要逆着来一遍得到以原先编码的二进制,然后再new String即可 new String(str.getBytes(“ISO8859-1”),“原来的编码”); 即可得到正确的。
  • 上述过程其实是这样的:
    ①我们发送的数据,str是utf-8字符串,二进制是:-28-67-96-27-91-67(‘你好’)
    ②tomcat把它的二进制编码用ISO8859-1进行读后new了个String str2 =(str.getBytes(“utf-8”),“ISO8859-1”),虽然这个字符串二进制还是-28-67-96-27-91-67,但str2里储存的读取方式是ISO8859-1肯定乱码(因为ISO8859-1字符集只包含少部分中文)。
    ③我们得到这个乱码字符串str2后,首先,str.getBytes(“ISO8859-1”),因为str2对象里储存的编码方式就是ISO8859-1,所以不会改变二进制,也就是说得到是还是-28-67-96-27-91-67,这个是原来utf-8下的“你好”,现在只要再new String(那个byte数组,“utf-8”);即可还原。
  • 链接:java中字符串编码的转换以及乱码后的处理总结

StringBuffer和StringBuilder

StringBuffer类:

  • java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象。
  • 很多方法与String相同。
  • 作为参数传递时,方法内部可以改变值。
---------------------------底层结构------------------------------
abstract class AbstractstringBuilder implements Appendable,charSequence {
	//value没有final声明,value可以不断扩容。
	char[] value;
	
	//count记录有效字符的个数。
	int count;
}
  • StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:
    ①StringBuffer():初始容量为16的字符串缓冲区
    ②StringBuffer(int size):构造指定容量的字符串缓冲区
    ③StringBuffer(String str):将内容初始化为指定字符串内容
  • StringBuffer类的常用方法:
    StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
    StringBuffer delete(int start,int end):删除指定位置的内容
    StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
    StringBuffer insert(int offset, xxx):在指定位置插入xxx
    StringBuffer reverse() :把当前字符序列逆转
    public int indexOf(String str)
    public String substring(int start,int end)
    public int length()
    public char charAt(int n )
    public void setCharAt(int n ,char ch)
    public String toString():若不添加字符串,默认返回为空串。
  • 注意:
    ①当append和insert时,如果原来value数组长度不够,可扩容。
    ②如上这些方法支持方法链操作。方法链的原理:
@override
public StringBuilder append( String str) i
	super.append( str) ;
	return this;
}

StringBuilder类:

  • StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且 提供相关功能的方法也一样
  • 面试题:对比String、StringBuffer、StringBuilder:
    ①String(JDK1.0):不可变字符序列
    ②StringBuffer(JDK1.0):可变字符序列、效率低、线程安全
    ③StringBuilder(JDK 5.0):可变字符序列、效率高、线程不安全
    注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder 会改变其值

CharSequence接口

简述:

  • CharSequence类型:这是一个接口,代表的是一个有序字符集合。
  • 这个接口包含的方法有:
    ①charAt(int index)
    ②toString()
    ③length()
    ④subSequence(int start,int end).
  • 对于一个抽象类或者是接口类,不能使用new来进行赋值。
    ①可以通过这样方式进行实例的创建:CharSequence cs=“hello”;
    ②不能这样来创建:CharSequence cs=new CharSequence(“hello”);

JDK 8之前的日期时间API

java.lang.System类:

  • System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
  • 此方法适于计算时间差。
  • 计算世界时间的主要标准有:
    ①UTC(Coordinated Universal Time)世界标准时间
    ②GMT(Greenwich Mean Time)格林威治时间
    ③CST(Central Standard Time)美国中央标准时间

java.util.Date类和java.sql.Date类:

  • java.util.Date类中,通过空参构造器可以获取本地时间。
    ①通过toString方法可以打印成一个形似的字符串。
    ②通过getTime方法可以返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。(即时间戳)
  • java.sql.Date类表示数据库里用的时间类,可以通过getTime转换成时间戳来与java.util.Date类相互转换。

java.text.SimpleDateFormat类:

  • 表示格式化类,可以通过创建一个SimpleDateFormat的构造器(若带参数,则表示转换的形式)来创建一个SimpleDateFormat对象,然后调用format方法将Date对象转换成指定形式的字符串。反之通过parse方法把字符串解析回Date对象。

java.util.Calendar(日历)类:

  • java.util.Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
  • 获取Calendar实例方法:
    ①通过Calendar.getInstance()方法。
    ②通过它的子类GregoorianCalander的构造器。
  • 注意:
    ①获取月份时,0表示1月,1表示2月
    ②获取星期时,周日是1,周二是2

日期时间类更迭:

  • 由于Date的可更改性,以及Date存在偏移量,即返回自1970年1月1日后的时间,导致不可直接通过输入所在时间获得所在时间的对象。
  • 以及操作日期和时间的Calendar类中获取月份和日期时返回的索引的不人性化设置,导致人们编写日期类时很麻烦!!!
  • 因此JDK8后引入了一个新的包------Time包

JDK 8中新日期时间API

LocalDate类和LocalDateTime类和LocalTime类:

  • LocalDate类是日期类,LocalDateTime类是日期时间类,LocalTime类是时间类
  • 这些类都是不可变的,其用法也跟Calendar也差不多。
  • 而后面还提供了Instant表示自1970年1月1日以来的时间,即机器时间。
  • formatter表示格式化。
  • 还有zoneid表示时区类,有巴黎时间,日本时间等等。
  • ZonedDateTime表示时区时间,表示的时间与LocalDateTime相比增加了个时区。
  • 还有许多,这里我就不一一介绍了。

注意

  • 在使用某些方法时,要求LocalDateTime要带上时区。因为实例化LocalDateTime时是没有带上时区的,尽管底层实现时是默认当前时区,但是生成时间后该时间是没有时区标志的。
  • 只有带上时区标志才可以算完整时间。毕竟全球化时间时,是要带上时区以及时区偏移量的。
  • 例如:以GMT为例,表示格林威治时间,即伦敦时间。当我们+8偏移量时来到东八区,即北京时间。 要在时这个单位上+8。

总结来说

  • 如果是JDK8的应用,可以使用Instant代替Date。LocalDateTime代替Calendar。DateTimeFormatter代替SimpleDateFormat。
  • 官方给出的解释是:Simple beautiful strong immutable thread-safe。

数据库与JAVA的时间

java(1.6) 中能保存时间日期类型的类主要有:

  • java.util.Date:包含日期时间
  • java.util.Calendar:包含日期时间
  • java.sql.Date:包含日期
  • java.sql.Time:包含时间
  • java.sql.Timestamp:时间戳(自1970年01月01日在伦敦(格林威治)算起)

日期时间类更迭概述:

  • 以前从mysql中查询出来的时间日期类型,都放在java.util.Date类型里面了。这样带来一系列的问题,首先这个类提供的时间操作函数太少,一般都需要转换成java.util.Calendar再去操作;
  • 其次即使使用了java.util.Calendar,也不是很方便,一个很简单的想法,需要写很多代码才能实现;java.util.Date的数据内容为xxxx-xx-xx xx:xx:xx,有时候不需要时间,只需要日期。
  • 从数据库中取值出来的日期类型放到这个类中的时候,会在时间位自动补上当前时间。这使得本来两个日期在数据库中是相等的,取出来放到这个类得时候就不再相等了,需要去考虑时间上的误差,很是头疼。

java提供与mysql方便交互的三种数据类型:

  • java.sql.Date :对应sql里的date
  • java.sql.Time :对应sql里的time
  • java.sql.Timestamp: 对应sql里的timestamp
  • 它们都是继承java.util.Date,算是对该类的精简,很适合跟数据库交互。

java.sql类与数据库的交互:

===========java注入数据库==========
java类型   mysql类型        成功与否
date         date               yes
date         time               no
date         timestamp       no
date         datetime         no

time         date               no
time         time               yes
time         timestamp       no
time         datetime         no

timestamp date              yes
timestamp time              yes
timestamp timestamp     yes
timestamp datetime        yes
==========end java注入数据库========
总规律,如果A完全包含B,则A可以向B注入数据,否则报错
==========从数据库提取到java ==========

mysql类型    java类型     成与否
date             date         yes
date             time         yes --------------缺少的部分使用历元
date           timestamp   yes --------------缺少的部分使用历元  

time           date           yes --------------缺少的部分使用历元
time           time           yes
time          timestamp    yes --------------缺少的部分使用历元

timestamp date           yes
timestamp time           yes
timestamp timestamp   yes

datetime      date         yes
datetime      time         yes
datetime    timestamp   yes
==========end 从数据库提取到java=======
不会出错,缺少的部分使用历元,而不是当前日期时间

mysql中的时间类型:

  • datetime:日期时间
  • time:时间
  • date :日期
  • year: 年
  • timestamp:时间戳

MYSQL-datatime和timestamp的区别:

  • 数据库中datetime和timestamp最大不同在于timestamp带有时区。它是从格林威治时间(伦敦)1970. 01.01开始的。因此任何时间转化为时间戳时都会根据当前时区来转化。
  • 两者的存储方式不一样
    ①对于TIMESTAMP,它把客户端插入的时间从当前时区转化为UTC(世界标准时间)进行存储。查询时,将其又转化为客户端当前时区进行返回。
    ②而对于DATETIME,不做任何改变,基本上是原样输入和输出。
  • 两者所能存储的时间范围不一样
    ①timestamp所能存储的时间范围为:’1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’。
    ②datetime所能存储的时间范围为:’1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’。
  • 总结:TIMESTAMP和DATETIME除了存储范围和存储方式不一样,没有太大区别。当然,对于跨时区的业务,TIMESTAMP更为合适。
  • 自动初始化和更新
    ①自动初始化指的是如果对该字段(譬如上例中的hiredate字段)没有显性赋值,则自动设置为当前系统时间。
    ②自动更新指的是如果修改了其它字段,则该字段的值将自动更新为当前系统时间。它与“explicit_defaults_for_timestamp”参数有关。默认情况下,该参数的值为OFF
mysql> show variables like '%explicit_defaults_for_timestamp%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| explicit_defaults_for_timestamp | OFF |
+---------------------------------+-------+
row in set (0.00 sec)
  • 总结:timestamp有自动初始化和更新,当你update某条记录的时候,该列值会自动更新,这是和datatime最大的区别。

历元是怎么选取的?

  • 时间是无头无尾的,人类要计量长时间,间隔从哪儿开始呢?这就需要在时间的某一点上作一个人为的标记,只有这样才能推算各个历史事件的准确时间。正像在坐标轴上选取原点一样。这就是所谓“历元”,历元就是开始纪年的时间。
  • 在古代,每一种历法都有它自己的历元,每一个国家都有它自己的历元和纪年方法。历元的选取方法也各不相同,当然都是人为的、武断的。有的是根据具体的历史事件选取历元,比如古罗马,曾以罗马城建立的时间作为纪元元年;信奉回教的阿訇们曾经以“象年”来纪年,这种纪年的开始是一个极有意义的地方事件——也门的军队进攻麦加,在军队里有许多战象。还有的是以皇帝登基的日子作为历元,如我国明太祖朱元璋的年号是“洪武”,他登基那年就是洪武元年。

数据库与JAVA的时间总结:

  • Java时间字符串对应数据库时间字符串
  • Java时间整型对应数据库时间整型
  • Java时间相应类型对应数据库时间相应类型

Java比较器

Java中实现对象排序的方法有两种:

  • 自然排序:java.lang.Comparable
    Comparable接口是在类中实现的方法。实现了表示此类可以排序。当排序时默认调用此方法。
public interface Comparable<T> {
    public int compareTo(T o);
}
  • 定制排序:java.lang.Comparator
    Comparator接口是在排序方法中实现的方法,是一种特殊的排序,当写入Comparator接口的实现类时。表示此时调用的方法不是自然排序而是定制排序。
public interface Comparator<T> {
	int compare(T o1, T o2);
}

compare()方法注意:

  • 重写的compare(a,b)方法的两个入参中,第一个入参a表示集合元素中相邻元素靠后的那一个;第二个入参b表示集合元素中相邻元素靠前的那一个(原因在下面源码分析中给出)。
  • 也就是说元素a的下标大于元素b的下标。
  • 判断条件:a<=b 希望后一个元素比前一个元素小,即期望降序; a>=b 希望后一个元素比前一个元素大,即期望升序
  • 返回1:就表示集合中元素目前的顺序满足判断条件里面期望的顺序,不需要调整;
  • 返回-1:就表示集合中元素目前的顺序不满足判断条件里面期望的顺序,要进行调整。

compareTo()方法注意:

  • 值为0如果这个对象等于参数对象 。
  • 值小于0如果这个对象数字小于参数对象 。
  • 值大于0如果此对象在数值上大于该参数对象。

System类

简述:

  • System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。
  • 该类位于java.lang包。
  • 由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。
  • 其内部的成员变量和成员方法都是static的,所以也可以很方便的进行调用。
  • 成员变量:
    ①System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
  • 成员方法:
    ①native long currentTimeMillis(): 该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
    ②void exit(int status): 该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。
    ③void gc(): 该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
    ④String getProperty(String key): 该方法的作用是获得系统中属性名为key的属性对应的值。
    在这里插入图片描述

Math类与Random类

Math类简介:

  • java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型
  • abs():求绝对值
  • ceil():天花板的意思,就是返回大的值,注意一些特殊值
  • floor():地板的意思,就是返回小的值
  • max(): 两个中返回大的值
  • min():两个中返回小的值
  • random(): 取得一个大于或者等于0.0小于不等于1.0的随机数
  • rint(): 四舍五入,返回double值
  • round(): 四舍五入,float时返回int值,double时返回long值

Java生成随机数:

  • 调用这个Math.Random()函数能够返回带正号的double值,该值取值区间是[0.0,1.0),注意,它是左闭右开区间。返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。
  • 如果生成三位随机数,则参考如下代码:
    ①由于Math.Random()返回值的类型是double,所以在赋值给其他类型的变量时需要进行类型转换。
int i = (int)(Math.random()*900 + 100);
String myStr = Integer.toString(i);
System.out.println(myStr);
  • 下面提供一种通用的表达式,以获取[min, max]之间的随机数:
    ①这里min,max和返回值都是整数。
(int)(Math.random()*(max - min + 1) + min)

Random类:

  • random.nextInt():random.nextIn()的作用是随机生成一个int类型,因为int 的取值范围是 -2147483648——2147483647
  • random.nextInt(int bound):random.nextInt(int bound)方法的作用是生成一个0-参数bound范围内的随机数,但是要记住,参数bound必须是正数,不可为负数
  • random.nextLong():random.nextLong()会随机生成一个Long类型,同理,因为Long的取值范围是 -9223372036854775808——9223372036854775807
  • random.nextDouble():random.nextDouble()会生成一个0-1的double类型,而不是生成double取值范围中的数
  • random.nextFloat():random.nextFloat()会生成一个随机的0-1之间的浮点型
  • random.nextBoolean():random.nextBoolean()会生成一个true或false
  • random.nextBytes(byte[] bytes):random.nextBytes()会为一个byte类型的数组随机赋值
  • random.nextGaussian():random.nextGaussian()的作用是随机生成一个高斯分布的浮点数

BigInteger与BigDecimal

BigInteger简介:

  • java.math包的BigInteger可以表示不可变的任意精度的整数。BigInteger 提供所有 Java的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。
  • 另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、 位操作以及一些其他操作。

BigDecimal简介:

  • 一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
  • BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
  • BigDecimal的原理就是把小数放大10的N次方倍,将小数点移动到后面,这样利用都是整数,就保证了精度。
  • 链接:BigDecimal的浮点数运算能保证精度的原理是什么?

BigDecimal详解:

System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);

输出:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
  • 可以看到在Java中进行浮点数运算的时候,会出现丢失精度的问题。那么我们如果在进行商品价格计算的时候,就会出现问题。很有可能造成我们手中有0.06元,却无法购买一个0.05元和一个0.01元的商品。因为如上所示,他们两个的总和为0.060000000000000005。这无疑是一个很严重的问题,尤其是当电商网站的并发量上去的时候,出现的问题将是巨大的。可能会导致无法下单,或者对账出现问题。所以接下来我们就可以使用Java中的BigDecimal类来解决这类问题。
  • API:
构造器:
  构造器                   描述
  BigDecimal(int)       创建一个具有参数所指定整数值的对象。
  BigDecimal(double)    创建一个具有参数所指定双精度值的对象。
  BigDecimal(long)      创建一个具有参数所指定长整数值的对象。
  BigDecimal(String)    创建一个具有参数所指定以字符串表示的数值的对象。
  
函数:
  方法                    描述
  add(BigDecimal)       BigDecimal对象中的值相加,然后返回这个对象。
  subtract(BigDecimal)  BigDecimal对象中的值相减,然后返回这个对象。
  multiply(BigDecimal)  BigDecimal对象中的值相乘,然后返回这个对象。
  divide(BigDecimal)    BigDecimal对象中的值相除,然后返回这个对象。
  toString()            将BigDecimal对象的数值转换成字符串。
  doubleValue()         将BigDecimal对象中的值以双精度数返回。
  floatValue()          将BigDecimal对象中的值以单精度数返回。
  longValue()           将BigDecimal对象中的值以长整数返回。
  intValue()            将BigDecimal对象中的值以整数返回。
  • BigDecimal精度也丢失:
    我们在使用BigDecimal时,使用它的BigDecimal(String)构造器创建对象才有意义。其他的如BigDecimal b = new BigDecimal(1)这种,还是会发生精度丢失的问题。如下代码:
BigDecimal a = new BigDecimal(1.01);
BigDecimal b = new BigDecimal(1.02);
BigDecimal c = new BigDecimal("1.01");
BigDecimal d = new BigDecimal("1.02");
System.out.println(a.add(b));
System.out.println(c.add(d));

输出:
2.0300000000000000266453525910037569701671600341796875
2.03
  • 可见论丢失精度BigDecimal显的更为过分。但是使用Bigdecimal的BigDecimal(String)构造器的变量在进行运算的时候却没有出现这种问题。究其原因计算机组成原理里面都有,它们的编码决定了这样的结果。long可以准确存储19位数字,而double只能准备存储16位数字。double由于有exp位,可以存16位以上的数字,但是需要以低位的不精确作为代价。如果需要高于19位数字的精确存储,则必须用BigInteger来保存,当然会牺牲一些性能。所以我们一般使用BigDecimal来解决商业运算上丢失精度的问题的时候,声明BigDecimal对象的时候一定要使用它构造参数为String的类型的构造器。
  • 正确运用BigDecimal
    ①另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象,由刚才我们所罗列的API也可看出。
    在一般开发过程中,我们数据库中存储的数据都是float和double类型的。在进行拿来拿去运算的时候还需要不断的转化,这样十分的不方便。这里我写了一个工具类:
public class BigDecimalUtil {

    private BigDecimalUtil() {

    }

    public static BigDecimal add(double v1, double v2) {// v1 + v2
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }

    public static BigDecimal sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2);
    }

    public static BigDecimal mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2);
    }

    public static BigDecimal div(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        // 2 = 保留小数点后两位   ROUND_HALF_UP = 四舍五入
        return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);// 应对除不尽的情况
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值