锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

「JavaSE」- 常用类

时间:2022-08-24 07:30:01 lance连接器19sb1j电连接器

常用类

Object类

Object所有类别的父亲都是默认继承的Object。理论上Object所有类别的父直接或间接继承java.lang.Object类。因为所有的类都是继承的Object类,因此省略了extends Object关键字。

主要有以下方法:

  • toString()
  • getClass()
  • equals()
  • clone()
  • finalize()

其中 toString(),getClass(),equals()最重要的方法之一。

【演示:查看Object类源码】

注意: Object类中的getClass(),notify(),notifyAll(),wait()方法定义为final类型,所以不能重写。

1、clone()方法

详解文章:

详解Java中的clone方法 -- 原型模式

protected native Object clone() throws CloneNotSupportedException;

clone顾名思义,就是复制, 在Java语言中, clone该方法被对象调用,因此将复制对象。所谓复制对象,首先要分配与源对象大小相同的空间,在这个空间中创建新的对象。

创建对象的方式:

  • 使用new创建对象的操作符
  • 使用clone复制一个对象的方法

相同点和差异:

  • new操作符的初衷是分配内存。
    • 程序执行到new操作符时, 首先去看new操作符后面的类型只有知道类型才能知道内存空间要分配多少。
    • 内存分配后,调用结构函数填充对象的每个域。这一步称为对象的初始化。结构方法返回后,一个对象创建后,可以将其引用(地址)发布到外部,并可以使用该引用来操纵外部对象。
  • 而clone第一步是和new相似的, 内存分配,调用clone分配的内存和源对象(即调用)clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成后,clone方法返回,创建新的相同对象,也可以将新对象的引用发布到外部。

clone与copy的区别

假设现在有一个Employee对象,Employee tobby =new Employee(“CMTobby”,5000)

通常我们会有这样的赋值Employee cindyelf=tobby,这个时候只是简单copy了一下reference,cindyelf和tobby都指向同一个内存object,这样cindyelf或者tobby一个操作可能会相互影响。例如,如果我们通过它cindyelf.raiseSalary()方法改变了salary域的值,所以tobby通过getSalary()修改后得到方法salary显然,这不是我们想看到的。我们想要的tobby同时两者之间没有相互影响的精确拷贝,此时, 我们可以使用它Clone满足我们的需求。Employee cindy=tobby.clone(),这个时候会产生新的Employee对象,和tobby具有相同的属性值和方法。

Shallow Clone与Deep Clone

主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用,我们有时候不希望在方法里将参数改变,这是就需要在类中复写clone方法(实现深复制)。

Clone它是如何完成的?

Object对某对象Clone对此一无所知,它只是简单地执行域对域copy,这就是Shallow Clone。

以Employee例如,它有一个域hireDay它不是基本数据类型的变量,而是一个reference变量,经过Clone之后会有新的产生Date型的reference,它与原始对象中相应的域指向相同Date对象,这样克隆类就原始类分享部分信息,这显然是不利的,如下图所示:

在这个时候,我们需要这样做deep Clone对非基本类型的域进行特殊处理,如本例hireDay。我们可以重新定义它Clone方法,对hireDay特殊处理如下代码所示:

class Employee implements Cloneable {   public Object clone() throws CloneNotSupportedException {     Employee cloned = (Employee) super.clone();     cloned.hireDay = (Date) hireDay.clone()       return cloned;   } }

clone方法的保护机制

在Object中Clone()被声明为protected是的,这样做有一定的道理Employee以类为例,通过声明为例protected,只能保证Employee克隆只能在类中克隆Employee对象.

clone方法的使用

何时使用shallow Clone,何时使用deep Clone,这主要取决于具体对象的域的性质、基本类型或reference variable

调用Clone()方法的对象所属的类(Class)必须implements Clonable接口,否则在调用Clone当方法被抛出时CloneNotSupportedException

2、toString()方法

public String toString() {   return getClass().getName()   "@"   Integer.toHexString(hashCode()); }

Object 类的 toString 方法返回字符串,字符串由类名(对象为此类实例),at 标记符“@与此对象哈希码的无符号十六进制表示组成。

该方法应用较多,一般子类都有覆盖

我们建议在学习阶段加上所有属性toString() 方法!

public static void main(String[] args){   Object o1 = new Object();   System.out.println(o1.toString()); }

3、getClass()方法

public final native Class getClass();

返回此Object的运行时类类型。

不可重写,要调用的话,一般和getName()联合使用,如getClass().getName();

public static void main(String[] args) {
  Object o = new Object();
  System.out.println(o.getClass());
  //class java.lang.Object
}

4、finalize()方法

protected void finalize() throws Throwable {}

该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。

Java允许在类中定义一个名为finalize()的方法。它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

关于垃圾回收,有三点需要记住:

  • 对象可能不被垃圾回收。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。
  • 垃圾回收并不等于“析构”。

科普:

析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。

  • 垃圾回收只与内存有关。使用垃圾回收的唯一原因是为了回收程序不再使用的内存。

finalize()的用途:

无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。

这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。

5、equals()方法

public boolean equals(Object obj) {
  return (this == obj);
}

Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参obj所引用的对象是否是同一对象,所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的hi同一块内存对象,则返回true,如果this和obj指向的不是同一块内存,则返回false。

注意:即便是内容完全相等的两块不同的内存对象,也返回false。

如果是同一块内存,则object中的equals方法返回true,如果是不同的内存,则返回false

如果希望不同内存但相同内容的两个对象equals时返回true,则我们需要重写父类的equal方法

String类已经重写了object中的equals方法(这样就是比较内容是否相等了)

【演示:查看String类源码equals方法】

public boolean equals(Object anObject) {
  if (this == anObject) {
    return true;
  }
  if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = value.length;
    if (n == anotherString.value.length) {
      char v1[] = value;
      char v2[] = anotherString.value;
      int i = 0;
      while (n-- != 0) {
        if (v1[i] != v2[i])
          return false;
        i++;
      }
      return true;
    }
  }
  return false;
}

6、hashCode()方法

public native int hashCode();

返回该对象的哈希码值。

该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

一般必须满足。可以推出obj1.hash Code() == obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。

7、wait()方法

public final void wait() throws InterruptedException {
  wait(0);
}
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
{
  if (timeout < 0) {
    throw new IllegalArgumentException("timeout value is negative");
  }
  if (nanos < 0 || nanos > 999999) {
    throw new IllegalArgumentException(
      "nanosecond timeout value out of range");
  }
  if (nanos > 0) {
    timeout++;
  }
  wait(timeout);
}

可以看到有三种重载,wait什么意思呢?

方法中的异常:

wait方法就是使当前线程等待该对象的,当前线程必须是该对象的拥有者,也就是具有该对象的锁。

wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

调用该方法后当前线程进入睡眠状态,直到以下事件发生:

(1)其他线程调用了该对象的notify方法。

(2)其他线程调用了该对象的notifyAll方法。

(3)其他线程调用了interrupt中断该线程。

(4)时间间隔到了。

此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。

8、notify()方法

public final native void notify();

该方法唤醒在该对象上等待的某个线程。

public final native void notifyAll();

该方法唤醒在该对象上等待的所有线程。

包装类

1、包装类介绍

虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性、没有方法可调用。

这种借助于非面向对象技术的做法有时也会带来不便,比如引用类型数据均继承了 Object 类的特性,要转换为 String 类型(经常有这种需要)时只要简单调用 Object 类中定义的toString()即可,而基本数据类型转换为 String 类型则要麻烦得多。

为解决此类问题 ,Java为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有教材称为外覆类或数据类型类。

基本数据类型

对应的包装类

byte

Byte

short

Short

int

Integer

long

Long

char

Character

float

Float

double

Double

boolean

Boolean

每个包装类的对象可以封装一个相应的基本类型的数据,并提供了其它一些有用的方法。包装类对象一经创建,其内容(所封装的基本类型数据值)不可改变。

基本类型和对应的包装类可以相互装换:

  • 由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象;
  • 包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。

2、包装类的应用

1)实现 int 和 Integer 的相互转换

可以通过 Integer 类的构造方法将 int 装箱,通过 Integer 类的 intValue 方法将 Integer 拆箱。

public static void main(String[] args) {
  int m = 500;
  Integer obj = new Integer(m); // 手动装箱
  int n = obj.intValue(); // 手动拆箱
  System.out.println("n = " + n);
  Integer obj1 = new Integer(500);
  System.out.println("obj 等价于 obj1?" + obj.equals(obj1));
}

2)将字符串转换为整数

Integer 类有一个静态的 paseInt() 方法,可以将字符串转换为整数,语法为:

parseInt(String s, int radix);

s 为要转换的字符串,radix 为进制,可选,默认为十进制。

下面的代码将会告诉你什么样的字符串可以转换为整数:

public static void main(String[] args) {
  String[] str = {"123", "123abc", "abc123", "abcxyz"};
  for(String str1 : str){
    try{
      int m = Integer.parseInt(str1, 10);
      System.out.println(str1 + " 可以转换为整数 " + m);
    }catch(Exception e){
      System.out.println(str1 + " 无法转换为整数");
    }
  }
}
//结果
123 可以转换为整数 123
123abc 无法转换为整数
abc123 无法转换为整数
abcxyz 无法转换为整数

3)将整数转换为字符串

Integer 类有一个静态的 toString() 方法,可以将整数转换为字符串,或者直接在整数后面加空字符串即可!

public static void main(String[] args) {
  int m = 500;
  String s = Integer.toString(m);
  String s2 = m+"";
  System.out.println("s = " + s);
}

3、自动拆箱和装箱

上面的例子都需要手动实例化一个包装类,称为手动拆箱装箱。Java 1.5(5.0) 之前必须手动拆箱装箱。

Java 1.5 之后可以自动拆箱装箱,即在进行基本数据类型和对应的包装类转换时,系统将自动进行,这将大大方便程序员的代码书写。

public static void main(String[] args) {
  int m = 500;
  Integer obj = m; // 自动装箱
  int n = obj; // 自动拆箱
  System.out.println("n = " + n);
  Integer obj1 = 500;
  System.out.println("obj 等价于 obj1?" + obj.equals(obj1));
}
//结果:
// n = 500
// obj 等价于 obj1?true

自动装箱与拆箱的功能事实上是编译器来帮您的忙,编译器在编译时期依您所编写的语法,决定是否进行装箱或拆箱动作。例如:

Integer i = 100;
相当于编译器自动为您作以下的语法编译:
Integer i = new Integer(100);

所以自动装箱与拆箱的功能是所谓的“编译器蜜糖”(Compiler Sugar),虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。例如下面的程序是可以通过编译的:

Integer i = null;
int j = i;

这样的语法在编译时期是合法的,但是在运行时期会有错误,因为这种写法相当于:

Integer i = null;
int j = i.intValue();

null表示i 没有参考至任何的对象实体,它可以合法地指定给对象参考名称。由于实际上i并没有参考至任何的对象,所以也就不可能操作intValue()方法,这样上面的写法在运行时会出现NullPointerException错误。

自动拆箱装箱是常用的一个功能,需要重点掌握。

一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte、int、long、double 等。

然而,在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。

为了解决这个问题,Java 语言为每一个内置数据类型提供了对应的包装类。

所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。

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的属性对应的值。系统中常见的属性名以及属性的作用如下:​​​​​​​
        • java.version     java运行时的环境版本​​​​​​​
        • java.home    java安装目录​​​​​​​
        • os.name    操作系统的名称​​​​​​​
        • os.version    操作系统的版本​​​​​​​
        • user.name   用户的账户名称​​​​​​​
        • user.home    用户的主目录​​​​​​​
        • user.dir    用户的当前工作目录

Math类

Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。

Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。

【演示:查看Math类的源码】

public final class Math{
//数学方法
}

【常用值与函数】

  • Math.PI 记录的圆周率
  • Math.E 记录e的常量
  • Math中还有一些类似的常量,都是一些工程数学常用量。
  • Math.abs 求绝对值
  • Math.sin 正弦函数 Math.asin 反正弦函数
  • Math.cos 余弦函数 Math.acos 反余弦函数
  • Math.tan 正切函数 Math.atan 反正切函数 Math.atan2 商的反正切函数
  • Math.toDegrees 弧度转化为角度 Math.toRadians 角度转化为弧度
  • Math.ceil 得到不小于某数的最大整数
  • Math.floor 得到不大于某数的最大整数
  • Math.IEEEremainder 求余
  • Math.max 求两数中最大
  • Math.min 求两数中最小
  • Math.sqrt 求开方
  • Math.pow 求某数的任意次方, 抛出ArithmeticException处理溢出异常
  • Math.exp 求e的任意次方
  • Math.log10 以10为底的对数
  • Math.log 自然对数
  • Math.rint 求距离某数最近的整数(可能比某数大,也可能比它小)
  • Math.round 同上,返回int型或者long型(上一个函数返回double型)
  • Math.random 返回0,1之间的一个随机数
public static void main(String[] args) {
  /**
*Math.sqrt()//计算平方根
*Math.cbrt()//计算立方根
*Math.pow(a, b)//计算a的b次方
*Math.max( , );//计算最大值
*Math.min( , );//计算最小值
*/
  System.out.println(Math.sqrt(16)); //4.0
  System.out.println(Math.cbrt(8)); //2.0
  System.out.println(Math.pow(3,2)); //9.0
  System.out.println(Math.max(2.3,4.5));//4.5
  System.out.println(Math.min(2.3,4.5));//2.3
  /**
* abs求绝对值
*/
  System.out.println(Math.abs(-10.4)); //10.4
  System.out.println(Math.abs(10.1)); //10.1
  /**
* ceil天花板的意思,就是返回大的值
*/
  System.out.println(Math.ceil(-10.1)); //-10.0
  System.out.println(Math.ceil(10.7)); //11.0
  System.out.println(Math.ceil(-0.7)); //-0.0
  System.out.println(Math.ceil(0.0)); //0.0
  System.out.println(Math.ceil(-0.0)); //-0.0
  System.out.println(Math.ceil(-1.7)); //-1.0
  /**
* floor地板的意思,就是返回小的值
*/
  System.out.println(Math.floor(-10.1)); //-11.0
  System.out.println(Math.floor(10.7)); //10.0
  System.out.println(Math.floor(-0.7)); //-1.0
  System.out.println(Math.floor(0.0)); //0.0
  System.out.println(Math.floor(-0.0)); //-0.0
  /**
* random 取得一个大于或者等于0.0小于不等于1.0的随机数 [0,1)
*/
  System.out.println(Math.random()); //小于1大于0的double类型的数
  System.out.println(Math.random()+1);//大于1小于2的double类型的数
  /**
* rint 四舍五入,返回double值
* 注意.5的时候会取偶数 异常的尴尬=。=
*/
  System.out.println(Math.rint(10.1)); //10.0
  System.out.println(Math.rint(10.7)); //11.0
  System.out.println(Math.rint(11.5)); //12.0
  System.out.println(Math.rint(10.5)); //10.0
  System.out.println(Math.rint(10.51)); //11.0
  System.out.println(Math.rint(-10.5)); //-10.0
  System.out.println(Math.rint(-11.5)); //-12.0
  System.out.println(Math.rint(-10.51)); //-11.0
  System.out.println(Math.rint(-10.6)); //-11.0
  System.out.println(Math.rint(-10.2)); //-10.0
  /**
* round 四舍五入,float时返回int值,double时返回long值
*/
  System.out.println(Math.round(10.1)); //10
  System.out.println(Math.round(10.7)); //11
  System.out.println(Math.round(10.5)); //11
  System.out.println(Math.round(10.51)); //11
  System.out.println(Math.round(-10.5)); //-10
  System.out.println(Math.round(-10.51)); //-11
  System.out.println(Math.round(-10.6)); //-11
  System.out.println(Math.round(-10.2)); //-10
}

Random类

Java中存在着两种Random函数:

1)java.lang.Math.Random;

调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。例子如下:

public static void main(String[] args) {
  // 结果是个double类型的值,区间为[0.0,1.0)
  System.out.println("Math.random()=" + Math.random());
  int num = (int) (Math.random() * 3);
  // 注意不要写成(int)Math.random()*3,这个结果为0或1,因为先执行了强制转换
  System.out.println("num=" + num);
}
//结果
//Math.random()=0.44938147153848396
//num=1

2)java.util.Random

下面是Random()的两种构造方法:

  • Random():创建一个新的随机数生成器。
  • Random(long seed):使用单个 long 种子创建一个新的随机数生成器。

你在创建一个Random对象的时候可以给定任意一个合法的种子数,种子数只是随机算法的起源数字,和生成的随机数的区间没有任何关系。

如下面的Java代码:

【演示一】

在没带参数构造函数生成的Random对象的种子缺省是当前系统时间的毫秒数。

rand.nextInt(100)中的100是随机数的上限,产生的随机数为0-100的整数,不包括100。

public static void main(String[] args) {
  Random rand =new Random();
  int i=rand.nextInt(100);
  System.out.println(i);
}

【演示二】

对于种子相同的Random对象,生成的随机数序列是一样的。

public static void main(String[] args) {
  Random ran1 = new Random(25);
  System.out.println("使用种子为25的Random对象生成[0,100)内随机整数序列: ");
  for (int i = 0; i < 10; i++) {
    System.out.print(ran1.nextInt(100) + " ");
  }
  System.out.println();
}

【方法摘要】

  • protected int next(int bits):生成下一个伪随机数。
  • 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):返回一个伪随机数,它是取自此随机数生成器序列的、在(包括和指定值(不包括)之间均匀分布的int值。
  • long nextLong():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。
  • void setSeed(long seed):使用单个 long 种子设置此随机数生成器的种子。

【例子】

  1. 生成[0,1.0)区间的小数:double d1 = r.nextDouble();
  2. 生成[0,5.0)区间的小数:double d2 = r.nextDouble() * 5;
  3. 生成[1,2.5)区间的小数:double d3 = r.nextDouble() * 1.5 + 1;
  4. 生成[0,10)区间的整数:int n2 = r.nextInt(10);

BigInteger类与BigDecimal类

1、BigInteger类

  • Integer类作为int的包装类,能存储的最大整型值为231-1,Long类也是有限的,最大为263-1。如果要表示再大的整数,不管是基本数据类型还是它们的包装类都无能为力了,更别说作运算了。
  • java.math包的BigInteger可以表示不可变的任何精度的整数。BigInteger提供所以Java的基本整数操作符的对应物,并提供java.lang.Math的所有相关方法。另外,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);
      • 返回其值为(thisexponent)的BigInteger。

2、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 devide(BigDecimal divisor,int scale,int roundingMode)     除

日期时间类

JDK8之前的日期时间

  • java.lang.System
    • System类提供的 public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差,称为时间戳
    • 此方法适用于计算时间差
  • java.util.Date
    • 表示特定的瞬间,精确到毫秒
    • 构造器:
      • Date():使用无参构造器创建当前时间的Date对象
      • Date(long date):创建指定毫秒数的Date对象
    • 常用方法
      • getTime():返回自1970年1月1日00:00:00GMT之间的时间差(时间戳)
      • toString():显示当前的年、月、日、时、分、秒
  • java.sql.Date
    • 对应数据可中的日期类型的变量
    • 实例化 new java.sql.Date(long date);
    • 将java.util.Date对象转换成java.sql.Date对象
    • 情况一:Date date4 = new java.sql.Date(12345678L);
      • java.sql.Date date5 = (java.sql.Date) date4;
    • 情况二:Date date6 = new Date();
      • java.sql.Date date7 = new java.sql.Date(date6.getTime());
  • java.text.SimpleDateFormat
    • 是一个不与语言环境有关的方式来格式化和解析日期的具体类​​​​​​​
    • 格式化:日期 -->字符串   解析:字符串 --> 日期
    • 格式化
      • SimpleDateFormat() :默认的模式和语言环境创建对象​​​​​​​
      • public SimpleDateFormat(String pattern) :该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用:​​​​​​​
      • public String format(Date date) 方法格式化时间对象date​​​​​​​
    • 解析
      • public Date parse(String source) :从给定字符串的开始解析文本,以生成一个日期​​​​​​​
  • java.util.Calendar()
    • Calendar是一个抽象基类,主要用于完成日期字段之间相互操作的功能。
    • 获取Calendar实例的方法
      • 使用Calendar.getInstance()静态方法
      • 调用它的子类GregorianCalendar的构造器
    • 一个Calendar的实例是系统时间的抽象表示,通过:(常用方法)​​​​​​​
      • get(int field)  :获取想要的时间信息。​​​​​​​
      • set(int field,int value)
      • add(int field,int amount)
      • getTime() :日历类 --> Date​​​​​​​
      • setTime(Date date)  :Date --> 日历类
    • 注意:
    • 获取月份时:一月是0,二月是1,以此类推,12月是11
    • 获取星期时:周日是1,周二是2,...,周六是7

1、Date类

java.util 包提供了 Date 类来封装当前的日期和时间。

Date 类提供两个构造函数来实例化 Date 对象。

第一个构造函数使用当前日期和时间来初始化对象。

Date()

第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。

Date(long millisec)

Date对象创建以后,可以调用下面的方法。

序号

方法和描述

1

boolean after(Date date) 若当调用此方法的Date对象在指定日期之后返回true,否则返回false。

2

boolean before(Date date) 若当调用此方法的Date对象在指定日期之前返回true,否则返回false。

3

Object clone( ) 返回此对象的副本。

4

int compareTo(Date date) 比较当调用此方法的Date对象和指定日期。两者相等时候返回0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数。

5

int compareTo(Object obj) 若obj是Date类型则操作等同于compareTo(Date) 。否则它抛出ClassCastException。

6

boolean equals(Object date) 当调用此方法的Date对象和指定日期相等时候返回true,否则返回false。

7

long getTime( ) 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

8

int hashCode( ) 返回此对象的哈希码值。

9

void setTime(long time) 用自1970年1月1日00:00:00 GMT以后time毫秒数设置时间和日期。

10

String toString( ) 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。

【演示:获取当前日期时间】

Java中获取当前日期和时间很简单,使用 Date 对象的 toString() 方法来打印当前日期和时间

如下所示:

public static void main(String args[]) {
  // 初始化 Date 对象
  Date date = new Date();
  // 使用 toString() 函数显示日期时间
  System.out.println(date.toString());
  //Sat Apr 27 15:09:43 CST 2019
}

【演示:日期比较】

  • 使用 getTime() 方法获取两个日期(自1970年1月1日经历的毫秒数值),然后比较这两个值。
public static void main(String[] args) {
  // 初始化 Date 对象
  Date date = new Date();
  long time = date.getTime();
  long time2 = date.getTime();
  System.out.println(time==time2);
}

  • 使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2,12).before(new Date (99, 2, 18)) 返回true。
public static void main(String[] args) {
  boolean before = new Date(97, 01, 05).before(new Date(99, 11, 16));
  System.out.println(before);
}

2、SimpleDateFormat

【演示:使用 SimpleDateFormat 格式化日期】

SimpleDateFormat 是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat 允许你选择任何用户自定义日期时间格式来运行。例如:

public static void main(String args[]) {
  Date dNow = new Date( );
  SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
  System.out.println("当前时间为: " + ft.format(dNow));
}

其中 yyyy 是完整的公元年,MM 是月份,dd 是日期,HH:mm:ss 是时、分、秒。

注意:有的格式大写,有的格式小写,例如 MM 是月份,mm 是分;HH 是 24 小时制,而 hh 是 12 小时制。时间模式字符串用来指定时间格式。在此模式中,所有的 ASCII 字母被保留为模式字母,定义如下:

字母

描述

示例

G

纪元标记

AD

y

四位年份

2001

M

月份

July or 07

d

一个月的日期

10

h

A.M./P.M. (1~12)格式小时

12

H

一天中的小时 (0~23)

22

m

分钟数

30

s

秒数

55

S

毫秒数

234

E

星期几

Tuesday

D

一年中的日子

360

F

一个月中第几周的周几

2 (second Wed. in July)

w

一年中第几周

40

W

一个月中第几周

1

a

A.M./P.M. 标记

PM

k

一天中的小时(1~24)

24

K

A.M./P.M. (0~11)格式小时

10

z

时区

Eastern Standard Time

'

文字定界符

Delimiter

"

单引号

`

【演示:使用printf格式化日期】

Java 格式化输出 printf 例子

printf 方法可以很轻松地格式化时间和日期。使用两个字母格式,它以 %t 开头并且以下面表格中的一个字母结尾。

public static void main(String args[]) {
  // 初始化 Date 对象
  Date date = new Date();
  //c的使用
  System.out.printf("全部日期和时间信息:%tc%n",date);
  //f的使用
  System.out.printf("年-月-日格式:%tF%n",date);
  //d的使用
  System.out.printf("月/日/年格式:%tD%n",date);
  //r的使用
  System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date);
  //t的使用
  System.out.printf("HH:MM:SS格式(24时制):%tT%n",date);
  //R的使用
  System.out.printf("HH:MM格式(24时制):%tR",date);
}
//结果:
全部日期和时间信息:星期六 四月 27 15:23:45 CST 2019
年-月-日格式:2019-04-27
月/日/年格式:04/27/19
HH:MM:SS PM格式(12时制):03:23:45 下午
HH:MM:SS格式(24时制):15:23:45
HH:MM格式(24时制):15:23

【时间休眠:休眠(sleep)】

sleep()使当前线程进入停滞状态(阻塞当前线程),让出CPU的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会。

你可以让程序休眠一毫秒的时间或者到您的计算机的寿命长的任意段时间。例如,下面的程序会休眠3秒:

public static void main(String args[]) {
  try {
    System.out.println(new Date( ) + "\n");
    Thread.sleep(1000*3); // 休眠3秒
    System.out.println(new Date( ) + "\n");
  } catch (Exception e) {
    System.out.println("Got an exception!");
  }
}

3、Calendar类

Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要复杂一些。

Calendar类是一个抽象类,在实际使用时实现特定 的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用getInstance方法创建即可。

创建一个代表系统当前日期的Calendar对象

public static void main(String args[]) {
  Calendar c = Calendar.getInstance();//默认是当前日期
  System.out.println(c);
}
//输出
java.util.GregorianCalendar[time=1556350818634,areFieldsSet=true,areAllFields Set=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offs
et=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null],firs
tDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=3,WEEK_OF_YEAR=17
,WEEK_OF_MONTH=4,DAY_OF_MONTH=27,DAY_OF_YEAR=117,DAY_OF_WEEK=7,DAY_OF_WEEK_IN
_MONTH=4,AM_PM=1,HOUR=3,HOUR_OF_DAY=15,MINUTE=40,SECOND=18,MILLISECOND=634,ZO
NE_OFFSET=28800000,DST_OFFSET=0]

创建一个指定日期的Calendar对象

使用Calendar类代表特定的时间,需要首先创建一个Calendar的对象,然后再设定该对象中的年月日参数来完成。

//创建一个代表2019年4月27日的Calendar对象
Calendar c1 = Calendar.getInstance();
c1.set(2019, 4 - 1, 27);

Calendar类对象字段类型

Calendar类中用以下这些常量表示不同的意义,jdk内的很多类其实都是采用的这种思想

常量

描述

Calendar.YEAR

年份

Calendar.MONTH

月份

Calendar.DATE

日期

Calendar.DAY_OF_MONTH

日期,和上面的字段意义完全相同

Calendar.HOUR

12小时制的小时

Calendar.HOUR_OF_DAY

24小时制的小时

Calendar.MINUTE

分钟

Calendar.SECOND

Calendar.DAY_OF_WEEK

星期几

// 获得年份
int year = c1.get(Calendar.YEAR);
// 获得月份
int month = c1.get(Calendar.MONTH) + 1;
// 获得日期
int date = c1.get(Calendar.DATE);
// 获得小时
int hour = c1.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c1.get(Calendar.MINUTE);
// 获得秒
int second = c1.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
  int day = c1.get(Calendar.DAY_OF_WEEK);

【演示:设置完整日期】

c1.set(2009, 6 - 1, 12);//把Calendar对象c1的年月日分别设这为:2009、6、12

【演示:设置某个字段】

c1.set(Calendar.DATE,10);
c1.set(Calendar.YEAR,2008);
//其他字段属性set的意义以此类推

【add设置】

//把c1对象的日期加上10,也就是c1也就表示为10天后的日期,其它所有的数值会被重新计算
c1.add(Calendar.DATE, 10);
//把c1对象的日期减去10,也就是c1也就表示为10天前的日期,其它所有的数值会被重新计算
c1.add(Calendar.DATE, -10);

【演示:GregorianCalendar】

public static void main(String args[]) {
  String months[] = {
    "Jan", "Feb", "Mar", "Apr",
    "May", "Jun", "Jul", "Aug",
    "Sep", "Oct", "Nov", "Dec"};
  int year;
  // 初始化 Gregorian 日历
  // 使用当前时间和日期
  // 默认为本地时间和时区
  GregorianCalendar gcalendar = new GregorianCalendar();
  // 显示当前时间和日期的信息
  System.out.print("Date: ");
  System.out.print(months[gcalendar.get(Calendar.MONTH)]);
  System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
  System.out.println(year = gcalendar.get(Calendar.YEAR));
  System.out.print("Time: ");
  System.out.print(gcalendar.get(Calendar.HOUR) + ":");
  System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
  System.out.println(gcalendar.get(Calendar.SECOND));
  // 测试当前年份是否为闰年
  if(gcalendar.isLeapYear(year)) {
    System.out.println("当前年份是闰年");
  }
  else {
    System.out.println("当前年份不是闰年");
  }
}
//输出:
Date: Apr 27 2019
Time: 3:56:20
当前年份不是闰年

注意:Calender的月份是从0开始的,但日期和年份是从1开始的

【演示】

public static void main(String[] args) {
  Calendar c1 = Calendar.getInstance();
  c1.set(2017, 1, 1);
  System.out.println(c1.get(Calendar.YEAR)
                     +"-"+c1.get(Calendar.MONTH)
                     +"-"+c1.get(Calendar.DATE));
  c1.set(2017, 1, 0);
  System.out.println(c1.get(Calendar.YEAR)
                     +"-"+c1.get(Calendar.MONTH)
                     +"-"+c1.get(Calendar.DATE));
}
//输出
2017-1-1
2017-0-31

可见,将日期设为0以后,月份变成了上个月,但月份可以为0,把月份改为2试试:

public static void main(String[] args) {
  Calendar c1 = Calendar.getInstance();
  c1.set(2017, 2, 1);
  System.out.println(c1.get(Calendar.YEAR)
                     +"-"+c1.get(Calendar.MONTH)
                     +"-"+c1.get(Calendar.DATE));
  c1.set(2017, 2, 0);
  System.out.println(c1.get(Calendar.YEAR)
                     +"-"+c1.get(Calendar.MONTH)
                     +"-"+c1.get(Calendar.DATE));
}
//输出
2017-2-1
2017-1-28

可以看到上个月的最后一天是28号,所以Calendar.MONTH为1的时候是2月 。

Java8中新的日期时间API

  • java.time — 包含值对象的基础包
  • java.time.chrono — 提供对不同的日历系统的访问
  • java.time.format — 格式化和解析时间和日期
  • java.time.temporal — 包括底层框架和拓展特性
  • java.time.zone — 包含时区支持的类

说明:大多数开发者只会用到基础包和format包,也可能用到temporal包。

LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime类是其中重要的几个类,它们的实例对象是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与失去相关的信息。

ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。

  • LocalDate代表ISO格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期。
  • LocalTime表示一个时间,而不是日期。
  • LocalDateTime是用来表示日期和时间的,这是一个最常用的类。

now(); 获取当前的日期、时间、日期和时间;
of();  获取指定的年、月、日、时、分、秒(没有偏移量);

getXxx(); 获取相关的属性;
getDayOfMonth();/getDayOfYear();  获取月份天数(1-31)/获取年份天数(1-366);
getDayOfWeek();  获取星期几,返回一个DayOfWeek枚举值;
getMonth();  获得月份,返回一个Month枚举值;
getMonthValue();/getYear();  获得月份(1-12)/获得年份
getHour();/getMinute();/getSecond();  获取当前对象对应的小时、分钟、秒

withXxx();  设置相关的属性; 
withDayOfMonth();/withDayOfYear();/withMonth();/withYear();  设置月份天数、年份天数、月份、年份;
plusDays();/plusWeeks();/plusMonths();/plusYears();/plusHours();  添加几天、几周、几个月、几年、几小时;
minusDays();/minusWeeks();/minusMonths();/minusYears();/minusHours();  减去几天、几周、几月、几年、几小时;  

Instant瞬时

相关文章