java log info乱码_跟光磊学Java开发-Java开发常用API的使用
Object类
Object类概述
java.lang.Object类是所有Java类的根类,即所有子类都会直接或者间接继承(Extends)Object类,直接继承是不用写extends Object,编译器会自动添加。java.lang包下的类在使用时不需要使用import关键字导入。
因为Object类是根类,不需要考虑它的继承关系,因此只需要去看看它有哪些方法即常用的方法即可,因为所有的子类都会拥有Object类的方法。
Object类所有的方法
如果你封装了一个JavaBean(即私有化成员变量,提供get/set方法和无参构造器的类),会使用到其父类Object的equals()方法和、oString()方法和hashCode()方法
而notify()方法,notifyAll()方法,wait()方法是多线程情况下使用。getClass()方法是反射特性会使用。
Employee JavaBean设计
Employee 是一个普通的JavaBean,包含三个私有化成员变量以及get/set方法以及构造方法,该类会默认继承java.lang.Object,因此会有父类的方法
package net.ittimeline.java.core.jdk.api.lang.bean;/** * 员工类 默认会继承java.lang.Object * * @author tony 18601767221@163.com * @version 2020/12/16 12:58 * @since JDK11 */public class Employee { /*************************私有化成员变量*****************************************/ /** * 员工编号 */ private String employeeNo; /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; /** * 默认无参数构造器 */ public Employee(){} /** * 全参数构造器 * @param employeeNo * @param name * @param age */ public Employee(String employeeNo, String name, Integer age) { this.employeeNo = employeeNo; this.name = name; this.age = age; } /**************************get/set方法*****************************************/ public String getEmployeeNo() { return employeeNo; } public void setEmployeeNo(String employeeNo) { this.employeeNo = employeeNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}
toString()方法的使用
toString()方法就是返回该对象的字符串表示,默认是返回的对象的全路径名+@加对象地址。
Object类的toString()方法实现
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
当打印输出对象时默认会调用对象的toString()方法
/** * 测试Employee类默认的toString()默认方法,该方法返回对象的字符串 * toString()方法默认会打印 类的全路径+@+对象的地址值 net.ittimeline.java.core.jdk.api.lang.bean.Employee@25e2ab5a * @see Object#toString() */ @Test public void tesEmployeeDefaultToStringMethod(){ Employee employee=new Employee(); //当打印对象时默认会调用对象的toString()方法 log.info("employee = {}",employee); log.info("employee.toString() = {}",employee.toString()); }
程序运行结果
因为Employee类是我们自己封装的一种数据类型,在进行业务系统开发时通常会查看对象的成员变量(也叫属性)值,而不关心对象的全类名和内存地址。
因此一般都会去重写java.lang.Object父类的toString()方法。
/** * 重写父类java.lang.Object的toString()方法 * @return 对象的属性信息的字符串 * @see Object#toString() */ @Override public String toString() { return "Employee{" + "employeeNo='" + employeeNo + ''' + ", name='" + name + ''' + ", age=" + age + '}'; }
重写toString()方法以后,会打印对象的属性值
/** * 测试重写父类java.lang.Object的toString()方法 */ @Test public void testEmployeeOverrideObjectToStringMethod(){ Employee employee=new Employee(); employee.setEmployeeNo("ittimeline00001"); employee.setName("tony"); employee.setAge(28); //当打印对象时默认会调用对象的toString()方法 log.info("employee = {}",employee); log.info("employee.toString() = {}",employee.toString()); }
程序运行结果
JDK提供的API也都重写了java.lang.Object类的toString()方法
StringBuilder重写toString()方法
String类重写toString()方法
equals()方法的使用
java.lang.Object类的equals()方法使用==来判断两个对象是否相等,该方法需要传递一个Object类对象的参数,返回一个布尔值,如果相等则返回true,不等则返回false
public boolean equals(Object obj) { return (this == obj); }
java.lang.Object类的equals()方法比较的是地址是否相等,但是日常开发中通常比较的是对象的成员变量值是否相等,如果属性值不相等则返回false
/** * 父类java.lang.Object的equals()方法使用==判断两个对象的地址是否像等,如果地址不相等返回false */ @Test public void testEmployeeDefaultEqualsMethod(){ //创建两个Employee对象 Employee ittimeline00001=new Employee(); ittimeline00001.setEmployeeNo("ittimeline00001"); ittimeline00001.setName("tony"); ittimeline00001.setAge(28); Employee ittimeline00002=new Employee(); ittimeline00002.setEmployeeNo("ittimeline00001"); ittimeline00002.setName("tony"); ittimeline00002.setAge(28); log.info("ittimeline00001 == ittimeline00002 {}",(ittimeline00001==ittimeline00002)); //ittimeline00002 是Object类的子类对象,因此可以使用参数多态作为equals()方法的参数 log.info("ittimeline00001.equals(ittimeline00002) = {}",(ittimeline00001.equals(ittimeline00002))); }
程序运行结果
因此如果想要判断对象的属性值是否相等,我们还需要重写java.lang.Object类的equals()方法,一般重写equals()方法都要重写hashCode()方法。
/** * 重写java.lang.Object的equals()方法 * @param object * @return * @see Object#equals(Object) */ @Override public boolean equals(Object object) { //如果两个对象的地址相等则返回true if(this==object){ return true; } //方法的参数为空或者类型不一样返回false if(null==object||this.getClass()!=object.getClass()){ return false; } Employee targetEmployee= (Employee) object; //判断如果员工编号一样就表示同一个员工 return Objects.equals(this.getEmployeeNo(),targetEmployee.getEmployeeNo()); } @Override public int hashCode() { return Objects.hash(employeeNo, name, age); }
重写后再次创建两个对象并分别调用==和equals()方法来判断两个对象的相等性
/** * 测试重写父类java.lang.Object的equals()方法 */ @Test public void testEmployeeOverrideObjectEqualsMethod(){ //创建两个Employee对象 Employee ittimeline00001=new Employee(); ittimeline00001.setEmployeeNo("ittimeline00001"); ittimeline00001.setName("tony"); ittimeline00001.setAge(28); Employee ittimeline00002=new Employee(); ittimeline00002.setEmployeeNo("ittimeline00001"); ittimeline00002.setName("tony"); ittimeline00002.setAge(28); log.info("ittimeline00001 == ittimeline00002 {}",(ittimeline00001==ittimeline00002)); //ittimeline00002 是Object类的子类对象,因此可以使用参数多态作为equals()方法的参数 log.info("ittimeline00001.equals(ittimeline00002) = {}",(ittimeline00001.equals(ittimeline00002))); }
程序运行结果
程序运行结果表明重写equals()方法以后,==判断的返回结果是false,而equals()方法返回的是true
看到这里读者应该能够解决一个面试题: ==和equals()方法有什么区别。回答该问题时应该先考虑未重写equals()前的行为和重写equals()后的行为。
Objects类
java.util.Objects类是JDK7以后新增的一个工具类,该类包含许多关于Object操作的静态方法,也就是可以直接通过类名.方法名调用。
java.util.Objects类提供的方法都是空指针安全的,也就是能够避免空指针异常。日常开发中应该尽量避免空指针异常。
我们可以学习Objects类的equals()方法的实现,如果避免空指针异常。
public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); }
equals()方法需要两个Object类型的参数,通常是传递的自己封装的类的成员变量。
equals()该方法的执行流程是
- 判断两个对象的地址是否相同,如果相同根据逻辑或的短路特性,直接返回true
- 如果两个对象的地址不同,则会判断第一个参数a是不是空,如果为空则会根据逻辑与的短路特性直接返回false
- 如果a不为空则调用两个参数的equals()方法来判断是否相等
在没有Objects提供的equals()方法前,如果使用JDK提供的API的equals()方法容易引发空指针异常
//测试String对象的相等性判断 @Test public void testStringEquals(){ // 使用String类的equals()进行相等性判断容易引发空指针 String str1 = null; String str2 = "tony"; log.info("str1 .equals(str2) = {}", str1.equals(str2)); }
程序运行结果
此时可以使用Objects提供的equals()方法来判断String的相等性
/** * 使用Objects.equals()方法判断String相等性 */ @Test public void testObjectsStringEquals(){ String str1 = null; String str2 = "tony"; log.info("Objects.equals(str1,str2) = {}", Objects.equals(str1, str2)); String str3="tony"; log.info("Objects.equals(str3,str2) = {}", Objects.equals(str3, str2)); String str4=new String("tony"); log.info("Objects.equals(str4, str2) = {}", Objects.equals(str4, str2)); }
程序运行结果
因此后面在日常开发中应该是用java.util.Objects类提供的equals()方法来比较两个对象是否相等。这样能够避免空指针异常。
因为Objects的equals()方法需要两个Object类型的参数,因此根据形参多态的特性,所有的Object子类都可以做为该方法的参数
/** * 使用Objects.equals()方法判断两个Employee对象是否相等 */ @Test public void testEmployeeObjectsEqualsMethod() { //创建两个不同属性值的Employee对象 Employee ittimeline00001=new Employee(); ittimeline00001.setEmployeeNo("ittimeline00001"); ittimeline00001.setName("tony"); ittimeline00001.setAge(28); Employee ittimeline00002=new Employee(); ittimeline00002.setEmployeeNo("ittimeline00002"); ittimeline00002.setName("jack"); ittimeline00002.setAge(27); boolean equalsResult= Objects.equals(ittimeline00001,ittimeline00002); log.info("equalsResult = {}",equalsResult); Employee ittimeline00003=ittimeline00001; equalsResult= Objects.equals(ittimeline00001,ittimeline00003); log.info("equalsResult = {}",equalsResult); }
程序运行结果
native 方法
native方法称为本地方法,本地方法没有方法体,我们也无法查看其实现,当我们需要访问C/C或者访问操作系统底层的类库时可以使用本地方法实现,也意味着Java语言可以通过JNI和其他语言进行交互。
本地方法的作用就是当Java调用非Java代码的接口时,方法的实现是非Java实现,通常都是C/C实现。
Object类中的getClass(),hashCode(),notify(),notifyAll(),wait()都是使用C/C++实现的本地方法
public final native Class> getClass();public native int hashCode(); public final native void notify(); public final native void notifyAll();public final native void wait(long timeoutMillis) throws InterruptedException;
时间日期类
Date类
Date类表示日期,时间精确到毫秒。
Date类是JDK1.0设计的类,因为其本身有些缺陷,在Java8重新设计了一套日期API,因此Date类的很多方法都已经标记为过时了,如果方法上有个@Deprecated注解就表示该方法已经过时,在日常开发中尽量避免使用过时的方法,因为JDK或者框架会在后期的版本升级中删除过时的方法,那样我们的程序会无法编译通过。
Date类有两个常用的构造函数
public Date() { this(System.currentTimeMillis()); } public Date(long date) { fastTime = date; }
其中无参数的构造器是以当前的时间创建日期对象
/** * 测试无参数的构造器 */ @Test public void testDateNoArgsConstructMethod(){ /** * 默认以当前时间创建日期对象 */ Date currentDate=new Date(); //Wed Dec 16 15:29:07 CST 2020 // CST 表示中国标准时间 // Dec 16 表示12月16日 // Wed 表示星期三 System.out.println(currentDate); }
程序运行结果
而传long参数的构造器用创建一个以标准时间为基准,指定偏移毫秒数对应的日期对象
- 标准时间指的是1970年1月1日 00:00:00 ,也就是Unix系统的诞生日,而我们伟大的祖国母亲是位于东八区,因此标准时间是1970年1月1日:08:00:00
@Test public void testDateLongArgsConstructMethod(){ /** * 以标准基准时间为基准,指定偏移毫秒数对应的日期对象 * 标准基准时间是格林威治时区: 1970年1月1日 00:00:00 * 中国处于东八区: 1970年1月1日:08:00:00 */ Date offSetDate=new Date(1000); //Thu Jan 01 08:00:01 CST 1970 System.out.println(offSetDate); }
程序运行结果
Date类还提供了getTime()获取标准当前日期距离标准基准时间的毫秒数,该方法的返回值可以用于统计程序的时间耗时,作为程序性能优化的依据,setTime()用于置当前日期对象距离标准基准时间的毫秒数
@Test public void testDateGetTimeMethod(){ Date now=new Date(); //获取当前日期对象距离标准基准时间的毫秒数 long milliseconds=now.getTime(); log.info("获取当前日期对象距离标准基准时间的毫秒数 {}",milliseconds); //设置当前日期对象距离标准基准时间1970年1月1日:08:00:00的毫秒数 now.setTime(2000); System.out.println("now = "+now); }
程序运行结果
Date类还提供了before()和after()方法用于比较两个日期
@Test public void testDateBeforeAfterMethod(){ //以当前时间创建日期对象 Date currentDate=new Date(); System.out.println("currentDate = "+currentDate); //从1970-01-01 08:00:00 加2000毫秒 1970-01-01 08:00:02 Date customDate=new Date(2000); System.out.println("customDate = "+customDate); log.info("customDate.before(currentDate) = {}",customDate.before(currentDate)); log.info("customDate.after(currentDate) = {}",customDate.after(currentDate)); }
程序运行结果
DateFormat类
java.text.DateFormat类是一个日期/时间格式化的抽象类,其应用场景是当Web前端传递过来的日期都是字符串形式,Java后端接收时需要按照指定的格式进行日期转换后存储到数据库。
由于DateFormat是一个抽象类,因此需要使用该类的子类SimpleDateFormat来实现日期/时间格式化。也就是将字符串日期和Date日期相互转换。
在创建SimpleDateFormat对象时需要传入指定的日期格式参数
public SimpleDateFormat(String pattern) { this(pattern, Locale.getDefault(Locale.Category.FORMAT)); }
常用的日期格式有yyyy年MM月dd日 HH时mm分ss秒和 yyyy-MM-dd HH:mm:ss
- y 表示年
- M 表示月
- d 表示日
- HH 表示小时
- mm 表示分钟
- ss 表示秒钟
SimpleDateFormat提供了format()方法用于将日期转换为字符串
/** * 标准日期格式常量 */ public static final String DEFAULT_PATTERN="yyyy-MM-dd HH:mm:ss"; /** * * 使用SimpleDateFormat的format()方法实现日期转字符串 * */ @Test public void testSimpleDateFormatDateToString(){ //按照指定的日期格式创建日期格式化对象 DateFormat dateFormatDefaultPattern =new SimpleDateFormat(DEFAULT_PATTERN); //调用format()方法将日期转换为字符串 //日期对象使用的是匿名对象 String defaultPatternDateToStr=dateFormatDefaultPattern.format(new Date()); log.info("defaultPatternDateToStr = {}",defaultPatternDateToStr); }
程序运行结果
SimpleDateFormat提供了parse()方法用以将字符串转换为日期
/** * 使用SimpleDateFormat的parse()方法将日期转换为字符串 * @throws ParseException */ @Test public void testSimpleDateFormatStringToDate()throws ParseException{ //创建日期字符串 String dateStr= "2020-12-16 16:02:00"; //按照指定的格式创建日期格式化对象 DateFormat dateFormatDefaultPattern =new SimpleDateFormat(DEFAULT_PATTERN); //通过parse()方法讲将字符串转换为日期对象 Date stringToDateResult =dateFormatDefaultPattern.parse(dateStr); System.out.println("stringToDateResult = "+stringToDateResult); }
程序运行结果
一个日期和格式化的案例:从键盘读取用户输入的生日,然后计算天数
程序实现思路
- 创建Scanner对象调用netxtLine()方法获取用户输入的生日字符串
- 使用SimpleDateFormat的parse()方法将生日字符串转换为Date日期
- 调用Date日期对象的getTime()方法获取系统基准时间到生日的毫秒数
- 调用当前日期对象额getTime()方法获取系统基准时间到当前时间的毫秒数
- 当前时间的毫秒数减去生日毫秒数后求天数。
程序实现代码
package net.ittimeline.java.core.jdk.api.text;import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Scanner;/** * 从键盘读取用户输入的生日,然后计算天数 * * @author tony 18601767221@163.com * @version 2020/12/16 16:24 * @since JDK11 */public class DateFormatBirthdayCalculatorTest { public static void main(String[] args) throws ParseException { Scanner input =new Scanner(System.in); System.out.println("请输入你的生日(格式为 yyyy-MM-dd)"); String birthdayStr=input.nextLine(); DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd"); Date birthdayDate=dateFormat.parse(birthdayStr); long birthdayMilliseconds= birthdayDate.getTime(); long currentMilliseconds=new Date().getTime(); long day=(currentMilliseconds-birthdayMilliseconds)/1000/60/60/24; System.out.printf("你已经来到这个世界%d天了",day); input.close(); }}
程序运行结果
Calendar类
java.uti.Calendar是一个抽象类,用于表示日历,包含日日期/时间信息,可以进行日期的运算。
Calendar不能创建对象,一般是使用它的子类:java.util.GregorianCalendar类
有两种方法可以创建GregorianCalendar对象
/** * 获取日历对象的两种方法 */ @Test public void testCreateCalendar() { // 当前系统时间的日历对象 Calendar calendarInstance = Calendar.getInstance(); Calendar calendar=new GregorianCalendar(); System.out.println(calendar); }
当创建GregorianCalendar对象后打印输出该对象会看到如下信息
java.util.GregorianCalendar[time=1608110761595,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2020,MONTH=11,WEEK_OF_YEAR=51,WEEK_OF_MONTH=3,DAY_OF_MONTH=16,DAY_OF_YEAR=351,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=26,SECOND=1,MILLISECOND=595,ZONE_OFFSET=28800000,DST_OFFSET=0]
关于GregorianCalendar对象关于日期/时间的属性名/属性值说明
- time=1608110761595 表示当前时间距离标准基准时间的毫秒数
- ZoneInfo 用于描述时区信息,当前时区是亚洲/上海,比标准基准时间晚8个小时
- MONTH=11 表示今天是今年的12月份,GregorianCalendar对象的月分是从0开始
- WEEK_OF_YEAR=51 表示今天是今年的51周
- WEEK_OF_MONTH=3 表示今天是这个月的第三周
- DAY_OF_WEEK=4 表示今天是这周的第四天,因为外国是从周日到周六,也就是说周日是一周的第一天,而今天(2020/12/16)按照外国人的算法就是周四
- DAY_OF_MONTH=16 表示今天是这个月的16天
- DAY_OF_YEAR=351 表示今天是今天的351天,难过的2020马上就要结束了
- DAY_OF_WEEK_IN_MONTH=3 表示今天是这个月的第三周
GregorianCalendar 提供了get()方法用于获取日历的日期/时间信息
/** * 通过GregorianCalendar对象的get方法获取日历的日期/时间信息 * * @see GregorianCalendar#get(int) */ @Test public void testCalendarGetMethod() { // 当前系统时间的日历对象 Calendar calendarInstance = Calendar.getInstance(); int year = calendarInstance.get(Calendar.YEAR); int month = calendarInstance.get(Calendar.MONTH); int day = calendarInstance.get(Calendar.DAY_OF_MONTH); int hour=calendarInstance.get(Calendar.HOUR_OF_DAY); int minute = calendarInstance.get(Calendar.MINUTE); int second=calendarInstance.get(Calendar.SECOND); System.out.printf("通过GregorianCalendar对象的get()方法获取日期信息:%d年%d月%d日 %d时%d分%d秒", year, month, day,hour,minute,second); }
程序运行结果
GregorianCalendar 提供了set()方法设置指定的日期/时间,add()方法增加日期/时间
/** 修改日历对应日期 add 增加日期/时间 set 设置指定的日期/时间 */ @Test public void testCalendarUpdate() { Calendar calendarInstance = Calendar.getInstance(); // 将年份设置为1999 calendarInstance.set(Calendar.YEAR, 1999); System.out.println("将年份设置为1999 当前年份是" + calendarInstance.get(Calendar.YEAR)); // 将当前的年份加两年 calendarInstance.add(Calendar.YEAR, 2); System.out.println("将当前的年份加两年 当前年份是" + calendarInstance.get(Calendar.YEAR)); // 将当年的年份减少2年 calendarInstance.add(Calendar.YEAR, -2); System.out.println("将当年的年份减少2年 当前年份是" + calendarInstance.get(Calendar.YEAR)); }
GregorianCalendar 还提供了setTime()的方法用于通过传递一个Date日期的参数来设置日历
/** 获取距离标准时间2小时的日历对象 */ @Test public void testCalendarSetTimeMethod() { Calendar calendarInstance = Calendar.getInstance(); // 首先获取距离标准时间2小时的日期 Date date = new Date(1000 * 60 * 60 * 2); // 调用日历对象的setTime()方法设置日历对象设置的日期 calendarInstance.setTime(date); log.info(calendarInstance); }
程序运行结果
GregorianCalendar 也提供了用于两个日历对象的比较方法:before()和after()
/** before() 判断此Calendar表示的时间是否在指定的Object表示的时间之前 ,返回布尔值。 */ @Test public void testCalendarBefore() { Calendar source = Calendar.getInstance(); System.out.printf("通过GregorianCalendar对象的get()方法获取source日期信息:%d年%d月%d日", source.get(Calendar.YEAR), source.get(Calendar.MONTH), source.get(Calendar.DAY_OF_MONTH)); //以标准基准时间偏移24小时创建日历对象 Calendar target = Calendar.getInstance(); Date date = new Date(1000 * 60 * 60 * 24); target.setTime(date); System.out.printf( "通过GregorianCalendar对象的get()方法获取target日期信息:%d年%d月%d日", target.get(Calendar.YEAR), target.get(Calendar.MONTH), target.get(Calendar.DAY_OF_MONTH)); boolean beforeResult = source.before(target); System.out.println("source.before(target)= "+beforeResult); boolean afterResult = source.after(target); System.out.println("source.after(target)= "+afterResult); }
程序运行结果
Math类
java.lang.Math类提供了一些关于数学运算的静态方法,即它的方法都是使用static修饰的,直接通过类名.方法名调用即可。
在日常开发中常用的Math提供的方法如下
- Math.abs()求一个数值的绝对值
/** Math.abs()求一个数值的绝对值 */ @Test public void testMathAbsMethod() { System.out.println("10的绝对值是"+Math.abs(10)); System.out.println("-10的绝对值是"+Math.abs(-10)); System.out.println("2.0的绝对值是"+Math.abs(2.0)); System.out.println("-2.0的绝对值是"+Math.abs(-2.0)); }
程序运行结果
- Math.ceil() 向上取整
- Math.floor() 向下取整
/** Math.ceil() 向上取整 大于这个数的最小整数 */ /** Math.floor() 向下取整 小于这个数的最小整数 */ @Test public void testMathCeilFloorMethod() { //3.2向上取整就是4.0 System.out.println("3.2向上取整的结果是"+Math.ceil(3.2)); //-3.2向上取整就是-3 System.out.println("-3.2向上取整的结果是"+Math.ceil(-3.2)); //3.2向下取整就是3.0 System.out.println("3.2向下取整的结果是"+Math.floor(3.2)); }
程序运行结果
- Math.pow(m,n) 求m的n次幂
/** * Math.pow(m,n) 计算m的n次方 */ @Test public void testMathPowMethod() { //计算2的3次方 System.out.println("2.0的3.0次幂的结果是"+Math.pow(2.0,3.0)); }
程序运行结果
- Math.round() 四舍五入
/** * Math.round() 四舍五入 */ @Test public void testMathRoundMethod() { System.out.println("3四舍五入的结果是"+Math.round(3)); System.out.println("99四舍五入的结果是"+Math.round(99)); System.out.println("3.49四舍五入的结果是"+Math.round(3.49)); System.out.println("3.50四舍五入的结果是"+Math.round(3.50)); }
程序运行结果
- Math.max()求两个数的最大值
- Math.min() 求两个数的最小值
/** * Math.max()获取最大值 * Math.min()获取最小值 */ @Test public void testMatMaxMinMethod() { System.out.println("10,20的最大值是"+Math.max(10,20)); System.out.println("10,20的最小值是"+Math.min(10,20)); }
程序运行结果
System类
java.lang.System类表示系统,不能实例化,因此该类提供了大量的静态方法用于获取或者去操作系统。
- System.getProperty()方法来获取系统的属性
首先使用System.getProperties().list(System.out);将所有的系统属性输出在终端后,使用System.getProperty()方法根据属性名获取属性值
/** * 获取系统属性 */ @Test public void testSystemGetProperties() { //将所有的系统属性输出在终端上 System.getProperties().list(System.out); System.out.println("当前Java程序依赖的JDK版本是"+System.getProperty("java.version")); System.out.println("当前Java程序依赖的JVM是"+System.getProperty("java.vm.name")); System.out.println("当前Java程序依赖的操作系统版本是"+System.getProperty("os.name")); System.out.println("当前Java程序的字节码版本是"+System.getProperty("java.class.version")); }
程序运行结果
程序运行结果
- System.getenv()获取系统所有环境变量
/** * 获取系统环境变量 */ @Test public void testSystemGetEnv() { // 将所有的系统属性输出在终端上 System.out.println(System.getenv()); }
程序运行结果
- System.arraycopy()方法实现数组的复制
@Test public void testSystemArrayCopyMethod(){ int[]source={1,2,3,4,5,6,7,8}; int[] target={10,20,30,40,50,60,70,80}; //将source的5,6,7,8拷贝到target的50,60,70,80 System.arraycopy(source,4,target,4,4); //输出结果 [10, 20, 30, 40, 5, 6, 7, 8] System.out.println("target = "+Arrays.toString(target)); }
程序运行结果
- System.currentTimeMillis()方法用于获取当前时间到标准基准时间的毫秒数,等价于调用Date对象的getTime()方法
@Test public void testSystemCurrentTimeMillisMethod(){ //获取当前时间到标准基准时间的毫秒数 // 等价与new Date().getTime(); System.out.println(System.currentTimeMillis()); System.out.println(new Date().getTime()); }
程序运行结果
我们可以基于System.currentTimeMillis()方法实现计算某段程序的耗时
/** * 统计程序耗时 */ @Test public void tesSystemOutStatisticTime(){ long start=System.currentTimeMillis(); for (int i = 0; i <100; i++) { System.out.println("i = "+i); } long end=System.currentTimeMillis(); log.info("程序耗时 {}毫秒",(end-start)); }
程序运行结果
包装类
之前学习的八种基本数据类型都不具备面向对象的特征:没有属性和方法,也没法创建对象,更没有面向对象的三大特征:封装、继承和多态。但是基本数据类型也有它的优势,主要在于存储方面。因此大佬们设计了8种基本数据类型的包装类,包装类就是将基本数据类型转换为对应的引用数据类型。
- byte的包装类是java.lang.Byte
- short的包装类是java.lang.Short
- char的包装类是java.lang.Char
- int的包装类是java.lang.Integer
- long的包装类是java.lang.Long
- float的包装类是java.lang.Float
- double的包装类是java.lang.Double
这里以开发中常用的Integer类来说明包装类的使用
Integer类定义了其占据的字节数,取值范围的常量,如果你忘记了int的取值范围,可以直接查看Integer类的源码,或者直接通过Integer类调用对应的常量获取
/** * Integer类定义了其占据的字节数,取值范围的常量 */ @Test public void testIntegerConstants(){ System.out.printf("int占据的字节数量是%d,int存储的最小值是%d,int存储的最大值是%d",Integer.BYTES,Integer.MIN_VALUE,Integer.MAX_VALUE); }
Integer类也定义了方法用于实现将int和Integer的相互转换
- valueOf()方法实现将int转换为Integer
- intValue()方法实现将Integer转换为int
/** int和Integer的相互转换 */ @Test public void testIntegerCast() { // 使用valueOf()方法将int转换为Integer Integer integer = Integer.valueOf(123); System.out.println("integer = " + integer); // intValue()方法将Integer转换为int int intValue = integer.intValue(); System.out.println("intValue = " + intValue); }
程序运行结果
但是日常开发中经常使用的是字符串和Integer之间的转换,因为前台传过来的都是字符串类型的数据
- parseInt()方法用于将字符串转换为Integer
@Test public void testIntegerStringCast(){ // 使用valueOf()方法将String转换为Integer Integer value = Integer.valueOf("123"); System.out.println("value = " + value); // 日常开发中常用的方法是将字符串转换为Integer对象 Integer integerValue=Integer.parseInt("999"); System.out.println("integerValue = "+integerValue); }
程序运行结果
JDK1.5以后支持了自动拆箱和装箱
- 自动拆箱: 将包装类自动转换为对应的基本数据类型
- 自动装箱:将基本数据类型自动转换为对应的包装类类型
/** * 自动拆箱和装箱 */ @Test public void testAutoBox(){ //自动装箱:将long自动转换为java.lang.Long Long longValueRef=70_00000000L; //自动拆箱:将java.lang.Long自动转换为long long longValue=longValueRef; System.out.printf("longValue = %d longValueRef = %d",longValue,longValueRef); }
程序运行结果
在日常开发中还会使用到基本数据类型和字符串之间的相互转换
- String.valueOf()静态方法用于将基本数据类型转换为String
/** * 基本数据类型转换为String */ @Test public void testPrimitiveTypeCast(){ int intValue=123; String stringValueInt=String.valueOf(intValue); long longValue=123456789L; String stringValueLong=String.valueOf(longValue); System.out.printf("stringValueInt = %s stringValueLong = %s ",stringValueInt,stringValueLong); }
程序运行结果
- 除了Character类以外,其他所有的包装类都提供了valueOf()静态方法用于将字符串转换为对应的包装类类型
/** * 字符串转包装类 */ @Test public void testStringCastWrapperClass(){ String str="123"; Byte byteRef=Byte.valueOf(str); Long longRef=Long.valueOf(str); System.out.printf("byteRef = %d longRef =%d",byteRef,longRef); }
程序运行结果
- 除了Character以外,其他所有包装类都提供了parseXX()静态方法将字符串参数转换为任意的基本数据类型
/** * 字符串转换为基本数据类型 */ @Test public void testStringCastPrimitiveType(){ String str="123"; long longValue=Long.parseLong(str); double doubleValue=Double.parseDouble(str); byte byteValue=Byte.parseByte(str); System.out.println("longValue = "+longValue); System.out.println("doubleValue = "+doubleValue); System.out.println("byteValue = "+byteValue); String bool="boolean"; boolean blValue=Boolean.parseBoolean(bool); System.out.println("blValue = "+blValue); }
程序运行结果
BigInteger类
java.math.BigInteger类表示一个超大的整数,也就是支持任意精度的整数。
当Integer,Long类型的整数不能满足存储和计算的要求,此时可以使用字符串的整数构建一个BigInteger对象。
/** * BigInteger构造器的使用 */ @Test public void testBigIntegerConstruct() { Integer intMax = Integer.MAX_VALUE; Long longMax = Long.MAX_VALUE; System.out.printf("int表示的最大值是%d long 表示的最大值是%d", intMax, longMax); //此处会编译错误,超过了long的表示范围 // long value=9223372036854775808L; BigInteger source=new BigInteger("9223372036854775808"); BigInteger target=new BigInteger("9223372036854775809"); log.info("source = {} target = {}",source,target); }
程序运行结果
构造BigInteger对象之后可以使用其提供的方法完成大整数的算术运算
/** * 使用BigInteger完成两个大整数的算术运算 */ @Test public void testBigIntegerArithmetic(){ BigInteger source=new BigInteger("9223372036854775808"); BigInteger target=new BigInteger("100"); log.info("source = {} target = {}",source,target); BigInteger addResult=source.add(target); log.info("addResult = {}",addResult); BigInteger subtractResult=source.subtract(target); log.info("subtractResult = {}",subtractResult); BigInteger multiplyResult=source.multiply(target); log.info("multiplyResult = {}",multiplyResult); BigInteger divideResult=source.divide(target); log.info("divideResult = {}",divideResult); }
程序运行结果
BigDecimal类
浮点数在运算时得到的是一个无限接近结果的近似值,也就是存在精度问题。
/** * 浮点数的运算结果是不精确的 * 0.09 + 0.01 = 0.09999999999999999 * 1.0 - 0.32 = 0.6799999999999999 * 1.015 * 100 = 101.49999999999999 * 1.301 / 100 = 0.013009999999999999 */ @Test public void testFloatPrecision(){ System.out.println("0.09 + 0.01 = "+(0.09 + 0.01 )); System.out.println("1.0 - 0.32 = "+(1.0-0.32 )); System.out.println("1.015 * 100 = "+(1.015 * 100 )); System.out.println("1.301 / 100 = "+(1.301 / 100 )); }
程序运行结果
BigDecimal类表示任意精度的十进制浮点数,可以解决浮点数运算的精度问题。
/** * 使用BigDecimal进行任意精度浮点数的算术运算 */ @Test public void testBigDecimalArithmetic(){ BigDecimal source=new BigDecimal("0.09"); BigDecimal target=new BigDecimal("0.01"); log.info("source = {} target = {}",source,target); BigDecimal addResult=source.add(target); log.info("addResult = {}",addResult); source=new BigDecimal("1.0"); target=new BigDecimal("0.32"); log.info("source = {} target = {}",source,target); BigDecimal subtractResult=source.subtract(target); log.info("subtractResult = {}",subtractResult); source=new BigDecimal("1.015"); target=new BigDecimal("100"); log.info("source = {} target = {}",source,target); BigDecimal multiplyResult=source.multiply(target); log.info("multiplyResult = {}",multiplyResult); source=new BigDecimal("1.301"); target=new BigDecimal("100"); BigDecimal divideResult=source.divide(target); log.info("divideResult = {}",divideResult); }
程序运行结果
但是使用字符串参数的构造器创建BigDecimal对象时在进行除法运算如果除不尽。例如10/3=3.3333 就会抛一个算术异常
/** * 除法除不尽就会抛异常 */ @Test public void testBigDecimalDivideMethod(){ BigDecimal source=new BigDecimal("10"); BigDecimal target=new BigDecimal("3"); BigDecimal divideResult=source.divide(target); System.out.println(divideResult); }
程序运行结果
为了解决BigDecimal除法的算术异常(ArithmeticException),可以使用BigDecimal重载的devide()方法。
/** * 使用重载的divide方法解决除法除不尽的算术异常 */ @Test public void testBigDecimalOverrideDivideMethod(){ BigDecimal source=new BigDecimal("10"); BigDecimal target=new BigDecimal("3"); /** * 重载的divide方法参数说明 * divisor 除数对应的BigDecimal对象 * scale 精确的位数 * roundingMode:取舍模式 */ //计算结果四舍五入 保留2位, BigDecimal divideResult=source.divide(target,2, RoundingMode.HALF_UP); log.info("divideResult = {}",divideResult); }
程序运行结果
在使用BigDecimal是需要注意,不能使用double类型的参数创建BigDecimal对象,其运算的结果也是不精确的
/** * 使用浮点数参数的构造器只能获得更加无限接近的结果,但是还是有精度损失问题 */ @Test public void testBigDecimalFloatConstruct(){ BigDecimal source= new BigDecimal(0.09); BigDecimal target= new BigDecimal(0.01); BigDecimal addResult=source.add(target); System.out.println("0.09 + 0.01 ="+addResult); }
程序运行结果
Arrays类
java.util.Array类是JDK提供的一个工具类,用于数组的常用操作:排序,查找,复制,比较,等等。
- Arrays.sort()方法可以实现数组元素的升序排序,该方法支持八种基本数据类型的数组元素
/** 数组升序排序 */ @Test public void testArraySort() { int[] numbers = {1, 2, 4, 5, 6, 7, 8, 9, 6, 3}; // 将整型数组按照升序排序 Arrays.sort(numbers); // 将数组以字符串打印在终端 System.out.println(Arrays.toString(numbers)); }
程序运行结果
- Arrays.binarySearch()方法可以实现数组元素二分法查找,查找之前需要对数组进行排序,该方法支持八种基本数据类型的数组元素
/** 数组二分法查找 */ @Test public void testArrayBinarySearch() { int[] numbers = {1, 2, 4, 5, 6, 7, 8, 9, 6, 3}; // 将整型数组按照升序排序 Arrays.sort(numbers); // 将数组以字符串打印在终端 System.out.println(Arrays.toString(numbers)); //使用二分法查找指定的数字5,返回5在数组中的索引 int key =5 ; int index = Arrays.binarySearch(numbers, 5); System.out.printf("%d在数组中的索引位置是%d",key,index); }
程序运行结果
java log info乱码_跟光磊学Java开发-Java开发常用API的使用相关推荐
- java数据库的量级_程序员学Python还是Java?分析了8张图后得出这个结论
Java和Python两门语言都是目前非常热门的语言,可谓北乔峰南慕容,二者不分上下,棋逢对手.但是对于初学者来说,非常困惑,因为时间和精力有限,上手必须要先学一门,到底选那个好呢,今天3分钟带你透彻 ...
- java 注解 属性 类型_跟光磊学Java开发-Java注解
注解概述 注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记以后,java编译器.开发工具或者其他的框架就可以通过反射来获取类以及类的成员上的注解,然后通过作相应的处 ...
- 找工作java还是python有用_你觉得学 Python 还是 Java 更好找工作?
不管现在大家如何追捧和吹嘘Python,培训机构怎么勾搭,广告怎么打,你打开招聘网站,在相同的搜索条件下搜下"Python"和"Java"两个关键词,认真的查看 ...
- 表达式必须具有与对应表达式相同的数据类型_跟光磊学Java开发-运算符和表达式...
运算符和表达式 运算符是用于对常量或者变量操作的符号,而表达式是用运算符把常量或者变量组合起来符合Java语法的式子就称为表达式.不同运算符连接的表达式体现的是不同类型的表达式. package ne ...
- python在匿名函数作和_跟光磊学Python开发-匿名函数函数和高阶函数
跟光磊学Python开发-匿名函数函数和高阶函数 跟光磊学Python开发-匿名函数函数和高阶函数跟光磊学Python开发 匿名函数 匿名函数就是函数定义时没有名字的函数,也称为匿名表达式. 普通函数 ...
- alpine linux图形界面_跟光磊学Linux运维-Linux入门与基本使用
认识Linux用户 在安装CentOS8.2时,设置过root用户的密码,同时也创建了用户guanglei. 其中root用户是系统自带的管理员账户,也被称为超级用户,root用户接近系统完整的控制能 ...
- java gc日志乱码_让bug无处藏身,Java 线上问题排查思路、常用工具
本文总结了一些常见的线上应急现象和对应排查步骤和工具.分享的主要目的是想让对线上问题接触少的同学有个预先认知,免得在遇到实际问题时手忙脚乱. 公--主--号: 我的名称"java小白学心理& ...
- 小白学习python好还是java好_小白应该学Python还是Java?
Java和Python两门语言都是目前非常热门的语言,可谓北乔峰南慕容,二者不分上下,棋逢对手.但是对于初学者来说,非常困惑,因为时间和精力有限,上手必须要先学一门,到底选那个好呢,今天3分钟带你透彻 ...
- linux下log日志乱码_如何用 Linux 技巧大大提高工作效率?
作者 | 守望先生 责编 | 屠敏 前言 Linux中的一些小技巧可以大大提高你的工作效率,本文就细数那些提高效率或者简单却有效的Linux技巧. 命令编辑及光标移动 这里有很多快捷键可以帮我们修正自 ...
- java程序设计实用教程_清华大学出版社-图书详情-《Java程序设计实用教程》
技术具有卓越的通用性.高效性.平台移植性和安全性,经过20多年的发展,目前已广泛应用于PC.数据中心.游戏控制台.超级计算机.移动电话和互联网,同时拥有全球最大的开发者专业社群.在全球云计算和移动互联 ...
最新文章
- 《UNIX环境高级编程(第3版)》——1.7 出错处理
- 利用OpenCV进行边缘检测
- 群晖备份linux分区,黑群晖二合一系统无损扩充系统分区方法补充
- [转载] - QWidget、QMainWindow、QDialog和QFrame的区别
- Python中局部变量和全局变量的详解
- cad隐藏图层命令快捷键_cad快捷键f是什么命令?cad中f快捷键都有哪些?
- 哈希表的大小为何最好是素数
- 当包装类的要与基本类型进行比较时候 需要先将包装类降级为基本类型
- P1396 营救(并查集+二分)
- Android 应用开发(42)---ImageView
- java socket client_java socket client
- 每日算法系列【LeetCode 992】K个不同整数的子数组
- *第八周*数据结构实践项目二【建设链串算法库】
- SqList *L与SqList *L的区别
- 卡拉曼达聊天服务器断开修复也没用,英雄联盟新版客户端 聊天系统神似QQ
- bmd硬盘测试_disk speed test mac版下载-Blackmagic Disk Speed Test for Mac(硬盘读写速度测试工具) v3.2免费版 - Mac天空...
- JPEG文件编/解码详解
- cat/tac查询命令
- java获取和风天气_和风天气(一)数据分析
- 鹏业安装算量软件识别电气系统图(表格式)