Java30天养成计划 || 05 超全整理Java常用API

写在前面,大家好!我是【跨考菌】,一枚跨界的程序猿,专注于后台技术的输出,目标成为全栈攻城狮!这博客是对我跨界过程的总结和思考。如果你也对Java后端技术感兴趣,抑或是正在纠结于跨界,都可以关注我的动态,让我们一起学习,一起进步~
我的博客地址为:【跨考菌】的博客

上一篇 Java30天养成计划 || 04 Java运算符&流程控制讲解了Java中中运算符和流程控制相关知识点,本文开始介绍Java开发中的高频类。

在这里插入图片描述


1、Object类

1.1、概述

java.lang.Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。

如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:

public class MyClass /*extends Object*/ {
  	// ...
}

根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。


public final native Class<?> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。

public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。
public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。

protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。

public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。

public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。

public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。

public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。

public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。

public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念

protected void finalize() throws Throwable { }//实例被垃圾回收器回收的时候触发的操作

下面就几个重要的方法进行说明。

1.2、toString方法

public String toString():返回该对象的字符串表示。

toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值

由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。

方法重写
如果不希望使用toString方法的默认行为,则可以对它进行覆盖重写。例如自定义的Person类:

public class Person {  
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }

    // 省略构造器与Getter Setter
}

在IntelliJ IDEA中,可以点击Code菜单中的Generate...,也可以使用快捷键alt+insert,点击toString()选项。选择需要包含的成员变量并确定。

在我们直接使用输出语句输出对象名的时候,其实通过该对象调用了其toString()方法。

1.3、equals方法

public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

默认地址比较

如果没有覆盖重写equals方法,那么Object类中默认进行==运算符的对象地址比较,只要不是同一个对象,结果必然为false。

对象内容比较

如果希望进行对象的内容比较,即所有或指定的部分成员变量相同就判定两个对象相同,则可以覆盖重写equals方法。例如:

import java.util.Objects;

public class Person {	
	private String name;
	private int age;
	
    @Override
    public boolean equals(Object o) {
        // 如果对象地址一样,则认为相同
        if (this == o)
            return true;
        // 如果参数为空,或者类型信息不一样,则认为不同
        if (o == null || getClass() != o.getClass())
            return false;
        // 转换为当前类型
        Person person = (Person) o;
        // 要求基本类型相等,并且将引用类型交给java.util.Objects类的equals静态方法取用结果
        return age == person.age && Objects.equals(name, person.name);
    }
}

总结:

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型比较的是值,引用数据类型比较的是内存地址)。

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  • 情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
  • 情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

举个栗子:

public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 从常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

1.4、hashCode和equals【面试高频】

面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写 equals 时必须重写 hashCode 方法?”

1)hashCode介绍
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

2)为什么要有 hashCode

我们先以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode: 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与该位置其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的 Java 启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

通过我们可以看出:hashCode() 的作用就是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()在散列表中才有用,在其它情况下没用。在散列表中 hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

3)hashCode()与 equals()的相关规定

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

2、String、StringBuffer和StringBuilder

2.1、String类

1)String类介绍

简单来说,String 类中使用 final 关键字修饰字符数组来保存字符串,private final char value[],所以String 对象是不可变的。

2)String类构造方法

// 无参构造
String str = new String();
// 通过字符数组构造
char chars[] = {'a', 'b', 'c'};
String str2 = new String(chars);
// 通过字节数组构造
byte bytes[] = { 97, 98, 99 };
String str3 = new String(bytes);

3)String类的常用方法

// 判断功能
public boolean equals (Object anObject) //将此字符串与指定对象进行比较。
public boolean equalsIgnoreCase (String anotherString) //将此字符串与指定对象进行比较,忽略大小
写。

// 获取功能
public int length () :返回此字符串的长度。
public String concat (String str) :将指定的字符串连接到该字符串的末尾。
public char charAt (int index) :返回指定索引处的 char值。
public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引。
public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符
串结尾。
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到
endIndex截取字符串。含beginIndex,不含endIndex

// 转换功能
public char[] toCharArray () :将此字符串转换为新的字符数组。
public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使
用replacement字符串替换。

// 分割功能
public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。

字符串拼接问题:

由于String类的对象内容不可改变,所以每当进行字符串拼接时,总是会在内存中创建一个新的对象。例如:

public class StringDemo {
    public static void main(String[] args) {
        String s = "Hello";
        s += "World";
        System.out.println(s);
    }
}

根据这句话分析我们的代码,其实总共产生了三个字符串,即"Hello"、"World"和"HelloWorld"。引用变量s首先指向Hello对象,最终指向拼接出来的新字符串对象,即HelloWord 。

由此可知,如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。为了解决这一问题,可以使用java.lang.StringBuilder类。

2.2、StringBuilder和StringBuffer类

1)介绍

StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilde 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串char[]value但是没有用 final 关键字修饰,所以这两种对象都是可变的。

其实,StringBuilder是个字符串的缓冲区,即它是一个容器,容器中可以装很多字符串。并且能够对其中的字符串进行各种操作。

它的内部拥有一个数组用来存放字符串内容,进行字符串拼接时,直接在数组中加入新内容。StringBuilder会自动维护数组的扩容。原理如下图所示:(默认16字符空间,超过自动扩充)

2)构造方法

public StringBuilder():构造一个空的StringBuilder容器。
public StringBuilder(String str):构造一个StringBuilder容器,并将字符串添加进去。

3)常用方法

public StringBuilder append(...):添加任意类型数据的字符串形式,并返回当前对象自身。
public String toString():将当前StringBuilder对象转换为String对象。

2.3、三者的对比

线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilderStringBuilderStringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacityappendinsertindexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结:

  1. 操作少量的数据: 适用 String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

3、System类

java.lang.System类中提供了大量的静态方法,可以获取与系统相关的信息或系统级操作,在System类的API文档中,常用的方法有:

  • public static long currentTimeMillis():返回以毫秒为单位的当前时间。
  • public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):将数组中指定的数据拷贝到另一个数组中。

完整的方法如图:
在这里插入图片描述

3.1 currentTimeMillis方法

实际上,currentTimeMillis方法就是 获取当前系统时间与1970年01月01日00:00点之间的毫秒差值

import java.util.Date;

public class SystemDemo {
    public static void main(String[] args) {
       	//获取当前时间毫秒值
        System.out.println(System.currentTimeMillis()); // 1516090531144
    }
}

案例

验证for循环打印数字1-9999所需要使用的时间(毫秒)

public class SystemTest1 {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            System.out.println(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("共耗时毫秒:" + (end - start));
    }
}

3.2 arraycopy方法

  • public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):将数组中指定的数据拷贝到另一个数组中。

数组的拷贝动作是系统级的,性能很高。System.arraycopy方法具有5个参数,含义分别为:

参数序号参数名称参数类型参数含义
1srcObject源数组
2srcPosint源数组索引起始位置
3destObject目标数组
4destPosint目标数组索引起始位置
5lengthint复制元素个数

案例

将src数组中前3个元素,复制到dest数组的前3个位置上复制元素前:src数组元素[1,2,3,4,5],dest数组元素[6,7,8,9,10]复制元素后:src数组元素[1,2,3,4,5],dest数组元素[1,2,3,9,10]

import java.util.Arrays;

public class Demo11SystemArrayCopy {
    public static void main(String[] args) {
        int[] src = new int[]{1,2,3,4,5};
        int[] dest = new int[]{6,7,8,9,10};
        System.arraycopy( src, 0, dest, 0, 3);
        /*代码运行后:两个数组中的元素发生了变化
         src数组元素[1,2,3,4,5]
         dest数组元素[1,2,3,9,10]
        */
    }
}

4、Date类

4.1、概述

java.util.Date类 表示特定的瞬间,精确到毫秒。

Date类常用的两个构造方法如下:

  • public Date():分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。
  • public Date(long date):分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即1970年1月1日00:00:00 GMT)以来的指定毫秒数。

tips: 由于我们处于东八区,所以我们的基准时间为1970年1月1日8时0分0秒。

简单来说:使用无参构造,可以自动设置当前系统时间的毫秒时刻;指定long类型的构造参数,可以自定义毫秒时刻。例如:

import java.util.Date;

public class Demo01Date {
    public static void main(String[] args) {
        // 创建日期对象,把当前的时间
        System.out.println(new Date()); // Sat Nov 28 20:54:44 CST 2020
        // 创建日期对象,把当前的毫秒值转成日期对象
        System.out.println(new Date(0L)); // Thu Jan 01 08:00:00 CST 1970
    }
}

tips:在使用println方法时,会自动调用Date类中的toString方法。Date类对Object类中的toString方法进行了覆盖重写,所以结果为指定格式的字符串。

常用方法

Date类中的多数方法已经过时,常用的方法有:

  • public long getTime() 把日期对象转换成对应的时间毫秒值。

4.2、DateFormat类

java.text.DateFormat 是日期/时间格式化子类的抽象类,我们通过这个类可以帮我们完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行来回转换。

  • 格式化:按照指定的格式,从Date对象转换为String对象。
  • 解析:按照指定的格式,从String对象转换为Date对象。

1)构造方法

由于DateFormat为抽象类,不能直接使用,所以需要常用的子类java.text.SimpleDateFormat。这个类需要一个模式(格式)来指定格式化或解析的标准。构造方法为:

  • public SimpleDateFormat(String pattern):用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat。

参数pattern是一个字符串,代表日期时间的自定义格式。

2)格式规则

常用的格式规则为:

标识字母(区分大小写)含义
y
M
d
H
m
s

备注:更详细的格式规则,可以参考SimpleDateFormat类的API文档0。

创建SimpleDateFormat对象的代码如:

import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class Demo02SimpleDateFormat {
    public static void main(String[] args) {
        // 对应的日期格式如:2018-01-16 15:06:38
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }    
}

3)常用方法

DateFormat类的常用方法有:

  • public String format(Date date):将Date对象格式化为字符串。
  • public Date parse(String source):将字符串解析为Date对象。

①format方法

使用format方法的代码为:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
 把Date对象转换成String
*/
public class Demo03DateFormatMethod {
    public static void main(String[] args) {
        Date date = new Date();
        // 创建日期格式化对象,在获取格式化对象时可以指定风格
        DateFormat df = new SimpleDateFormat("yyyy年MM月dd日");
        String str = df.format(date);
        System.out.println(str); // 2008年1月23日
    }
}

②parse方法

使用parse方法的代码为:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
 把String转换成Date对象
*/
public class Demo04DateFormatMethod {
    public static void main(String[] args) throws ParseException {
        DateFormat df = new SimpleDateFormat("yyyy年MM月dd日");
        String str = "2018年12月11日";
        Date date = df.parse(str);
        System.out.println(date); // Tue Dec 11 00:00:00 CST 2018
    }
}

4.3、案例

请使用日期时间相关的API,计算出一个人已经出生了多少天。

思路:

1.获取当前时间对应的毫秒值

2.获取自己出生日期对应的毫秒值

3.两个时间相减(当前时间– 出生日期)

代码实现:

public static void function() throws Exception {
	System.out.println("请输入出生日期 格式 YYYY-MM-dd");
	// 获取出生日期,键盘输入
	String birthdayString = new Scanner(System.in).next();
	// 将字符串日期,转成Date对象
	// 创建SimpleDateFormat对象,写日期模式
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	// 调用方法parse,字符串转成日期对象
	Date birthdayDate = sdf.parse(birthdayString);	
	// 获取今天的日期对象
	Date todayDate = new Date();	
	// 将两个日期转成毫秒值,Date类的方法getTime
	long birthdaySecond = birthdayDate.getTime();
	long todaySecond = todayDate.getTime();
	long secone = todaySecond-birthdaySecond;	
	if (secone < 0){
		System.out.println("还没出生呢");
	} else {
		System.out.println(secone/1000/60/60/24);
	}
}

5、Calendar类

5.1、概念

java.util.Calendar是日历类,在Date后出现,替换掉了许多Date的方法。该类将所有可能用到的时间信息封装为静态成员变量,方便获取。日历类就是方便获取各个时间属性的。

5.2、获取方式

Calendar为抽象类,由于语言敏感性,Calendar类在创建对象时并非直接创建,而是通过静态方法创建,返回子类对象,如下:

Calendar静态方法

  • public static Calendar getInstance():使用默认时区和语言环境获得一个日历

例如:

import java.util.Calendar;

public class Demo06CalendarInit {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
    }    
}

5.3、常用方法

根据Calendar类的API文档,常用方法有:

  • public int get(int field):返回给定日历字段的值。
  • public void set(int field, int value):将给定的日历字段设置为给定值。
  • public abstract void add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
  • public Date getTime():返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的Date对象。

Calendar类中提供很多成员常量,代表给定的日历字段:

字段值含义
YEAR
MONTH月(从0开始,可以+1使用)
DAY_OF_MONTH月中的天(几号)
HOUR时(12小时制)
HOUR_OF_DAY时(24小时制)
MINUTE
SECOND
DAY_OF_WEEK周中的天(周几,周日为1,可以-1使用)

① get/set方法

get方法用来获取指定字段的值,set方法用来设置指定字段的值,代码使用演示:

import java.util.Calendar;

public class CalendarUtil {
    public static void main(String[] args) {
        // 创建Calendar对象
        Calendar cal = Calendar.getInstance();
        // 设置年 
        int year = cal.get(Calendar.YEAR);
        // 设置月
        int month = cal.get(Calendar.MONTH) + 1;
        // 设置日
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        System.out.print(year + "年" + month + "月" + dayOfMonth + "日");
    }    
}
import java.util.Calendar;

public class Demo07CalendarMethod {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, 2020);
        System.out.print(year + "年" + month + "月" + dayOfMonth + "日"); // 2020年1月17日
    }
}

② add方法

add方法可以对指定日历字段的值进行加减操作,如果第二个参数为正数则加上偏移量,如果为负数则减去偏移量。代码如:

import java.util.Calendar;

public class Demo08CalendarMethod {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        System.out.print(year + "年" + month + "月" + dayOfMonth + "日"); // 2018年1月17日
        // 使用add方法
        cal.add(Calendar.DAY_OF_MONTH, 2); // 加2天
        cal.add(Calendar.YEAR, -3); // 减3年
        System.out.print(year + "年" + month + "月" + dayOfMonth + "日"); // 2015年1月18日; 
    }
}

③ getTime方法

Calendar中的getTime方法并不是获取毫秒时刻,而是拿到对应的Date对象。

import java.util.Calendar;
import java.util.Date;

public class Demo09CalendarMethod {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        Date date = cal.getTime();
        System.out.println(date); // Tue Jan 16 16:03:09 CST 2018
    }
}

小贴士:

​ 西方星期的开始为周日,中国为周一。

​ 在Calendar类中,月份的表示是以0-11代表1-12月。

​ 日期是有大小关系的,时间靠后,时间越大。

6、Random类

此类的实例用于生成伪随机数

例如:

Random r = new Random();
int i = r.nextInt();

public int nextInt(int n) :返回一个伪随机数,范围在 0 (包括)和 指定值 n (不包括)之间的int 值

6.1、不带种子

生成1-n(包含n)之间的随机整数:

// 导包
import java.util.Random;
public class Test01Random {
public static void main(String[] args) {
		int n = 50;
		// 创建对象
		Random r = new Random(); // 不带种子
		for  (int i = 0; i < 10; i++) {
            System.out.println(r.nextInt(10)); // 每次运行获得不同的10个数
        }
	}
}

6.2、带种子

// 导包
import java.util.Random;
public class Test01Random {
public static void main(String[] args) {
		int n = 50;
		// 创建对象
		Random r = new Random(11); // 带种子
		for  (int i = 0; i < 10; i++) {
            System.out.println(r.nextInt(10)); // 每次运行获得相同的10个数
        }
	}
}

6.3、总结

如何获得范围在[a,b]的数?

r.nextInt() * (b-a)+a

7、Math类

7.1、概述

java.lang.Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。类似这样的工具类,其所有方法均为静态方法,并且不会创建对象,调用起来非常简单。

7.2、基本运算的方法

1)public static double abs(double a) :返回 double 值的绝对值

double d1 = Math.abs(5); //d1的值为5
double d2 = Math.abs(5); //d2的值为5

2)public static double ceil(double a) :返回大于等于参数的最小的整数。

double d1 = Math.ceil(3.3); //d1的值为 4.0
double d2 = Math.ceil(3.3); //d2的值为 ‐3.0
double d3 = Math.ceil(5.1); //d3的值为 6.0

3)public static double floor(double a) :返回小于等于参数最大的整数。

double d1 = Math.floor(3.3); //d1的值为3.0
double d2 = Math.floor(3.3); //d2的值为‐4.0
double d3 = Math.floor(5.1); //d3的值为 5.0

4)public static long round(double a) :返回最接近参数的 long。(相当于四舍五入方法)

long d1 = Math.round(5.5); //d1的值为6.0
long d2 = Math.round(5.4); //d2的值为5.0

8、Arrays类

java.util.Arrays 此类包含用来操作数组的各种方法,比如排序和搜索等。其所有方法均为静态方法,调用起来非常简单。

Arrays类的常用方法如下:

boolean equals(array1,array2):比较两个数组是否相等
void sort(array):对数组array元素进行升序排序
String toString(array):该方法将会一个数组array转换成一个字符串
void fill(array,val):把数组array所有元素都赋值为val
copyof(array,length):把数组array复制成一个长度为length的新数组
int binarySearch(array,val):查询元素值val在数组array中下标

测试:

int[] array = new int[5];
//填充数组
Arrays.fill(array,5); // 5 5 5 5 5 


//将数组的索引2到3的元素赋值为8
Arrays.fill(array,2,4,8); // 5 5 8 8 5 

int[] array1 = {7,8,3,2,12,6,3,5,4};
//对数组的第2个到第6个进行排序
Arrays.sort(array1,2,7); // 7 8 2 3 3 6 12 5 4

 //对整个数组进行排序
Arrays.sort(array1); // 2 3 3 4 5 6 7 8 12

//比较数组元素是否相等
boolean b = Arrays.equals(array,array1); // false
int[] array2 = array1.clone(); // 2 3 3 4 5 6 7 8 12

9、Collections类

9.1、常用功能

java.utils.Collections是集合工具类,用来对集合进行操作。部分方法如下:

  • public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。
  • public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。
  • public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
  • public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。

案例:

public class CollectionsDemo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        //原来写法
        //list.add(12);
        //list.add(14);
        //list.add(15);
        //list.add(1000);
        //采用工具类 完成 往集合中添加元素  
        Collections.addAll(list, 5, 222, 12);
        System.out.println(list);
        //排序方法 
        Collections.sort(list);
        System.out.println(list);
    }
}
结果:
[5, 222, 1, 2]
[1, 2, 5, 222]

发现我们的集合按照顺序进行了排列,可是这样的顺序是采用默认的顺序,如果想要指定顺序那该怎么办呢?

我们发现还有个方法没有讲,public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。接下来讲解一下指定规则的排列。

9.2 Comparator比较器

public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。

不过这次存储的是字符串类型。

public class CollectionsDemo2 {
    public static void main(String[] args) {
        ArrayList<String>  list = new ArrayList<String>();
        list.add("cba");
        list.add("aba");
        list.add("sba");
        list.add("nba");
        //排序方法
        Collections.sort(list);
        System.out.println(list);
    }
}

结果:

[aba, cba, nba, sba]

我们使用的是默认的规则完成字符串的排序,那么默认规则是怎么定义出来的呢?

说到排序了,简单的说就是两个对象之间比较大小,那么在JAVA中提供了两种比较实现的方式,一种是比较死板的采用java.lang.Comparable接口去实现,一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator接口完成。

那么我们采用的public static <T> void sort(List<T> list)这个方法完成的排序,实际上要求了被排序的类型需要实现Comparable接口完成比较的功能,在String类型上如下:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {

String类实现了这个接口,并完成了比较规则的定义,但是这样就把这种规则写死了,那比如我想要字符串按照第一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了,那么这个时候我们可以使用

public static <T> void sort(List<T> list,Comparator<? super T> )方法灵活的完成,这个里面就涉及到了Comparator这个接口,位于位于java.util包下,排序是comparator能实现的功能之一,该接口代表一个比较器,比较器具有可比性!顾名思义就是做排序的,通俗地讲需要比较两个对象谁排在前谁排在后,那么比较的方法就是:

  • public int compare(String o1, String o2):比较其两个参数的顺序。

    两个对象比较的结果有三种:大于,等于,小于。

    如果要按照升序排序,
    则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数)
    如果要按照降序排序
    则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

操作如下:

public class CollectionsDemo3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("cba");
        list.add("aba");
        list.add("sba");
        list.add("nba");
        //排序方法  按照第一个单词的降序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.charAt(0) - o1.charAt(0);
            }
        });
        System.out.println(list);
    }
}

结果如下:

[sba, nba, cba, aba]

9.3 Comparable和Comparator的区别

Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

Comparator强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。

案例:

创建一个学生类,存储到ArrayList集合中完成指定排序操作。

Student 初始类

public class Student{
    private String name;
    private int age;

    public Student() {
    }

    public Student(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 "Student{" +
               "name='" + name + '\'' +
               ", age=" + age +
               '}';
    }
}

测试类:

public class Demo {

    public static void main(String[] args) {
        // 创建四个学生对象 存储到集合中
        ArrayList<Student> list = new ArrayList<Student>();

        list.add(new Student("rose",18));
        list.add(new Student("jack",16));
        list.add(new Student("abc",16));
        list.add(new Student("ace",17));
        list.add(new Student("mark",16));


        /*
          让学生 按照年龄排序 升序
         */
//        Collections.sort(list);//要求 该list中元素类型  必须实现比较器Comparable接口


        for (Student student : list) {
            System.out.println(student);
        }


    }
}

发现,当我们调用Collections.sort()方法的时候 程序报错了。

原因:如果想要集合中的元素完成排序,那么必须要实现比较器Comparable接口。

于是我们就完成了Student类的一个实现,如下:

public class Student implements Comparable<Student>{
    ....
    @Override
    public int compareTo(Student o) {
        return this.age-o.age;//升序
    }
}

再次测试,代码就OK 了效果如下:

Student{name='jack', age=16}
Student{name='abc', age=16}
Student{name='mark', age=16}
Student{name='ace', age=17}
Student{name='rose', age=18}

扩展

如果在使用的时候,想要独立的定义规则去使用 可以采用Collections.sort(List list,Comparetor c)方式,自己定义规则:

Collections.sort(list, new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o2.getAge()-o1.getAge();//以学生的年龄降序
    }
});

效果:

Student{name='rose', age=18}
Student{name='ace', age=17}
Student{name='jack', age=16}
Student{name='abc', age=16}
Student{name='mark', age=16}

如果想要规则更多一些,可以参考下面代码:

Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                // 年龄降序
                int result = o2.getAge()-o1.getAge();//年龄降序

                if(result==0){//第一个规则判断完了 下一个规则 姓名的首字母 升序
                    result = o1.getName().charAt(0)-o2.getName().charAt(0);
                }

                return result;
            }
        });

效果如下:

Student{name='rose', age=18}
Student{name='ace', age=17}
Student{name='abc', age=16}
Student{name='jack', age=16}
Student{name='mark', age=16}

在这里插入图片描述

最后,如果您觉得对您有帮助的话,不要忘记帮助帮博主一键三连😊哦

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值