Object类
Object类是所有类(包括超类,基类)的直接或间接父类,位于继承树的最顶层。任何类,如果没有显式地继承某个类,都默认直接继承Object类,否则为间接继承。Object类所定义的方法,是所有对象都具备的方法。Object类中可以存储任何对象,它作为参数时,可以接受任何对象;作为返回值时,可返回任何对象。Object类只声明了一个空参构造器。
1、hashCode()方法
hashCode()方法返回该对象的hash值。hash值是根据对象的地址使用hash函数计算出来的int类型的数值。一般情况下,相同的对象会返回相同的hash值。
User user = new User("小明",20);
User user1 = new User("Lee",21);
User user2 = user;
//hashCode()方法
System.out.println(user.hashCode()); //356573597
System.out.println(user1.hashCode());//1735600054
System.out.println(user2.hashCode());//356573597
2、toString()方法
返回该对象的字符串表示,可以根据需求重写该方法,例如显示对象的各个属性的值。
不重写Object类的toString()方法,Object类自身的toString()方法返回一个字符串,包名+类名+@+该对象哈希码的无符号十六进制表示 如:usual.User@1540e19d
重写Object类的toString()方法,显示对象的各个属性的值,
User{name=‘null’, age=0}。
//重写toString()方法
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//toString()方法
//不重写Object的toString方法时
//System.out.println(user.toString()); //usual.User@1540e19d
//重写toString方法后
user.setAge(20);
System.out.println(user.toString()); //User{name='null', age=20}
3、clone()方法
clone()创建并返回此对象的副本,实现对象中各个属性的复制,以后可以改变各自的状态,而互不影响。但它的可见范围是protected的,实体类使用克隆的前提是:
1、实现Cloneable接口,这是一个标记接口,本身没有方法。
2、覆盖clone()方法,可见性提升为public。
浅拷贝:被复制对象的所有值属性都与原来对象的相同,所有的对象引用属性仍然指向原来的对象。
深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。
如果被复制的属性都是基本类型,只需要实现当前类的cloneable机制就可以了,此为浅拷贝。
如果被复制对象的属性包含其他实体类对象引用,那么这些实体类对象都需要实现Cloneable接口并重写clone()方法。
public class User implements Cloneable {
private String name;
private int age;
}
//clone()方法
try {
User cloneUser = (User) user.clone();
System.out.println(user == cloneUser); //false
cloneUser.setAge(18);
System.out.println(cloneUser); //User{name='小明', age=18}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
4、getClass()方法
getClass()方法返回对象运行时的实例类。通常用来判断两个引用中实际对象的类型是否一致。
//getCLass()方法
User stuUser = new Student();
Class<? extends User> userClass = user.getClass();
Class<? extends User> user1Class = user1.getClass();
Class<? extends User> stuUserClass = stuUser.getClass();
System.out.println(userClass); //class usual.User
System.out.println(user1Class); //class usual.User
System.out.println(stuUserClass); //class usual.Student
System.out.println(userClass == stuUserClass); //false
5、notify()方法
唤醒正在等待对象监视器的单个线程。 如果任何线程正在等待这个对象,其中一个被选择被唤醒。选择是任意的,并且由实施的判断发生。 线程通过调用wait方法之一。
唤醒的线程将无法继续,直到当前线程放弃此对象上的锁定为止。 唤醒的线程将以通常的方式与任何其他线程竞争,这些线程可能正在积极地竞争在该对象上进行同步; 例如,唤醒的线程在下一个锁定该对象的线程中没有可靠的权限或缺点。
该方法只能由作为该对象的监视器的所有者的线程调用。 线程以三种方式之一成为对象监视器的所有者:
通过执行该对象的同步实例方法。
通过执行在对象上synchronized synchronized语句的正文。
对于类型为Class,的对象,通过执行该类的同步静态方法。
一次只能有一个线程可以拥有一个对象的显示器。
6、wait()方法
导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。
当前的线程必须拥有该对象的显示器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify方法或notifyAll方法notifyAll 。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。
像在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用:
synchronized (obj) {
while ()
obj.wait();
… // Perform action appropriate to condition
}
该方法只能由作为该对象的监视器的所有者的线程调用。 有关线程可以成为监视器所有者的方式的说明,请参阅notify方法。
7、equals()方法
该方法默认实现为(this==obj),判断两个对象地址是否相同。也可重写,比较两个对象的内容是否相同。返回值类型是boolean类型,若比较的两个对象地址相同则返回true,反之为false。
注意,无论何时重写该方法,通常需要重写hashCode方法,以便维护hashCode方法的通用合同,该方法规定相等的对象必须具有相等的哈希值。
==和equals()区别
== 是运算符 可以使用在基本数据类型和引用数据类型变量中。
如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等(类型不一定要相同),如果比较的是引用数据类型变量,比较两个对象的地址值是否相等,即两个引用是否指向同一个对象实体。
equals()是一个方法,只能适用于引用数据类型,Object类中定义的equals()和==作用相同,比较两个对象的地址值是否相等,即两个引用是否指向同一个对象实体。
像String、Date、File、包装类等都重写了Object类中的equals()方法,重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同。
重写equals()方法:
1、比较两个引用是否指向同一个对象
2、判断obj是否为null
3、判断两个引用指向的实际对象类型是否一致
4、强制类型转换,一次性比较各个属性值是否相同,属性中存在的类类型也需要重写equals方法
//重写equals方法
@Override
public boolean equals(Object obj) {
// return super.equals(obj);
// 比较两个引用是否指向同一个对象
if (this == obj) {
return true;
}
// 判断obj是否为null
if (obj == null) {
return false;
}
// 判断两个引用指向的实际对象类型是否一致
if (obj instanceof User) {
User user = (User) obj;
if (this.name.equals(user.getName()) && this.age == user.getAge()) {
return true;
}
}
return false;
}
//equals()方法
User user = new User("小明",20);
User user1 = new User("Lee",21);
User user2 = user;
System.out.println(user.equals(user1)); //false
System.out.println(user.equals(user2)); //true
8、finalize()方法 已过时 可能导致内部出现循环引用,导致此对象不能被回收
当对象被判定为垃圾对象,由JVM自动调用此方法,标记垃圾对象,进入回收队列。
垃圾对象:没有有效引用指向此对象时,此对象为垃圾对象。
垃圾回收:由gc销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc(),通知JVM执行垃圾回收。
//重写finalize方法
@Override
protected void finalize() throws Throwable {
// super.finalize();
System.out.println(this+"被回收了...");
}
//finalize()方法
User user3 = new User("A",19);
User user4 = new User("B",20);
//C没有有效引用,被回收v
new User("C",21); //User{name='C', age=21}被回收了...
System.gc();
Math类
java.lang.Math包提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double类型。
public static double ceil(double a)
:返回大于等于参数的最小的整数。public static double floor(double a)
:返回小于等于参数最大的整数。public static long round(double a)
:返回最接近参数的 long。(相当于四舍五入方法)
abs() 绝对值
acos(),asin(),atan(),cos(),sin(),tan() 三角函数、反三角函数
sqrt() 平方根
pow(double a,doble b) a的b次幂 log
自然对数 exp() 以e为底的指数
max(double a,double b)
min(double a,double b)
random():返回取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机数,在该范围内(近似)均匀分布。需求:获取[a,b]范围内的随机整数 int random = (int)(Math.random() *(b - a + 1) ) + a
toDegrees(double angrad) 弧度—>角度
toRadians(double angdeg) 角度—>弧度
//Math类
System.out.println(Math.pow(2, 3));
System.out.println(Math.abs(-1));
System.out.println(Math.round(1231.213124)); //long 四舍五入
System.out.println(Math.random() + 1);
System.out.println(Math.exp(1 / 2));
System.out.println(Math.sin(Math.PI / 2));
System.out.println(Math.sqrt(2));
System.out.println(Math.toDegrees(Math.PI / 2));
System.out.println(Math.toRadians(30) * 6); //Pi
Random类
Random常用来创建一些随机数
1、实现的随机算法是伪随机,也就是有规则的随机,所谓有规则的就是在给定种子(seed)的区间内随机生成数字;
2、相同种子数的Random对象,相同次数生成的随机数字完全相同;
3、Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率均等;
Random():使用一个和当前系统时间对应的相对时间有关的数字作为种子数。Random(long seed):直接传入一个种子数。
-
boolean nextBoolean()
:返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 boolean 值。 -
void nextBytes(byte[] bytes)
:生成随机字节并将其置于用户提供的 byte 数组中。 -
double nextDouble()
:返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 double 值。 -
float nextFloat()
:返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 float 值。 -
double nextGaussian()
:返回下一个伪随机数,它是取自此随机数生成器序列的、呈高斯(“正态”)分布的 double 值,其平均值是 0.0,标准差是 1.0。 -
int nextInt()
:返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。 -
int nextInt(int n)
:返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。 -
long nextLong()
:返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。
// Random类
Random random = new Random();
int[] arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(10); //获取数的范围:[0,10)
}
for (int elem : arr) {
System.out.print(elem + "\t");
}
System.out.println();
UUID
什么是UUID?
UUID全称:Universally Unique ldentifier,通用唯一识别码。
UUID是由一组32位数的16进制数字所构成,UUID理论上的每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。
UUID的标准型式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的32个字符,如:b0f483a7-c6b3-4d3f-8d32-3b07f6c1bb98
UUID的作用
UUID的是让分布式系统中的所有元素都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。
在这样的情况下,就不需考虑数据库创建时的名称重复问题。目前最广泛应用的UUID,是微软公司的全局唯—标识行(t系统、LUKS加密分区、GNOME、KDE、Mac OS X等等。
UUID的组成
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
UUID由以下几部分的组合:
当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。时钟序列。全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。
UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique ldentifiers)。
//UUID 生成随机的UUID
String uuid = UUID.randomUUID().toString();
String uuid2 = UUID.randomUUID().toString();
System.out.println(uuid);
System.out.println(uuid2);
//去除‘-’符号
String str = UUID.randomUUID().toString().replaceAll("-", "");
System.out.println(str);
File类
java.io.File类是java中很常见的一个类。该类有以下特点:
1、封装文件或目录。
2、无法创建文件,在程序中创建一个File对象,并不会在计算机创建一个文件,这个File对象是计算机上某个文件的对象的引用。
3、不能向文件中写入内容,不能从文件中读取内容。
常见方法:
exists():File对象表示的文件名或目录是否存在,存在返回true。
canRead():File对象表示的文件名或目录存在且可读,存在返回true。
canWrite():File对象表示的文件名或目录存在且可写,存在返回true。
isFile():File对象是一个文件,返回true。
isDirectory():File对象表示的是一个目录,返回true。
isAbsolute():File对象表示的文件是用绝对路径名创建的,返回true。
isHidden():File对象表示的文件属性是隐藏的,返回true。
getAbsolutePath():返回File对象表示的文件或目录的绝对路径。
getCanonicalPath():返回File对象表示的文件或目录的绝对路径,用于unix系统
getName():返回File对象表示的文件或目录的名称。
getPath():返回File对象表示的文件或目录的完整路径。
getParent():返回File对象表示的文件或目录的父目录的完整路径。
lastModified():返回File对象表示的文件或目录的最后一次修改时间。
length():返回File对象表示的文件或目录的长度。
listFiles():如果返回File对象表示的是一个目录,则返回该目录下所有的文件和目录。
delete():删除File对象表示的文件或目录。
renameTo(File file):重命名文件或目录。
public static void main(String[] args) {
File file = new File("1.txt");
File file1 = new File("E:\\IDEAWorkSpace\\JavaSE");
File[] files = file1.listFiles();
for (File fileElem : files) {
System.out.print(fileElem.getName()+"\t");
}
System.out.println();
System.out.println("file==file1:"+file.equals(file1)); //false
System.out.println("isFile:"+file.isFile());
System.out.println("fileName:"+file.getName());
System.out.println("fileLength:"+file.length());
System.out.println("lastModified:"+file.lastModified());
System.out.println("absolutePath:"+file.getAbsolutePath());
System.out.println("getParentPath:"+file1.getParent());
System.out.println("isDirectory:" + file.isDirectory());
System.out.println("canRead:"+file.canRead());
System.out.println("canWrite:"+file.canWrite());
}
包装类
Java提供了8种基本数据类型对应的包装类,使基本数据类型变量具备引用数据类型的相关特征(封装、继承、多态)
byte–>Byte
short–>Short
int–>Integer
long–>Long
float–>Float
double–>Double
boolean–>Boolean
char–>Character
自动装箱和自动拆箱
创建包装类对象有两种方式:new关键字和valueOf()方法。
JDK1.5之后,提供自动装箱和拆箱的功能
public static void main(String[] args) {
int i = 10;
//int取值范围
System.out.println(Integer.MIN_VALUE + "~" + Integer.MAX_VALUE);
//创建包装类对象有两种方式:new关键字和valueOf()方法。
//自动装箱
Integer integer = new Integer(i); //基本数据类型转换为包装类
//自动拆箱 引用类型转换为基本类型
int j = integer;
System.out.println(j);
Integer value = Integer.valueOf("12345");
//将String类型解析为int类型
int parseInt = Integer.parseInt("1000");
System.out.println(integer);
System.out.println(value);
System.out.println(parseInt);
}
包装类的缓存对象
Byte:-128-127
Short:-128-127
Integer:-128-127
Long:-128-127
Float:无
Double:无
Character:0-127
Boolean:true和false
Integer i =1;
Integer j = 1;
System.out.println(i==j); //true
Date类和Calendar类
UTC:Coordinated Universal Time 协调世界时。
GMT:Greenwich Mean Time 格林尼治标准时间。GMT = UTC+0
CST:CST却同时可以代表如下 4 个不同的时区:
1)China Standard Time 中国标准时区 (UTC+8)
2)Cuba Standard Time 古巴标准时区 (UTC-4)
3)Central Standard Time (USA) 美国中央时区 (UTC-6)
4)Central Standard Time (Australia) 澳大利亚中央时区(UTC+9)
计算方式:UTC是根据原子钟来计算时间,而GMT是根据地球的自转和公转来计算时间。
准确性:UTC是现在用的时间标准,GMT是老的时间计量标准。UTC更加精确,由于现在世界上最精确的原子钟50亿年误差1秒。
因为地球自转越来越慢,每年都会比前一年多出零点几秒,每隔几年协调世界时组织都会给世界时+1秒,让基于原子钟的世界时和基于天文学(人类感知)的格林尼治标准时间相差不至于太大。并将得到的时间称为UTC,这是现在使用的世界标准时间。
1、java.util.Date 从1970-1-1开始计算的时间
两个构造器:
new Date(): 获取当前时间
new Date(long date): 获取毫秒数对应的时间
两个方法:
toString() : 输出时间的内容
getTime() : 获取时间对应的毫秒数
2、java.sql.Date,对应数据库中的date类型
一个构造器:
new Date(long date); 获取毫秒数对应的日期
两个方法:
toString() : 输出日期的内容
getTime() : 获取日期对应的毫秒数
3、java.text.SimpleDateFormat : 用来格式化日期和时间
两个方法:
format(Date date) : 将Date转成字符串
parse(String time) : 将字符串转成Date的格式
注意:字符串中时间的格式和当前SimpleDateFormat对象设置的时间格式必须一致
Calendar类
Calendar类是一个抽象基类,主要用于完成日期字段之间相互操作的功能。
构造方法:protected Calendar():protected修饰,无法直接创建对象。
获取Calendar实例的方法
1、调用Calendar.getInstance()静态方法
2、调用它的子类GregorianCalendar的构造器
一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法取得时间信息。field为常量
常用方法:
public void set(int field,int value):修改时间信息
public void add(int field,int amount):在常量的基础上增加或减少数值,amount可为负数
public final Date getTime()
public final vod setTime(Date date)
注意:获取月份时,一月是0,二月是1…十二月是11
获取星期时,周日是1,周一是2…周六是7
Date date = new Date();
System.out.println(date.getTime());
System.out.println(date.toString());
//获取毫秒数对应的日期
java.sql.Date sqlDate = new java.sql.Date(date.getTime());
System.out.println(sqlDate.toString());
//SimpleDateFormat类
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(date);
System.out.println("time:" + time);
try {
//将字符串转换为date
Date date1 = sdf.parse("2000-01-01 00:00:01");
System.out.println(date1);
} catch (ParseException e) {
e.printStackTrace();
}
//SimpleDateFormat将字符串转换为java.sql.Date对象
try {
Date parse = sdf.parse("2022-06-11 00:00:01");
java.sql.Date sqlDate1 = new java.sql.Date(parse.getTime());
System.out.println("sqlDate1:"+sqlDate1.toString());
} catch (ParseException e) {
e.printStackTrace();
}
//Calendar类
//获得calendar对象
// Calendar calendar= new GregorianCalendar();
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getClass().getName()); //java.util.GregorianCalendar
System.out.println(calendar.getCalendarType());
//修改今天为本月的第一天
calendar.set(Calendar.DAY_OF_MONTH, 1);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
//在本月第几天的基础上增加或者减少
calendar.add(Calendar.DAY_OF_MONTH, 2);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
//查询本周是今年的第几周
int week = calendar.get(Calendar.WEEK_OF_YEAR);
System.out.println("week:" + week);
//查询今天是本月的第几天
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("day:" + day);
//获得日历所对应的日期和时间 Calendar--->Date
Date calendarDate = calendar.getTime();
System.out.println(calendarDate);
//Date--->Calendar
Date date1 = new Date();
calendar.setTime(date1);
System.out.println(calendar);
JDK8中新日期时间API
新的java.time包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类
LocalDate、LocalTime、LocalDateTime都有不可变性,LocalDateTime使用频率高。
常用方法:
now():获取当前的日期、时间、日期+时间
of():设置指定的年、月、日、时、分、秒,纳秒,返回一个新对象,没有偏移量。
getXXX():获取相关属性
withXXX():设置相关属性
//LocalDate、LocalTime、LocalDateTime
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDate:" + localDate);
System.out.println("localTime:" + localTime);
System.out.println("localDateTime:" + localDateTime);
LocalDate localDate1 = LocalDate.of(2022, 5, 1);
System.out.println("localDate:" + localDate);
System.out.println("localDate1:" + localDate1);
LocalTime localTime1 = LocalTime.of(9, 55, 55, 33);
System.out.println("localTime:" + localTime);
System.out.println("localTime1:" + localTime1);
LocalDateTime localDateTime1 = LocalDateTime.of(2022, 5, 1, 9, 59, 23);
System.out.println("localDateTime:" + localDateTime);
System.out.println("localDateTime1:" + localDateTime1);
//getXXX():获取相关属性
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getDayOfYear());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getMonth());
System.out.println(localDateTime.getMonthValue()); //int
//体现不可变性 withXXX():设置相关属性
LocalDate localDate2 = localDate.withDayOfMonth(29); //修改月份的第几天
LocalDate localDate3 = localDate2.plusDays(1); //加天数
System.out.println("localDate:"+localDate);
System.out.println("localDate2:"+localDate2);
System.out.println("localDate3:"+localDate3);
LocalDateTime localDateTime2 = localDateTime.withHour(10).withMinute(00); //修改小时、分钟
System.out.println(localDateTime);
System.out.println(localDateTime2);
Instant类
时间线上的一个瞬时点,可能被用来记录应用程序中的事件时间戳。
now():获取本初子午线对应的标准时间
toEpochMilli():获取从1970-1-1 00:00:00(UTC) 开始的毫秒数
ofEpochMilli():通过给定的毫秒数,获取Instant实例
//Instant类
Instant instant = Instant.now();
System.out.println("instant:" + instant); //2022-06-11T13:46:39.005Z
//添加时间的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime); //2022-06-11T21:48:25.583+08:00
//toEpochMilli()
long milli = instant.toEpochMilli();
System.out.println(milli);
//ofEpochMilli()
Instant instant1 = Instant.ofEpochMilli(1654955501436L);
System.out.println(instant1);
DateTimeFormatter类
ofPattern(String pattern):静态方法,返回一个指定字符串格式的DateTimeFormatter
format(TemporalAccessor t):格式化一个日期、时间,返回一个字符串
parse(CharSequence text):将指定格式的字符序列解析为一个日期、时间
用于格式化或解析日期、时间 类似SimpleDateFormat
方式一:预定义的标准格式ISO_LOCAL_DATE、ISO_LOCAL_TIME、ISO_LOCAL_DATE_TIME
方式二:本地化相关的格式化 如:ofLocalizedDateTime
FormatStyle.LONG、FormatStyle.MEDIUM、FormatStyle.SHORT
重点:方式三:自定义的格式化 如:ofPattern(“yyyy–MM-dd HH:mm:ss E”);
//DateTimeFormatter类
//方式一:预定义的标准格式ISO_LOCAL_DATE、ISO_LOCAL_TIME、ISO_LOCAL_DATE_TIME
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化 日期-->字符串
LocalDateTime localDateTime3 = LocalDateTime.now();
String format = formatter.format(localDateTime3);
System.out.println("localDateTime3:"+localDateTime3);
System.out.println("format:"+format);
//解析 字符串-->日期
TemporalAccessor parse = formatter.parse("2022-06-12T10:09:36.155");
System.out.println(parse); //{},ISO resolved to 2022-06-12T10:09:36.155
//方式二:本地化相关的格式化 如:ofLocalizedDateTime
// FormatStyle.LONG、FormatStyle.MEDIUM、FormatStyle.SHORT
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
String format1 = formatter1.format(LocalDateTime.now());
System.out.println("short:"+format1); //22-6-12 上午10:22
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
String format2 = formatter2.format(LocalDateTime.now());
System.out.println("medium:"+format2); //2022-6-12 10:23:46
DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
String format3 = formatter3.format(LocalDateTime.now());
System.out.println("long:"+format3); //2022年6月12日 上午10时24分27秒
//重点:方式三:自定义的格式化 如:ofPattern(“yyyy--MM-dd HH:mm:ss E”);
//格式化
DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss E");
String format4 = formatter4.format(LocalDateTime.now());
System.out.println("format4:"+format4); //2022-06-12 10:30:53 星期日
//解析
TemporalAccessor accessor = formatter4.parse("2022-06-12 10:30:53 星期日");
LocalDateTime localDateTime4 = LocalDateTime.from(accessor);
System.out.println("localDateTime4:"+localDateTime4); //2022-06-12T10:30:53
其他时间API
Zoneld:该类中包含了所有的时区信息,一个时区的ID,如Europe/Paris
ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如2007-12-03T10:00:00+01:00 Europe/Paris 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,如:Asia/Shanghai等
Clock:使用时区提供对当前即时、日期和时间的访问的时钟。
Duration,用于计算两个“时间”间隔
Period:用于计算两个“日期”间隔
TemporalAdjuster:时间校正器。有时我们可能需要获取 例如:将日期调整到“下一个工作日”等操作。
TemporalAdjusters:该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster的实现
什么是编码,解码?何为日期时间的格式化?解析?
编码:字符串–>字节
解码:字节–>字符串
格式化:日期–>字符串
解析:字符串–>日期
String、StringBuffer和StringBuilder
String类被final修饰,不能被继承,具有不可变性。
String实现了Serializable接口,该类的对象可以被序列化。
序列化:可以将对象写到硬盘上,也可将不同进程间的对象进行传递
String实现了Comparable接口 :可以用来比较内容(往往通过Comparable接口实现排序的功能)
String(StringBuffer,StringBuilder)实现了CharSequence接口:
实现该接口可以获取字符串的长度,获取指定索引位置上的字符等。
String底层是一个char[],而且被final修饰。String是一个不可变长的字符序列
面试题: String str = new String(“abc”)语句在内存中开辟了几块空间?
常量池中一块空间,堆中一块空间。
内存结构分析:
①String s = “abc”; //在常量池中创建一个"abc"
②String s = new String(“abc”);//在堆中创建一个对象,在常量池中创建一个"abc"。
注:常量池中没有重复的内容。
String常用方法:
增(添加,连接),删(delete),改(replace),查(indexOf),插入(insert),长度(length)
int length():返回字符串的长度: return value.length
char charAt(int index): 返回某索引处的字符 return value[index]
static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String
static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String
static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String
static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String
boolean isEmpty():判断是否空串:return value.length == 0
String toLowerCase():将 String 中的所有字符转换为小写
String toUpperCase():将 String 中的所有字符转换为大写
String trim():返回字符串的副本,去除前导空白和尾部空白,不去除中间空白
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
int compareTo(String other):比较字符串大小,区分大小写,按照unicode编码值比较大小
int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
String concat(String str):将指定字符串连接到此字符串的结尾。等价于“+”
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
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
boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
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 替换此字符串匹配给定的正则表达式的第一个子字符串。
String[] split(String regex):根据给定的匹配拆分此字符串。
String、StringBuffer和StringBuilder
String: 不可变的字符序列,线程不安全,底层是char[],被final所修饰,意味着不能继承String。
JDK8中String的声明:
public final class String implements java.io.Serializable, Comparable < String > , CharSequence {…}
private final char value[]; //String对象的字符内容是存储在此数组中
final指明value数组一旦初始化,其地址就不可变
Serializable:可序列化的接口,凡是实现此接口的类的对象就可以通过网络或者本地流进行传输
Comparable :实现Comparable接口的类,其对象都可以比较大小。
JDK9开始String的声明:为了节省内存空间
private final byte value[ ]; //存储字符串数据的容器
字符串常量都存储在字符串常量池(StringTable)中,字符串常量池不允许存放两个相同的字符串常量。
字符串常量池 JDK7之前存放在方法区,JDK7及以后存放在堆空间
String的不可变性:
1、当对字符串变量重新赋值时,需要重新指定一个字符串常量的位置进行赋值,不能在原有位置进行修改。
2、当对现有的字符串进行拼接时,需要重新开辟空间保存拼接以后的字符串,不能在原有位置修改。
3、当调用字符串的replace()替换现有的某个字符时,需要重新开辟空间保存拼接以后的字符串,不能在原有位置进行修改。
String实例化的两种方式:
1、String s1 = “hello”;
2、String s2 = new String(“hello”);
【面试题】 String s2 = new String(“hello”);创建了几个对象?
两个对象,一个是堆空间我们new的对象,另一个是字符串常量池中生成的字面量。
String的连接操作 :+
1、常量+常量:结果仍然存储在字符串的常量池中,返回此字面量的地址。此时的常量是字面量或者final修饰的常量
2、常量+变量,变量+变量:都会通过new的方式创建一个新的字符串,返回堆空间中此字符串对象的地址。会创建一个StringBuilder实例,通过append()方法添加字符串,最后调用一个toString()返回一个字符串(toString()内部new了一个String实例)。
3、调用字符串的intern()方法:返回的是字符串常量池中字面量的地址。
concat()方法:不管是常量调用还是变量调用此方法,也不管参数是常量还是变量,总之调用完concat()方法,都返回一个新new的对象。
String的构造器与常用方法
构造器:
public String()
:初始化新创建的 String对象,以使其表示空字符序列。String(String original)
: 初始化一个新创建的String
对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。public String(char[] value)
:通过当前参数中的字符数组来构造新的String。public String(char[] value,int offset, int count)
:通过字符数组的一部分来构造新的String。public String(byte[] bytes)
:通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。public String(byte[] bytes,String charsetName)
:通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
字符串 --> 基本数据类型、包装类:
- Integer包装类的public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。
- 类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 --> 字符串:
- 调用String类的public String valueOf(int n)可将int型转换为字符串
- 相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可由参数的相应类型到字符串的转换。
字符数组 --> 字符串:
- String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
字符串 --> 字符数组:
- public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。
- public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
字符串 --> 字节/字节数组:(编码)
UTF-8中,一个汉字占用3个字节,一个字母占用1个字节。
GBK中,一个汉字占用2个字节,一个字母占用1个字节。
UTF-8和GBK都向下兼容了ASCII码
- public byte[] getBytes() :使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
- public byte[] getBytes(String charsetName) :使用指定的字符集将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
字节/字节数组 --> 字符串:(解码)
注:解码时使用的字符集要求与编码时使用的字符集一致,不一致就会乱码。
- String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
- String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象。
- String(byte[], String charsetName ) 或 new String(byte[], int, int,String charsetName ):解码,按照指定的编码方式进行解码。
StringBuffer: 可变的字符序列,JDK1.0提供,线程安全,效率低,底层是char[]
StringBuffer类中的方法都添加了synchronized关键字,给这个方法添加了一个锁,用来保证线程安全。
StringBuilder: 可变的字符序列 JDK1.5提供,线程不安全,效率高,底层是char[]
StringBuilder内部属性:char[] value //存储字符序列 , int count //实际存储的字符个数
StringBuffer构造器:
StringBuffer():创建初始容量为16的字符串缓冲区
StringBuffer(int capacity):构造指定容量的字符串缓冲区
StringBuffer(String str):将内容初始化为指定字符串内容
StringBuffer常用方法:
StringBuffer append(xxx):用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer deleteCharAt(int index):删除[index]位置字符
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xx):在字符串指定位置插入数据
StringBuffer reverse() :将字符串逆转
public int indexOf(String str):在当前字符序列中查询str的第一次出现下标
public int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标
public int lastIndexOf(String str):在当前字符序列中查询str的最后一次出现下标
public int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标
String substring(int start):截取当前字符序列[start,最后]
public String substring(int start,int end):截取当前字符序列[start,end)
String toString():返回此序列中数据的字符串表示形式
void setLength(int newLength) :设置当前字符序列长度为newLength
public int length():返回存储的字符数据的长度
public char charAt(int index):查找指定index位置上的字符
public void setCharAt(int index ,char ch):将指定位置的字符改为指定字符
底层扩容机制:
当我们通过空参的StringBuffer创建对象时,底层创建一个长度为16的数组,向该数组添加第17个元素时底层会自动扩容,扩容为原来的2倍+2.同时将原数组中的内容复制到新的字符数组中。
- 如果开发中需要频繁的针对字符串进行增删改查,建议使用StringBuffer或StringBuilder替换String,因为String效率低。
- 如果开发中不涉及线程安全问题,建议使用StringBuilder。因为StringBuilder效率高。
- 如果开发中大体确定要操作的字符个数,建议使用带int capacity参数的构造器,因为可以避免底层多次扩容操作,性能好。
StringBuilder构造器和方法与StringBuffer基本相同
三者执行效率:StringBuilder > StringBuffer >String
public class StringDemo {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s1 == s4); //false
System.out.println(s3 == s4); //false
System.out.println(s1.equals(s2)); //true
System.out.println(s1.equals(s3)); //true
System.out.println(s3.equals(s4)); //true
String test1 = "hello";
String test2 = "world";
String test3 = "helloworld";
String test4 = "hello" + "world";
String test5 = test1 + "world"; //查看字节码发现调用了StringBuilder的toString()-->new String()
String test6 = "hello" + test2;
String test7 = test1 + test2;
System.out.println(test3 == test4); //true
System.out.println(test3 == test5); //false
System.out.println(test3 == test6);//false
System.out.println(test3 == test7);//false
System.out.println(test5 == test6);//false
System.out.println(test5 == test7);//false
String test8 = test5.intern();
System.out.println(test3 == test8); //true
String test9 = test1.concat(test2);
String test10 = "hello".concat("world");
String test11 = s1.concat("world");
System.out.println(test9 == test10); //false
System.out.println(test9 == test11); //false
System.out.println(test10 == test11); //false
String str = "abcda";
System.out.println("str.length:" + str.length());
System.out.println("charAt 0:" + str.charAt(0));
System.out.println("UpperCase:" + str.toUpperCase());
System.out.println("trim:" + str.trim());
System.out.println("subString 1:" + str.substring(1));
System.out.println("subString [0,2):" + str.substring(0, 2));
System.out.println("contains a:" + str.contains("a"));
System.out.println("index b:" + str.indexOf("b"));
System.out.println("index a:" + str.indexOf("a", 1));
System.out.println("lastIndex ab:" + str.lastIndexOf("ab"));
System.out.println("lastIndex da:" + str.lastIndexOf("da", 4));
System.out.println("endWith da:" + str.endsWith("da"));
System.out.println("startWith abac:" + str.startsWith("abac"));
System.out.println("a-->e" + str.replace('a', 'e'));
// 根据给定的匹配拆分此字符串
String[] split = str.split("c");
for (String s : split) {
System.out.print(s + "\t");
}
System.out.println();
String concat = str.concat("123");
String str1 = "abcda" + "123";
String str2 = "abcda123";
String str3 = new String("abcdddd");
System.out.println("concat:" + concat);
System.out.println(str1 == concat); //false
System.out.println(str1.equals(concat)); //true
System.out.println(str1 == str2); //true
//基本数据类型和String转换
//String -->int
int i = Integer.parseInt("123");
System.out.println(i);
//String -->Integer
Integer integer = new Integer("456");
System.out.println(integer);
//String -->byte[]
byte[] bytes = "qwe".getBytes();
//byte[] -->String
String s = new String(bytes);
System.out.println("s:" + s);
//String -->char[]
char[] chars = s.toCharArray();
//char[] -->String
String ss1 = new String(chars);
System.out.println("ss1:" + ss1);
String string = "a" + 1 + 2; //12a
String string1 = 1 + 2 + "a"; //3a
System.out.println("sting:" + string + "\t string1:" + string1);
//StringBuffer
// StringBuffer buffer = new StringBuffer(20);
StringBuffer buffer = new StringBuffer();
buffer.append("Lee").append(" 20");
StringBuffer reverse = buffer.reverse();
System.out.println("reverse:" + reverse);
buffer.insert(0, "5");
System.out.println(buffer);
buffer.setCharAt(1, 'e');
System.out.println(buffer);
System.out.println("buffer length:" + buffer.length());
//StringBuilder
StringBuilder builder = new StringBuilder();
builder.append("Java").append("EE").append("666");
System.out.println("builder:" + builder);
builder.delete(0, builder.length());
System.out.println("builder:" + builder);
long startTime = 0L;
long endTime = 0L;
String text = "";
StringBuffer buffer1 = new StringBuffer("");
StringBuilder builder1 = new StringBuilder("");
//开始对比效率
startTime = System.currentTimeMillis();
for (i = 0; i < 20000; i++) {
buffer1.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime) + "ms");
startTime = System.currentTimeMillis();
for (i = 0; i < 20000; i++) {
builder1.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime) + "ms");
startTime = System.currentTimeMillis();
for (i = 0; i < 20000; i++) {
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime) + "ms");
}
}
System类
System类代表系统,系统级很多属性和控制方法都放置在该类的内部。
该类的构造器是private的,无法创建该类的对象,也就无法实例化该类。其内部的成员变量和成员方法都是static的,可以很方便的进行调用。
成员变量:System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
常用方法:
static native long currentTimeMillis();
返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
static native void arraycopy(Object src, int srcPos, Object dest,int length);
复制数组 src:原数组 ,srcPos:从指定位置开始复制
destPos:目标数组的位置,length:复制的长度
static void gc():通知JVM回收垃圾对象
static void exit(int status):退出JVM,参数为0表示正常退出,参数非0表示异常退出。
String getProperty(String key):该方法的作用是获得系统中属性名为key的属性对应的值。系统中常用的属性名以及属性的作用如下所示:
java.version Java版本
java.home Java安装目录
os.name 操作系统名称
os.version 操作系统版本
public static void main(String[] args) {
//复制数组
int[] arr = new int[]{1, -1, 0, 2, -2, -3, 3};
int[] dest = new int[10];
System.arraycopy(arr, 0, dest, 1, 7);
for (int elem : dest) {
System.out.print(elem + "\t");
}
StringBuffer buffer = new StringBuffer();
StringBuilder builder = new StringBuilder();
long bufferStart = System.currentTimeMillis();
for (int i = 0; i < 9999; i++) {
for (int j = 0; j < 9999; j++) {
buffer.append(i + j);
}
}
System.out.println();
long bufferEnd = System.currentTimeMillis();
System.out.println("buffer循环用时:" + (bufferEnd - bufferStart) + "ms");
long builderStart = System.currentTimeMillis();
for (int i = 0; i < 9999; i++) {
for (int j = 0; j < 9999; j++) {
builder.append(i + j);
}
}
long builderEnd = System.currentTimeMillis();
System.out.println("builder循环用时:" + (builderEnd - builderStart) + "ms");
//获得系统信息
System.out.println("java.version:"+System.getProperty("java.version"));
System.out.println("java.home:"+System.getProperty("java.home"));
System.out.println("os.name:"+System.getProperty("os.name"));
System.out.println("os.version:"+System.getProperty("os.version"));
System.out.println("user.name:"+System.getProperty("user.name"));
System.exit(0);
System.out.println("JVM退出了..."); //未执行
}
Runtime类
每个 Java 应用程序都有一个 Runtime
类实例,使应用程序能够与其运行的环境相连接。
public static Runtime getRuntime()
: 返回与当前 Java 应用程序相关的运行时对象。应用程序不能创建自己的 Runtime 类实例。
public long totalMemory()
:返回 Java 虚拟机中初始化时的内存总量。此方法返回的值可能随时间的推移而变化,这取决于主机环境。默认为物理电脑内存的1/64。
public long maxMemory()
:返回 Java 虚拟机中最大程度能使用的内存总量。默认为物理电脑内存的1/4。
public long freeMemory()
:回 Java 虚拟机中的空闲内存量。调用 gc 方法可能导致 freeMemory 返回值的增加。
Runtime runtime = Runtime.getRuntime();
long initialMemory = runtime.totalMemory(); //获取虚拟机初始化时堆内存总量
long maxMemory = runtime.maxMemory(); //获取虚拟机最大堆内存总量
String str = "";
//模拟占用内存
for (int i = 0; i < 10000; i++) {
str += i;
}
long freeMemory = runtime.freeMemory(); //获取空闲堆内存总量
System.out.println("总内存:" + initialMemory / 1024 / 1024 * 64 + "MB");
System.out.println("总内存:" + maxMemory / 1024 / 1024 * 4 + "MB");
System.out.println("空闲内存:" + freeMemory / 1024 / 1024 + "MB") ;
System.out.println("已用内存:" + (initialMemory-freeMemory) / 1024 / 1024 + "MB");
BigInteger类和BigDecimal类
BigInteger
BigInteger可以表示不可变的任意精度的整数,可以模算术、GCD计算、质数测试、素数生成、位操作等。
构造器:BigInteger(String val):根据字符串创建BigInteger对象
- 常用方法
- public BigInteger
abs
():返回此 BigInteger 的绝对值的 BigInteger。 - BigInteger
add
(BigInteger val) :返回其值为 (this + val) 的 BigInteger - BigInteger
subtract
(BigInteger val) :返回其值为 (this - val) 的 BigInteger - BigInteger
multiply
(BigInteger val) :返回其值为 (this * val) 的 BigInteger - BigInteger
divide
(BigInteger val) :返回其值为 (this / val) 的 BigInteger。整数相除只保留整数部分。 - BigInteger
remainder
(BigInteger val) :返回其值为 (this % val) 的 BigInteger。 - BigInteger[]
divideAndRemainder
(BigInteger val):返回包含 (this / val) 后跟 (this % val) 的两个 BigInteger 的数组。 - BigInteger
pow
(int exponent) :返回其值为 (this^exponent) 的 BigInteger。
- public BigInteger
BigDecimal
一般的Float类和Double类可以做科学计算或工程计算。
但在商业计算中,要求数字精度比较高,用到java.math.BigDecimal类。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
- 构造器
- public BigDecimal(double val)
- public BigDecimal(String val) --> 推荐
- 常用方法
- public BigDecimal
add
(BigDecimal augend) - public BigDecimal
subtract
(BigDecimal subtrahend) - public BigDecimal
multiply
(BigDecimal multiplicand) - public BigDecimal
divide
(BigDecimal divisor, int scale, int roundingMode):divisor是除数,scale指明保留几位小数,roundingMode指明舍入模式(ROUND_UP :向上加1、ROUND_DOWN :直接舍去、ROUND_HALF_UP:四舍五入)
- public BigDecimal
public static void main(String[] args) {
int i = Integer.MAX_VALUE;
BigInteger a = new BigInteger(String.valueOf(i));
BigInteger b = new BigInteger(String.valueOf(1000000000));
System.out.println(a.add(b));
BigDecimal c = new BigDecimal(String.valueOf(100));
BigDecimal d = new BigDecimal(String.valueOf(0.412));
System.out.println(c.subtract(d));
System.out.println(c.multiply(d));
//保留15位小数,结果四舍五入
System.out.println(c.divide(d,15,BigDecimal.ROUND_HALF_UP));
}