Java基础学习14之Date类及比较器Comparable

2,170 阅读10分钟

Java基础学习14之Date类及比较器Comparable

「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」。

关于作者

  • 作者介绍

🍓 博客主页:作者主页
🍓 简介:JAVA领域优质创作者🥇、一名在校大三学生🎓、在校期间参加各种省赛、国赛,斩获一系列荣誉🏆。
🍓 关注我:关注我学习资料、文档下载统统都有,每日定时更新文章,励志做一名JAVA资深程序猿👨‍💻。


日期处理类—Date类

java.util.data类是在整个程序处理之中唯一可以取得日期当前日期实例化对象的操作方法,也就是说我们要取出当前日期输出Date类对象即可。

public class Date extends Object implements Serializable, Cloneable, Comparable<Date> 实现了Serializable、Serializable、Comparable接口。

Date (Java Platform SE 8 )

  • Date课程以Date级的Date表示特定的时间。

    在JDK 1.1之前, Date有两个附加功能。 它允许将日期解释为年,月,日,小时,分钟和第二个值。 它还允许格式化和解析日期字符串。 不幸的是,这些功能的API不适合国际化。 从JDK 1.1开始, Calendar类应该用于在日期和时间字段之间进行转换,并且DateFormat类应用于格式化和解析日期字符串。 在相应的方法Date被弃用。

    尽管Date类旨在反映协调的世界时间(UTC),但根据Java虚拟机的主机环境的不同,可能不会这样做。 几乎所有的现代操作系统都假设在所有情况下1天= 24×60×60 = 86400秒。 然而,在UTC的时候,大概每一两年会有一秒钟的时间,叫做“闰秒”。 闰秒总是作为一天的最后一秒,总是在12月31日或6月30日。例如,1995年的最后一分钟是61秒,由于增加了闰秒。 大多数计算机时钟不够准确,不能反映出闰秒的区别。

    一些计算机标准是根据格林尼治标准时间(GMT)定义的,相当于世界时间(UT)。 GMT是标准的“民用”名称; UT是同一标准的“科学”名称。 UTC和UT之间的区别是UTC是基于原子钟,UT是基于天文观测,对于所有的实际目的来说,这是一个看不见的细毛。 因为地球的旋转不均匀(减速并以复杂的方式加速),UT并不总是均匀地流动。 根据需要,将时差引入到UTC中,以使UT在UT1的0.9秒内保持UTC,这是UT的版本,并应用了某些修正。 还有其他的时间和日期系统; 例如,基于卫星的全球定位系统(GPS)使用的时间尺度与UTC同步,但不对闰秒进行调整。

    进一步信息的一个有趣的来源是美国海军天文台,特别是时间局在:http://tycho.usno.navy.mil

    及其“时间系统”的定义如下:
    http://tycho.usno.navy.mil/systime.html

    在类的所有方法Date接受或返回年,月,日,小时,分钟和秒值,以下表述中使用:

    • y年代表整数y - 1900
    • 一个月由0到11的整数表示; 0是1月,1是2月,等等; 11月12日。
    • 日期(月的一天)以通常的方式从1到31的整数表示。
    • 一小时由0到23之间的整数表示。因此,从午夜到凌晨1点的时间是小时0,从中午到下午1点的小时是12小时。
    • 一般以0〜59的整数表示。
    • 第二个由0到61的整数表示; 值60和61仅发生在闰秒上,甚至仅在实际上正确跟踪闰秒的Java实现中发生。 由于目前引入闰秒的方式,在同一分钟内不会发生两个闰秒,但是本规范遵循ISO C的日期和时间约定。

    在所有情况下,为这些目的而提供的方法的论证不必在指定范围内; 例如,可以将日期指定为1月32日,并将其解释为2月1日。

package com.day13.demo;

import java.util.Date;

public class DateDemo1 {
	public static void main(String[] args) {
		Date date = new Date();
        //Tue Aug 17 17:01:50 CST 2021
		System.out.println(date);
	}
}

在Date类中最需要关心的一个核心问题:long可以描述日期,看了一通过Date类中提供的方法来进行观察。

方法名称类型描述
public Date(long date)普通将long类型变为Date类型数据
public long getTime()普通将Date类型变为long类型数据

观察转化

package com.day13.demo;

import java.util.Date;

public class DateDemo1 {
	public static void main(String[] args) {
		long num = System.currentTimeMillis();
		System.out.println(new Date(num));
		System.out.println(new Date(num).getTime());
	}
}

这中简单的转换在以后的程序开发经常会使用。

日期格式化—SimpleDateFormat类(核心)

虽然Date可以取得当前的日期时间,但是取出的结构不是我们所喜欢的格式,这时候就需要我们进行格式的转化,使用的是java.text包

image-20210817171959845

但是日期格式里面需要设置一些日期标记:年(YYYY)、月(MM)、日(dd)、时(HH)、分(mm)、秒(ss)、毫秒(SS);

实现日期格式化处理(日期格式化之后是字符串)

package com.day13.demo;

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateDemo1 {
	public static void main(String[] args) {
		Date date = new Date();
		String str = "YYYY-MM-dd HH:mm:ss";
		SimpleDateFormat sdf = new SimpleDateFormat(str);
		String dateFromat = sdf.format(date);
		System.out.println(dateFromat);
	}
}

将字符串变为Date类型

package com.day13.demo;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateDemo2 {
	public static void main(String[] args) throws ParseException{
		Date date = new Date();
		System.out.println(date);
		String str = "yyyy-MM-dd HH:mm:ss";
		SimpleDateFormat sdf = new SimpleDateFormat(str);
		//将Date类型转化为字符串类型
		String newdateStirng = sdf.format(date);
		System.out.println(newdateStirng);
		//将字符串转化为Date类型
		Date newdate = sdf.parse(newdateStirng);
		System.out.println(newdate);
	}
}

数字操作类—Math类

在Java.lang.Math类之中定义了所有的于数学有关的基本公式,在这个类之中所有的方法都是static型的方法,强调一个方法:round(),public static long round(double a),表示四舍五入。

package com.day13.demo;

public class MathDemo {
	public static void main(String[] args) {
		System.out.println(Math.round(13.51));
		System.out.println(Math.round(13.5));
		//如果负数小数,没大于0.5都不进位
		System.out.println(Math.round(-13.51));
		System.out.println(Math.round(-13.5));//-13
	}	
}

希望可以准确的保存小数位进行处理。

需要保留几位小数

package com.day13.demo;
class MyMath{
	public static double round(double num, int scale){
		return Math.round(num * Math.pow(10, scale)) / Math.pow(10, scale);
	}
}
public class MathDemo {
	public static void main(String[] args) {
        //1234.457
		System.out.println(MyMath.round(1234.4567, 3));
	}	
}

随机数—Random()

Java .util.Random的主要主要作用就是产生随机数,下面通过一个代码来观察就行。 Random (Java Platform SE 8 )

public class Random extends Object implements Serializable

Random (Java Platform SE 8 )

  • 该类的实例用于生成伪随机数的流。 该类使用48位种子,其使用线性同余公式进行修改。 (见Donald Knuth, “计算机编程艺术”,第2卷 ,第3.2.1节)

    如果使用相同的种子创建两个Random Random ,并且对每个实例进行相同的方法调用序列,则它们将生成并返回相同的数字序列。 为了保证此属性,为Random类Random 。 为了Java代码的绝对可移植性,Java实现必须使用这里所示的所有算法为Random类。 然而,Random类的子类Random使用其他算法,只要它们遵守所有方法的一般合同。

    Random类实现的Random使用protected实用程序方法,每次调用可以提供多达32个伪随机生成位。

    许多应用程序会发现方法Math.random()使用起来更简单。

    java.util.Random的java.util.Random是线程安全的。 但是,跨线程的同时使用java.util.Random实例可能会遇到争用,从而导致性能下降。 在多线程设计中考虑使用ThreadLocalRandom

    java.util.Random的java.util.Random不是加密安全的。 考虑使用SecureRandom获取一个加密安全的伪随机数生成器,供安全敏感应用程序使用。

网站开发的随机验证码

package com.day13.demo;

import java.util.Random;

public class RandomDemo {
	public static void main(String[] args) {
		char data [] = new char[]{'a','b','c','d','e'};
		for (int i = 0; i < 4; i++) {
			System.out.print(data[new Random().nextInt(data.length)]);
		}
	}
}

大数字操作类

如果说现在有两个非常大的数字要进行数学操作,你们认为要怎么做?这个时候数字已经超过了double的范围,那么只能利用字符串来表示,取出每一个字符串变为数字后进行数学计算,这种方式的难度较高,为了解决这种问题,在Java之中提供了两个大数字操作类:java.math包中BigInteger,BigDecimal,而这两个类是属于Number的子类。

1.大整数操作类:BigIntegr

之前已经强调过了,如果数字较大,肯定按照String来处理,所以这一点可以通过Biginteger的构造方法来观察:

​ 构造:public BigInteger(String val);

而且在BigInteger类之中定义了一些基本的数学计算:

​ 加法:public BigInteger add(BigInteger val);

​ 减法:public BigInteger subtract(BigInteger val);

​ 乘法:public BigInteger multiply(BigInteger val);

​ 除法(不保存余数):public BigInteger divide(BigInteger val);

​ 除法(保存余数):public BigInteger divideAndRemainder(BigInteger val)

大数的四则运算

package com.day13.demo;

import java.math.BigInteger;

public class BigAddDemo {
	public static void main(String[] args) {
		BigInteger bigA = new BigInteger("123712487812974891274891274128947891");
		BigInteger bigB = new BigInteger("43895748395789347589347589398");
		System.out.println("加法计算:" + bigA.add(bigB));
		System.out.println("减法计算:" + bigA.subtract(bigB));
		System.out.println("乘法计算:" + bigA.multiply(bigB));
		System.out.println("除法计算:" + bigA.divide(bigB));
		BigInteger result[] = bigA.divideAndRemainder(bigB);
		System.out.println("除法计算:" + result[0] + "." + result[1]);
	}
}

2.大小数操作类:BigDcimal

BigDecimal类表示的是大小数操作类,但是这个类也具备了于之前同样的基本计算方式,而在实际的工作之中,是用这个类最多的情况是进行准确位数的四舍五入操作,如果要完成这一操作需要关心BigDecimal类中的以下定义:

构造:public BigDecimal(double val);

除法:public BigDecimal divide(BigDecimal divisor ,int scale ,int roundingMode);

进位模式:public static final int ROUND_HALF_UP。

四舍五入进位操作

package com.day13.demo;

import java.math.BigDecimal;
//大数进位方法
class MyMath1{
	public static double round(double num, int scale){
		return new BigDecimal(num).divide(new BigDecimal(1), scale, BigDecimal.ROUND_HALF_DOWN).doubleValue();
	}
}
public class BigDecimalDemo {
	public static void main(String[] args) {
		System.out.println(MyMath1.round(2138845.4567, 3));
	}
}

Arrays类

排序操作:java.util.Arrays.sort(数组名称),对于Arrays类一直是进行数组排序的操作,类一直进行数组排序的操作,而Arrays类是定义在java.util包下的一个操作类,在这个类之中定义了所有的与数组有关的基本操作:二分查找,拷贝操作,相等判断,填充,变为字符串输出等。

package com.day13.demo;

import java.util.Arrays;

public class ArraysDemo {
	public static void main(String[] args) {
		int dataA[] = new int []{1,2,3,4,5,6};
		int dataB[] = new int []{1,2,3,4,5,6};
		//数组输出
		System.out.println(Arrays.toString(dataA));
		//两个数组进行比较
		System.out.println(Arrays.equals(dataA,dataB));
		//数组二分法查找
		System.out.println(Arrays.binarySearch(dataA, 4)+1);
	}
}

比较器—Comparable

Comparable

对象数组排序:public static void sort(Object[] a)

package com.day13.demo;

import java.util.Arrays;

class Pers{
	private String name;
	private int age;
	public Pers(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Pers [name=" + name + ", age=" + age + "]";
	}
}
public class ComparableDemo {
	public static void main(String[] args) {
		Pers pers[] = new Pers[]{
			new Pers("张三",12),
			new Pers("李四",23),
			new Pers("刘武",54)//对象数组
		};
		Arrays.sort(pers);//要进行对象数组的排序处理
		System.out.println(Arrays.toString(pers));
	}
}

这个时候没有任何的语法错误,即:程序的代码是正确的,但是在程序执行的时候出现了以下的问题:

Exception in thread "main" java.lang.ClassCastException: com.day13.demo.Pers cannot be cast to java.lang.Comparable
	at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
	at java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
	at java.util.Arrays.sort(Arrays.java:1246)
	at com.day13.demo.ComparableDemo.main(ComparableDemo.java:36)

明确的告诉用户现在发生了“ClassCaseException”,类转换异常,Person类不能变为Comparables实例。

如果要为对象指定比较规则,那么对象所在的类必须实现Comparable接口,下面首先来看一下这个接口的定义:

public interface Comaparable<T>{
	public int compareTo(T o)
}

Stirng类中的compareTo()就属于覆写Comaparable接口所的来的方法。

image-20210817191154586

实现对象数组的排序

package com.day13.demo;

import java.util.Arrays;

class Pers implements Comparable<Pers>{
	private String name;
	private int age;
	public Pers(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Pers [name=" + name + ", age=" + age + "]\n";
	}
	@Override
	public int compareTo(Pers o) {
		// TODO Auto-generated method stub
		//升序排序 如果降序排序将1 和 -1 进行位置调换
		if(this.age > o.age){
			return -1;
		}else if(this.age < o.age){
			return 1;
		}else{
			return 0;
		}
	}
}
public class ComparableDemo {
	public static void main(String[] args) {
		Pers pers[] = new Pers[]{
			new Pers("张三",12),
			new Pers("李四",23),
			new Pers("刘武",54)//对象数组
		};
		Arrays.sort(pers);//要进行对象数组的排序处理
		System.out.println(Arrays.toString(pers));
	}
}

只要是对象数组排序,就必须有Comparable接口。

二叉树( Binary Tree )

二叉树是一种排序的基本的数据结构,而如果要想为多个对象进行排序,那么就必须可以区分出对象的大小,那么就必须依靠Comparable接口完成。

二叉树的基本原理:取第一个元素作为根节点,之后每一个元素的排列要求:如果比根节点晓得数据放在左子树,如果比根节点大的数据放在右子树,在输出的时候采用中序(左-根-右)遍历的方式完成。

但是不管是何种方式操作,一定要记住,这种数据结构的实现永远都需要依靠节点类,而这个时候的节点类要保存两个节点:左,右。

国际化

在java.util.Locale可以找java提供国际化的相关信息

Locale构造:public Locale(String language, String country)

观察区域和语言代码

package com.day13.demo;

import java.util.Locale;

public class LocalDemo {
	public static void main(String[] args) {
		System.out.println(Locale.CHINA);//zh_CN
		System.out.println(Locale.CHINESE);//zh
	}
}
  • 中国Locale:public static final Locale CHINESE
  • 美国Locale:public static final Locale US
  • 取得当前的Locale对象:public static Locale getDefault()

当我们用eclipse打开Message.properties进行编写后不要慌,我们还有一个非常强大的工具在JDK中,CLASSPATH:C:\Program Files\Java\jdk1.8.0_241\bin 自己安装JDK的环境目录下有一个叫native2ascii.exe可以帮助我们进行转码。这种做法非常麻烦,如果要开发国际版本的软件还是自己安装一个编辑软件比较好。

image-20210817212132969

语言配置文件Message.properties

welcome.info = \u5317\u4EAC\u6B22\u8FCE\u4F60\uFF01

测试文件LocaleDemo.java

package com.day13.demo;

import java.util.ResourceBundle;

public class LocaleDemo {
	public static void main(String[] args) {
		//这个时候设置的baseName没有后缀,而且一定要在CLASSPATH之中
		ResourceBundle res = ResourceBundle.getBundle("com.day13.msg.Message");
        //北京欢迎你!
		System.out.println(res.getString("welcome.info"));
	}
}

资源文件的名称就只是 包.名称前缀