1 常用API

  • API(:Application Programming Interface ):应用程序编程接口

1.1 Math类(java.lang)

Math类包含执行基本数字运算的方法,如基本指数,对数,平方根和三角函数。
  • Math中没有构造方法类的成员都是静态的(static修饰),通过类名就可以直接调用

  • 静态常量

    • static final double PI = 3.141……(精确到19位)
    • static double exp(double a) :返回Euler的数字 e ,其值 double值。
      • 用于计算 Euler’s 数(自然对数的底 e)的 a 次幂。参数 a 是幂的指数。
  • 常用方法

方法名 说明
public static int abs(int a) 获取参数a的绝对值
public static double ceil(double a) 向上取整
public static double floor(double a) 向下取整
public static long round(double a) 四舍五入取整
public static int max(int a,int b) 返回两个数中较大值
public static int min(int a,int b) 返回两个数中较小值
public static double pow(double a,double b) 获取a的b次幂
public static double random() 返回值为double类型随机数 [0.0~1.0)
static double cos(double a) 返回角度的三角余弦值。
static double acos(double a) 返回值的反余弦值; 返回的角度在0.0到pi的范围内。
static double expm1(double x) 返回 e^x -1
static double log(double a) 返回 double值的自然对数(基数 e )
static double log10(double a) 返回 double值的基数10对数。
static double sqrt(double a) 返回 double值的正确舍入正平方根。
static double toDegrees(double angrad) 将以弧度测量的角度转换为以度为单位测量的近似等效角度。
static double toRadians(double angdeg) 将以度为单位测量的角度转换为以弧度为单位测量的近似等效角度。
public class MathDemo {
    public static void main(String[] args) {
        //1、public static int abs(int a)	获取参数a的绝对值
        System.out.println(Math.abs(88)); //88
        System.out.println(Math.abs(-88)); //88

        //2、public static double ceil(double a)	向上取整
        System.out.println(Math.ceil(12.34)); //13.0
        System.out.println(Math.ceil(12.56)); //13.0

        //3、public static double floor(double a)	向下取整
        System.out.println(Math.floor(12.34)); //12.0
        System.out.println(Math.floor(12.56)); //12.0

        //4、public static long round(double a)	四舍五入取整
        System.out.println(Math.round(12.34)); //12
        System.out.println(Math.round(12.56)); //13

        //5、public static int max(int a,int b)	返回两个数中较大值
        System.out.println(Math.max(66,88)); //88

        //6、public static int min(int a,int b)	返回两个数中较小值
        System.out.println(Math.min(66,88)); //66

        //7、public static double pow(double a,double b)	获取a的b次幂
        System.out.println(Math.pow(2.0,3.0)); //8.0

        //8、public static double random()	返回值为double类型随机数 [0.0~1.0)
        System.out.println(Math.random()); //0.36896250602163483
        System.out.println(Math.random()); //0.3507783145075083
    }
}

1.2 System类

  • System被静态修饰,通过类名访问

  • 常用方法

    • static long currentTimeMillis():返回以毫秒为单位的当前时间。//获取毫秒值形式的当前时间。

      常用于测试程序效率
      
    • static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):将数组中指定的数据拷贝到另一个数组中。

    • src Object:源数组(原来的数组)。

      src Posint:源数组索引起始位置。dest Object:目标数组。dest Posint:目标数组索引起始位置。length int:复制元素个数。
      
    • static void setErr(PrintStream err):重新分配“标准”错误输出流。

    • static void setIn(InputStream in):重新分配“标准”输入流。

    • static void setOut(PrintStream out):重新分配“标准”输出流。

    • public static void exit(int status) 终止JVM虚拟机,非 0 是异常终止 System.exit(0);

    import java.text.SimpleDateFormat;
    
    public class SystemDemo {
        public static void main(String[] args) {
            /*
            System.out.println("开始"); //开始
            //1、public static void exit(int status)	终止JVM虚拟机,非 0 是异常终止
            System.exit(0);
            System.out.println("结束"); //没有输出结束
            */
    
            //2、public static long currentTimeMillis()	返回当前时间(以毫秒为单位)
            System.out.println(System.currentTimeMillis()); //1625491582918
            long time = System.currentTimeMillis();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
            System.out.println(sdf.format(time)); //2023年12月05日 21:26:22 星期一 下午
        }
    }
    

1.3 Object类(java.lang)

  • Object 类是 Java 中的祖宗类,所有类都直接或者间接继承自该类

    • Class Object是类Object结构的根。 每个班都有Object作为超类。 所有对象(包括数组)都实现了这个类的方法。
  • 只有无参构造方法public Object()

  • 常用方法

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

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

    • int hasCode():返回该对象的哈希码值。

      HashSet集合存放自定义类型元素时,需要重写对象中的hashCode和equals方法
      
    • void wait():在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。

    • void wait(long timeout):在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。

    • void wait(long timeout, int nanos):在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。

    • void notify():唤醒在此对象监视器上等待的单个线程。

    • void notifyAll():唤醒在此对象监视器上等待的所有线程。
      Class<?> getClass():返回此 Object 的运行时类。

    • protected Object clone():创建并返回此对象的一个副本。

    • protected void finalize():当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。

1、public String toString()

默认是返回当前对象在堆内存中的地址信息
直接输出对象名称,默认会调用 toString()方法,所以直接输出对象可以省略 toString()
所以 toString() 存在的意义是为了被子类重写,以便能够返回对象的数据内容输出
重写快捷键:按下Fn+Alt+Insert / 右键 -> generate -> toString -> OK
看方法的源码:选中方法,按Ctrl+B

package ceshi;

public class Student extends Object{
    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;
}

//自动生成重写toString()方法;按下Fn+Alt+Insert / 右键 -> generate -> toString -> OK
@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}

}
package ceshi;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("yy");
        s.setAge(20);
        System.out.println(s); //ceshi.Student@1b6d3586
        System.out.println(s.toString()); //ceshi.Student@1b6d3586
        //重写后输出
        /*源码
        Student{name='yy', age=20}
        Student{name='yy', age=20}*/

        //选中方法Ctrl+B查看方法源码
        /*public void println(Object x) { //1、x = s
            String s = String.valueOf(x);
            synchronized (this) {
                print(s);
                newLine();
            }
        }*/
    
        /*public static String valueOf(Object obj) { //2、obj = x
            return (obj == null) ? "null" : obj.toString();
        }*/
    
        /*public String toString() { //3、
            return getClass().getName() + "@" + Integer.toHexString(hashCode()); //所以重写前才会输出ceshi.Student@1b6d3586
        }*/
    }

}

2、public boolean equals(Object o)

默认是比较两个对象的地址是否相同,相同返回true
直接比较两个对象的地址是否完全相同,可以用”==”替代equals
所以 equals 存在的意义是为了被子类重写
重写快捷键:按下Fn+Alt+Insert -> generate -> equals() and hashCode() -> Template:选择 IntelliJ default -> 三个next > finsh ;然后删除hashCode()方法

package ceshi;

public class Student extends Object{
    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;
    }
    
    //自动生成重写equals()方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true; //1、比较地址是否相同,如果相同就是同一个对象,直接返回true
        //2、先判断参数是否为null;判断连个对象是否来自同一个类;一个满足就返回false
        if (o == null || getClass() != o.getClass()) return false;
        //向下转型
        Student student = (Student) o; //student = s2;
        //3、比较年龄是否相同,年龄相同往下走
        if (age != student.age) return false;
        //比较名字是否相同,s1的name不是null才能取调方法
        return name != null ? name.equals(student.name) : student.name == null;
    }

}
package ceshi;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("yy");
        s1.setAge(20);

        Student s2 = new Student();
        s2.setName("yy");
        s2.setAge(20);
    
        //比较两个对象内容是否相等
        System.out.println(s1.equals(s2)); //重写前:false ; 重写后:true
        /*public boolean equals(Object obj) {
            //this---s1
            //obj---s2
            return (this == obj); //重写前==比较的是地址值,不是内容需要重写equals()方法
        }*/
    
    }

}

1.4 Objects类 (java.util)

  • Objects类是 jdk 1.7 开始之后才有的

  • 常用方法

    • public static boolean equals(Object a, Object b) 比较两个对象内容是否相等

    • public static boolean isNull(Object obj) 判断变量是否为 null , 为 null 返回 true

public class ObjectsDemo {
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
        System.out.println(s1.equals(s2));
        System.out.println(Objects.equals(s1,s2));
        // true
        // true

        //询问s1是否为null,为null返回true
        System.out.println(Objects.isNull(s1));
    }

}

1.5 Arrays类 (java.util)

  • Arrays类包含用于操作数组的各种方法

  • 工具类的设计思想

    • 构造方法用 private 修饰(防止外界创建对象)
    • 成员用 public static 修饰(使用类名来访问
  • 常用方法

    -

    • 方法 描述
      public static String toString(int[] a) 返回指定数组的内容的字符串表示形式
      sort(T[] a) 对数组进行自然排序
      sort(T[] a, Comparator<? super T> c) 使用指定的比较器对数组进行排序
      binarySearch(T[] a, T key) 在已排序的数组中使用二分搜索算法查找指定元素的索引
      binarySearch(T[] a, int fromIndex, int toIndex, T key) 在指定范围内的已排序数组中使用二分搜索算法查找指定元素的索引
      fill(T[] a, T val) 使用指定的值填充整个数组
      fill(T[] a, int fromIndex, int toIndex, T val) 使用指定的值填充数组的指定范围
      equals(T[] a, T[] a2) 比较两个数组是否相等
      deepEquals(Object[] a1, Object[] a2) 深度比较两个数组是否相等
      toString(T[] a) 返回包含数组元素的字符串表示形式
      asList(T... a) 将指定数组转换为 List
      copyOf(T[] original, int newLength) 复制指定数组的副本,截取或填充空值以使副本具有指定的长度
      copyOfRange(T[] original, int from, int to) 复制指定数组的指定范围
  • 冒泡排序

package ceshi;

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = {21,56,15,89,62};
        System.out.println("排序前:"+arrayToString(arr)); //排序前:[21, 56, 15, 89, 62]

        //冒泡排序
        for(int i=0;i<arr.length-1;i++) {
            for(int x=0;x< arr.length-1-i;x++) {
                if(arr[x] > arr[x+1]) {
                    //当前一个大于后一个时,双方交换位置
                    int temp = arr[x];
                    arr[x] = arr[x+1];
                    arr[x+1] = temp;
                }
            }
        }
        System.out.println("排序后:"+arrayToString(arr)); //排序后:[15, 21, 56, 62, 89]

    }
    public static String arrayToString(int[] arr) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for(int i=0;i<arr.length;i++) {
            if(i==arr.length-1) {
                sb.append(arr[i]);
            }else {
                sb.append(arr[i]).append(", ");
            }
        }
        sb.append("]");
        String s = sb.toString();
        return s;
    }
}
//排序前:[21, 56, 15, 89, 62]
//排序后:[15, 21, 56, 62, 89]

image-20240311004011670

  • Arrays方法范例
package ceshi;

import java.util.Arrays;

public class ArrayDemo {
    public static void main(String[] args) {
        int[] arr = {21,56,15,89,62};
        //1、public static String toString(int[] a) 	返回指定数组的内容的字符串表示形式
        System.out.println("排序前:"+ Arrays.toString(arr)); //排序前:[21, 56, 15, 89, 62]
        //2、public static void sort(int[] a) 	按照数字排序指定的数组
        Arrays.sort(arr);
        System.out.println("排序后:"+Arrays.toString(arr)); //排序后:[15, 21, 56, 62, 89]
    }
}

1.6 基本类型包装类

  • 将基本数据类型封装成对象的好处在于在对象中定义更多的功能方法操作该数据
  • 常用的操作之一:用于基本数据类型与字符串之间的转换
基本数据类型 包装类
byte Byte
short Short
int Integer(重点)
long Long
float Float
double Double
char Character(特殊)
boolean Boolean

包装类和基本数据类型的区别

存储方式

  • 基本数据类型存储的是实际的数据值,它们在栈上分配内存。
  • 包装类存储的是对象的引用,它们在堆上分配内存。

对象特性

  • 基本数据类型不是对象,因此它们没有方法或属性。
  • 包装类是对象,它们具有方法和属性,可以进行对象操作。

装箱(基本类型的数据->包装类)

1.6.1 Integer类概述和使用

  • Integer:包装一个对象中原始类型int的值
  • 常用方法

构造方法:

  • Integer(int value):构造一个新分配的 Integer 对象,它表示指定的 int 值。(过时)

  • Integer(String s):构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。(传递的字符串,必须是基本类型的字符串,否则会抛出异常 “100” 正确 “a” 抛异常)

静态方法:

  • static Integer valueOf(int i):返回一个表示指定的 int 值的 Integer 实例。

  • static Integer valueOf(String s):返回保存指定的 String 的值的 Integer 对象。

进制转换静态方法:

  • static String toBinaryString(int i):返回数字i的二进制数字符串。
  • static String toOctalString(int i):返回数字i的八进制数字符串。
  • static String toHexString(int i):返回数字i的十六进制数字符串。
  • static int parseInt(String s): 将字符串参数s解析为带符号的十进制整数。
  • static int parseInt(String s, int radix): 将整数字符串s(radix用来指明s是几进制)转换成10进制的整数。

1.6.2 int 和 String 的相互转换

  • 1、int 转换为 String 类型
    • public static String valueOf(int i):返回 int 参数的字符串表示形式。该方法是 String 类中的方法
  • 2、String 转换为 int 类型
    • public static int parselnt(String s):将字符串解析为int类型。该方法是 Integer 类中的方法
package ceshi;

public class IntegerDemo {
    public static void main(String[] args) {
        //int --- String
        int number = 10;
        //1、public static String valueOf (int i)
        String s = String.valueOf(number);
        System.out.println(s); //10

        //String --- int
        String s1 = "100";
        //2、public static int parseInt(String s)
        int i = Integer.parseInt(s1);
        System.out.println(i); //100
    }
}

1.6.3 案例:字符串中数据排序

package ceshi; // 定义一个包名为"ceshi"

import java.util.Arrays; // 导入 Arrays 类,用于排序数组

public class IntegerTest {
    public static void main(String[] args) {
        String s = "15 8 45 32 21"; // 定义一个包含整数字符串
        String[] strArray = s.split(" "); // 使用空格作为分隔符将字符串分割为字符串数组

        int[] arr = new int[strArray.length]; // 创建一个整型数组,长度与字符串数组相同
        for (int i = 0; i < arr.length; i++) {
            arr[i] = Integer.parseInt(strArray[i]); // 将字符串数组中的每个元素转换为整数并赋值给整型数组
        }

        Arrays.sort(arr); // 使用 Arrays 类的 sort 方法对整型数组进行排序

        StringBuilder sb = new StringBuilder(); // 创建一个 StringBuilder 对象,用于拼接排序后的整数字符串
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                sb.append(arr[i]); // 如果是数组最后一个元素,不添加逗号
            } else {
                sb.append(arr[i]).append(", "); // 否则添加逗号和空格
            }
        }
        String s1 = sb.toString(); // 将 StringBuilder 对象转换为字符串

        System.out.println(s1); // 输出排序后的整数字符串
    }
}

1.6.4 自动装箱和拆箱

  • 自动装箱: 可以直接把基本数据类型的值或变量赋值给包装类
  • 自动拆箱: 可以把包装类的变量直接赋值给基本数据类型
public class PackageClass {
    public static void main(String[] args) {
        //基本数据类型的值或变量赋值给包装类
        Integer i = Integer.valueOf(100); //手动调方法装箱
        Integer ii = 100; //默认调用Integer.valueOf(100);
        //拆箱
        int i1 = ii; //自动拆箱,100
        ii +=200; //
        System.out.println(ii) //300
        

        //开发中如果是引用类型变量最好先做不为null判断
        Integer iii = null;
        if(iii != null) {
            iii += 300; //NullPointerException
        }
              
    }

}
  • 注意:在使用包装类的时候,如果是操作最好先判断是否为null;推荐只要是对象,再使用前必须进行不为null判断

1.7 日期类

1.7.1 Date类

  • 导包java.util.Date
  • 构造方法
方法名 说明
public Date() 创建当前系统的此刻日期时间对象
public Date(long time) 把时间毫秒值转换成日期对象
package ceshi;

import java.util.Date;

public class DateDemo {
    public static void main(String[] args) {
        //1、public Date()
        Date d1 = new Date();
        System.out.println(d1); //Tue Jul 06 22:36:15 CST 2021

        //2、public Date(long time)
        long date = 60;
        Date d2 = new Date(date);
        System.out.println(d2); //Thu Jan 01 08:00:00 CST 1970
    }

}
  • 常用方法
方法名 说明
public long getTime() 获取日期对象从1970年1月1日00:00:00 到现在的毫秒值
public void setTime(long time) 设置时间,给的是毫秒值
package ceshi;

import java.util.Date;

public class DateDemo {
    public static void main(String[] args) {
        //1、public long getTime() 	获取日期对象从1970年1月1日00:00:00 到现在的毫秒值
        Date d = new Date();
        System.out.println(d.getTime()); //1625582796041

        //2、public void setTime(long time) 	设置时间,给的是毫秒值
        long time = 1000*60*60;
        d.setTime(time);
        System.out.println(d); //Thu Jan 01 09:00:00 CST 1970
    }
}

1.7.2 SimpleDateFormat类 [ˈsɪmpl]

  • 可以对日期格式化和解析
  • 日期和时间格式由日期和时间模式字符串指定,在日期和时间模式字符串中,从 ‘A’ 到 ‘Z’ 以及从 ‘a’ 到’z’ 引号的字母被解释为表示日期或时间字符串的组件的模式字母
  • 常用的模式字母对应: y—年;M—月;d—日;H—时;m—分;s—秒;E—星期几;a—上午 / 下午
  • 构造方法:
方法名 说明
public SimpleDateFormat() 使用默认模式和日期模式
public SimpleDateFormat(String pattern) 指定时间的格式创建简单日期格式化对象
  • 格式化和解析日期方法

    • public String format(Date date) 将日期格式化为日期 / 时间字符串

    • public String format(Object time) 将时间毫秒格式化为日期 / 时间字符串

    • public Date parse(String source) [pɑːz] 从给定的字符串开始解析文本生成日期

package ceshi;

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

public class SimpleDateFormatDemo {
    public static void main(String[] args) throws ParseException {
        //格式化 Date》String
         Date d = new Date();
//1、        SimpleDateFormat sdf = new SimpleDateFormat(); //无参构造
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss E a"); //2、带参构造
        String s = sdf.format(d);
        System.out.println(s); //1、21-7-11 上午10:13  2、2021年07月11日 10:16:00 星期日 上午

        //解析 String > date
        String s1 = "2020年1月1日 8:25:12";
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        Date d1 = sdf1.parse(s1); //parse报错了,选中按下Alt+enter,默认选第一个
        System.out.println(d1); //Wed Jan 01 08:25:12 CST 2020
    }
}

日期工具类

/**
 * 日期时间工具类
 *
 */
public class DateUtils {

    /**
     * 显示年月日时分秒,例如 2015-08-11 09:51:53.
     */
    public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 显示年月日时分,例如 2015-08-11 09:51.
     */
    public static final String NO_SECOND_DATETIME_PATTERN = "yyyy-MM-dd HH:mm";

    /**
     * 仅显示年月日,例如 2015-08-11.
     */
    public static final String DATE_PATTERN = "yyyy-MM-dd";

    /**
     * 仅显示时分秒,例如 09:51:53.
     */
    public static final String TIME_PATTERN = "HH:mm:ss";

    /**
     * 显示年月日时分秒(由/分割),例如 2015/08/11 09:51:53.
     */
    public static final String DATETIME_PATTERN_WITH_SLASH = "yyyy/MM/dd HH:mm:ss";

    /**
     * 显示年月日(由/分割),例如 2015/08/11.
     */
    public static final String DATE_PATTERN_WITH_SLASH = "yyyy/MM/dd";

    /**
     * 显示年月日时分秒(无符号),例如 20150811095153.
     */
    public static final String UNSIGNED_DATETIME_PATTERN = "yyyyMMddHHmmss";

    /**
     * 仅显示年月日(无符号),例如 20150811.
     */
    public static final String UNSIGNED_DATE_PATTERN = "yyyyMMdd";

    /**
     * 仅显示年(无符号),例如 2015.
     */
    private static final String YEAR_PATTERN = "yyyy";

    /**
     * 仅显示年月,例如 2015-08.
     */
    private static final String MONTH_PATTERN = "yyyy-MM";

    /**
     * 仅显示年月(无符号),例如 201508.
     */
    private static final String UNSIGNED_MONTH_PATTERN = "yyyyMM";

    /**
     * 一天的开始时间,仅显示时分秒
     */
    private static final String START_TIME = "00:00:00";

    /**
     * 一天的结束时间,仅显示时分秒
     */
    private static final String END_TIME = "23:59:59";

    /**
     * 每天的毫秒数.
     */
    public static final long MILLISECONDS_PER_DAY = 86400000L;

    /**
     * 每小时毫秒数.
     */
    public static final long MILLISECONDS_PER_HOUR = 3600000L;

    /**
     * 每分钟毫秒数.
     */
    public static final long MILLISECONDS_PER_MINU = 60000L;

    /**
     * 每秒的毫秒数.
     */
    public static final long MILLISECONDS_PER_SECONDS = 1000L;

    /**
     * 每分钟秒数.
     */
    public static final long SECONDS_PER_MINUTE = 60L;

    /**
     * 每小时秒数.
     */
    public static final long SECONDS_PER_HOUR = 3600L;

    /**
     * 每天秒数.
     */
    public static final long SECONDS_PER_DAY = 86400L;

    /**
     * 每周秒数.
     */
    public static final long SECONDS_PER_WEEK = 604800L;

    /**
     * 每个月秒数,默认每月30天.
     */
    public static final long SECONDS_PER_MONTH = 2592000L;

    /**
     * 每年秒数,默认每年365天.
     */
    public static final long SECONDS_PER_YEAR = 31536000L;

    /**
     * 每周的天数.
     */
    public static final long DAYS_PER_WEEK = 7L;

    /**
     * 春天;
     */
    public static final Integer SPRING = 1;

    /**
     * 夏天;
     */
    public static final Integer SUMMER = 2;

    /**
     * 秋天;
     */
    public static final Integer AUTUMN = 3;

    /**
     * 冬天;
     */
    public static final Integer WINTER = 4;

    /**
     * 星期日;
     */
    public static final String SUNDAY = "星期日";

    /**
     * 星期一;
     */
    public static final String MONDAY = "星期一";

    /**
     * 星期二;
     */
    public static final String TUESDAY = "星期二";

    /**
     * 星期三;
     */
    public static final String WEDNESDAY = "星期三";

    /**
     * 星期四;
     */
    public static final String THURSDAY = "星期四";

    /**
     * 星期五;
     */
    public static final String FRIDAY = "星期五";

    /**
     * 星期六;
     */
    public static final String SATURDAY = "星期六";

    /**
     * 获取当前日期和时间字符串.
     *
     * @return String 日期时间字符串,例如 2015-08-11 09:51:53
     */
    public static String getDateTimeStr() {
        return format(new Date(), DATETIME_PATTERN);
    }

    /**
     * 获取当前日期字符串.
     *
     * @return String 日期字符串,例如2015-08-11
     */
    public static String getDateStr() {
        return format(new Date(), DATE_PATTERN);
    }

    /**
     * 获取当前时间字符串.
     *
     * @return String 时间字符串,例如 09:51:53
     */
    public static String getTimeStr() {
        return format(new Date(), TIME_PATTERN);
    }

    /**
     * 获取当前年份字符串.
     *
     * @return String 当前年份字符串,例如 2015
     */
    public static String getYearStr() {
        return format(new Date(), YEAR_PATTERN);
    }

    /**
     * 获取当前月份字符串.
     *
     * @return String 当前月份字符串,例如 08
     */
    public static String getMonthStr() {
        return format(new Date(), "MM");
    }

    /**
     * 获取当前天数字符串.
     *
     * @return String 当前天数字符串,例如 11
     */
    public static String getDayStr() {
        return format(new Date(), "dd");
    }

    /**
     * 获取当前星期字符串.
     *
     * @return String 当前星期字符串,例如 星期二
     */
    public static String getDayOfWeekStr() {
        return format(new Date(), "E");
    }

    /**
     * 获取指定日期是星期几
     *
     * @param date 日期
     * @return String 星期几
     */
    public static String getDayOfWeekStr(Date date) {
        String[] weekOfDays = {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY};
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int num = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return weekOfDays[num];
    }

    /**
     * 获取当前小时字符串.
     *
     * @return String 当前小时字符串,例如09
     */
    public static String getHourStr() {
        return format(new Date(), "HH");
    }

    /**
     * 获取当前分钟字符串.
     *
     * @return String 当前分钟字符串,例如51
     */
    public static String getMinuteStr() {
        return format(new Date(), "mm");
    }

    /**
     * 获取当前秒钟字符串.
     *
     * @return String 当前秒钟字符串,例如53
     */
    public static String getSecondStr() {
        return format(new Date(), "ss");
    }

    /**
     * 获取日期时间字符串
     *
     * @param date    需要转化的日期时间
     * @param pattern 时间格式
     * @return String 日期时间字符串,例如 2015-08-11 09:51:53
     */
    public static String format(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 时间戳转换为日期时间字符串
     *
     * @param timestamp 时间戳
     * @param pattern   日期格式 例如DATETIME_PATTERN
     * @return String 日期时间字符串,例如 2015-08-11 09:51:53
     */
    public static String getDateTimeStr(long timestamp, String pattern) {
        return new SimpleDateFormat(pattern).format(timestamp);
    }

    /**
     * 日期字符串转换为日期(java.util.Date)
     *
     * @param dateStr 日期字符串
     * @param pattern 日期格式 例如DATETIME_PATTERN
     * @return Date 日期
     */
    public static Date parse(String dateStr, String pattern) {
        Date date = null;
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
        dateFormat.setLenient(false);
        try {
            date = dateFormat.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * 获取指定日期num年数之后的日期.
     *
     * @param num 间隔年数(负数表示之前)
     * @return Date 日期
     */
    public static Date addYears(Date date, int num) {
        return add(date, num, Calendar.YEAR);
    }

    /**
     * 获取当前日期指定年数之后的日期.
     *
     * @param num 间隔年数(负数表示之前)
     * @return Date 日期
     */
    public static Date addYears(int num) {
        return add(new Date(), num, Calendar.YEAR);
    }

    /**
     * 获取当前日期num月数之后的日期.
     *
     * @param num 间隔月数(负数表示之前)
     * @return Date 日期
     */
    public static Date addMonths(Date date, int num) {
        return add(date, num, Calendar.MONTH);
    }

    /**
     * 获取当前日期指定月数之后的日期.
     *
     * @param num 间隔月数(负数表示之前)
     * @return Date 日期
     */
    public static Date addMonths(int num) {
        return add(new Date(), num, Calendar.MONTH);
    }

    /**
     * 获取指定日期num周数之后的日期.
     *
     * @param date 日期
     * @param num  周数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addWeeks(Date date, int num) {
        return add(date, num, Calendar.WEEK_OF_YEAR);
    }

    /**
     * 获取当前日期指定周数之后的日期.
     *
     * @param num 周数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addWeeks(int num) {
        return add(new Date(), num, Calendar.WEEK_OF_YEAR);
    }

    /**
     * 获取指定日期num天数之后的日期.
     *
     * @param date 日期
     * @param num  天数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addDays(Date date, int num) {
        return add(date, num, Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取当前日期指定天数之后的日期.
     *
     * @param num 天数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addDays(int num) {
        return add(new Date(), num, Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取指定日期num小时之后的日期.
     *
     * @param date 日期
     * @param num  小时数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addHours(Date date, int num) {
        return add(date, num, Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取当前日期指定小时之后的日期.
     *
     * @param num 小时数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addHours(int num) {
        return add(new Date(), num, Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取指定日期num分钟之后的日期.
     *
     * @param date 日期
     * @param num  分钟数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addMinutes(Date date, int num) {
        return add(date, num, Calendar.MINUTE);
    }

    /**
     * 获取当前日期指定分钟之后的日期.
     *
     * @param num 分钟数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addMinutes(int num) {
        return add(new Date(), num, Calendar.MINUTE);
    }

    /**
     * 获取指定日期num秒钟之后的日期.
     *
     * @param date 日期
     * @param num  秒钟数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addSeconds(Date date, int num) {
        return add(date, num, Calendar.SECOND);
    }

    /**
     * 获取当前日期指定秒钟之后的日期.
     *
     * @param num 秒钟数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addSeconds(int num) {
        return add(new Date(), num, Calendar.SECOND);
    }

    /**
     * 获取指定日期num毫秒之后的日期.
     *
     * @param date 日期
     * @param num  毫秒数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addMilliSeconds(Date date, int num) {
        return add(date, num, Calendar.MILLISECOND);
    }

    /**
     * 获取当前日期指定毫秒之后的日期.
     *
     * @param num 毫秒数(负数表示之前)
     * @return Date 新的日期
     */
    public static Date addMilliSeconds(int num) {
        return add(new Date(), num, Calendar.MILLISECOND);
    }

    /**
     * 获取当前日期指定数量日期时间单位之后的日期.
     *
     * @param date 日期
     * @param num  数量
     * @param unit 日期时间单位
     * @return Date 新的日期
     */
    public static Date add(Date date, int num, int unit) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(unit, num);
        return calendar.getTime();
    }

    /**
     * 计算两个日期之间相隔年数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return int 相隔年数,向下取整
     */
    public static int getYearsBetween(Date startDate, Date endDate) {
        return getMonthsBetween(startDate, endDate) / 12;
    }

    /**
     * 计算两个日期之间相隔月数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return int 相隔月数,向下取整
     */
    public static int getMonthsBetween(Date startDate, Date endDate) {
        int months;
        int flag = 0;

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);

        if (endCalendar.equals(startCalendar)) {
            return 0;
        }

        if (startCalendar.after(endCalendar)) {
            Calendar temp = startCalendar;
            startCalendar = endCalendar;
            endCalendar = temp;
        }
        if (endCalendar.get(Calendar.DAY_OF_MONTH) < startCalendar.get(Calendar.DAY_OF_MONTH)) {
            flag = 1;
        }

        if (endCalendar.get(Calendar.YEAR) > startCalendar.get(Calendar.YEAR)) {
            months = ((endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR))
                    * 12 + endCalendar.get(Calendar.MONTH) - flag)
                    - startCalendar.get(Calendar.MONTH);
        } else {
            months = endCalendar.get(Calendar.MONTH)
                    - startCalendar.get(Calendar.MONTH) - flag;
        }

        return months;
    }

    /**
     * 计算两个日期之间相隔周数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return long 相隔周数,向下取整
     */
    public static long getWeeksBetween(Date startDate, Date endDate) {
        return getDaysBetween(startDate, endDate) / DAYS_PER_WEEK;
    }

    /**
     * 计算两个日期之间相隔天数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return long 相隔天数,向下取整
     */
    public static long getDaysBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_DAY;
    }

    /**
     * 计算两个日期之间相隔小时数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return long 相隔小时数,向下取整
     */
    public static long getHoursBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_HOUR;
    }

    /**
     * 计算两个日期之间相隔分钟数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return long 相隔分钟数,向下取整
     */
    public static long getMinutesBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_MINU;
    }

    /**
     * 计算两个日期之间相隔秒数.
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return long 相隔秒数,向下取整
     */
    public static long getSecondsBetween(Date startDate, Date endDate) {
        return (endDate.getTime() - startDate.getTime()) / MILLISECONDS_PER_SECONDS;
    }

    /**
     * 获取当前季度.
     * 注意:3~5月为春季 1,6~8月为夏季 2,9~11月为秋季 3,12~2月为冬季 4
     *
     * @return int 当前季度数
     */
    public static int getCurrentSeason() {
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH) + 1;
        int season = 0;
        if (month >= 3 && month <= 5) {
            season = SPRING;
        } else if (month >= 6 && month <= 8) {
            season = SUMMER;
        } else if (month >= 9 && month <= 11) {
            season = AUTUMN;
        } else if (month == 12 || month >= 1 && month <= 2) {
            season = WINTER;
        }
        return season;
    }

    /**
     * 获取当前日期与之前日期的时间间隔.
     *
     * @param date 之前的日期
     * @return String 例如 16分钟前、2小时前、3天前、4月前、5年前等
     */
    public static String getIntervalByDate(Date date) {
        long secondsBetween = getSecondsBetween(date, new Date());
        return getIntervalBySeconds(secondsBetween);
    }

    /**
     * 将以秒为单位的时间转换为其他单位.
     *
     * @param seconds 秒数
     * @return String 例如 16分钟前、2小时前、3天前、4月前、5年前等
     */
    public static String getIntervalBySeconds(long seconds) {
        StringBuffer buffer = new StringBuffer();
        if (seconds < SECONDS_PER_MINUTE) {
            buffer.append(seconds).append("秒前");
        } else if (seconds < SECONDS_PER_HOUR) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_MINUTE)).append("分钟前");
        } else if (seconds < SECONDS_PER_DAY) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_HOUR)).append("小时前");
        } else if (seconds < SECONDS_PER_WEEK) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_DAY)).append("天前");
        } else if (seconds < SECONDS_PER_MONTH) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_WEEK)).append("周前");
        } else if (seconds < SECONDS_PER_YEAR) {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_MONTH)).append("月前");
        } else {
            buffer.append((long) Math.floor(seconds / SECONDS_PER_YEAR)).append("年前");
        }
        return buffer.toString();
    }

    /**
     * 将 Date 日期转化为 Calendar 类型日期.
     *
     * @param date 指定日期
     * @return Calendar Calendar对象
     */
    public static Calendar getCalendar(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 得到UTC时间,类型为字符串,格式为"yyyy-MM-dd HH:mm"
     * 如果获取失败,返回null
     *
     * @return
     */
    public static String getUTCTimeStr() {
        StringBuffer UTCTimeBuffer = new StringBuffer();
        // 1、取得本地时间:
        Calendar cal = Calendar.getInstance();
        // 2、取得时间偏移量:
        int zoneOffset = cal.get(Calendar.ZONE_OFFSET);
        // 3、取得夏令时差:
        int dstOffset = cal.get(Calendar.DST_OFFSET);
        // 4、从本地时间里扣除这些差量,即可以取得UTC时间:
        cal.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        UTCTimeBuffer.append(year).append("-").append(month).append("-").append(day);
        UTCTimeBuffer.append(" ").append(hour).append(":").append(minute);
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(NO_SECOND_DATETIME_PATTERN);
            sdf.parse(UTCTimeBuffer.toString());
            return UTCTimeBuffer.toString();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将Timestamp转换为yyyy-MM-dd HH:mm:ss格式字符串
     *
     * @param timestamp
     * @return
     */
    public static String timestampToStr(Timestamp timestamp) {
        return timestamp.toString().substring(0, 19);
    }

    /**
     * 比较传进来的日期是否大于当前日期,如果传进来的日期大于当前日期则返回true,否则返回false
     *
     * @param dateStr 日期字符串
     * @param pattern 日期格式
     * @return boolean
     */
    public static boolean compareNowDate(String dateStr, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try {
            Date date = simpleDateFormat.parse(dateStr);
            return date.after(new Date());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 如果endDateStr>startDateStr,返回true,否则返回false
     *
     * @param startDateStr 开始日期字符串
     * @param endDateStr   结束日期字符串
     * @param pattern      日期格式
     * @return boolean
     */
    public static boolean compareDate(String startDateStr, String endDateStr, String pattern) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        try {
            Date startDate = simpleDateFormat.parse(startDateStr);
            Date endDate = simpleDateFormat.parse(endDateStr);
            return endDate.after(startDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 如果startDate>endDate,返回true,否则返回false
     *
     * @param startDate 开始日期字符串
     * @param endDate   结束日期字符串
     * @return boolean
     */
    public static boolean compareDate(Date startDate, Date endDate) {
        return endDate.after(startDate);
    }

    /**
     * 判断日期是否合法
     *
     * @param dateStr yyyy-MM-dd HH:mm:ss格式日期字符串
     * @return
     */
    public static boolean isValidDate(String dateStr) {
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期
        SimpleDateFormat format = new SimpleDateFormat(DATETIME_PATTERN);
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
            format.setLenient(false);
            format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }

    /**
     * 判断日期是否为月底最后一天
     *
     * @param date 日期
     * @return boolean true:是  false:否
     */
    public static boolean isLastDayofMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
        if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
            return true;
        }
        return false;
    }

    /**
     * 获取本年第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearStartTimeStr() {
        return getDateTimeStr(getStartDayOfYear(new Date()));
    }

    /**
     * 获取指定日期当年第一天的日期字符串
     *
     * @param date
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfYear(date));
    }

    /**
     * 获取本年最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearEndTimeStr() {
        return getDateTimeStr(getEndDayOfYear(new Date()));
    }

    /**
     * 获取指定日期当年最后一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getYearEndTimeStr(Date date) {
        return getDateTimeStr(getEndDayOfYear(date));
    }

    /**
     * 获取本月第一天的日期字符串
     * 格式:yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String getMonthStartTimeStr() {
        return getDateTimeStr(getStartDayOfMonth(new Date()));
    }

    /**
     * 获取指定日期当月第一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfMonth(date));
    }

    /**
     * 获取本月最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthEndTimeStr() {
        return getDateTimeStr(getEndDayOfMonth(new Date()));
    }

    /**
     * 获取指定日期当月最后一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthEndTimeStr(Date date) {
        return getDateTimeStr(getEndDayOfMonth(date));
    }

    /**
     * 获取本周第一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekStartTimeStr() {
        return getDateTimeStr(getStartDayOfWeek(new Date()));
    }

    /**
     * 获取指定日期当周第一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfWeek(date));
    }

    /**
     * 获取本周最后一天的日期字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekEndTimeStr() {
        return getDateTimeStr(getEndDayOfWeek(new Date()));
    }

    /**
     * 获取指定日期当周最后一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekEndTimeStr(Date date) {
        return getDateTimeStr(getEndDayOfWeek(date));
    }

    /**
     * 获取今天的开始时间字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayStartTimeStr() {
        return getDateTimeStr(getTodayStartTime(new Date()));
    }

    /**
     * 获取指定日期的开始时间字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayStartTimeStr(Date date) {
        return getDateTimeStr(getTodayStartTime(date));
    }

    /**
     * 获取今天的结束时间字符串
     *
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayEndTimeStr() {
        return getDateTimeStr(getTodayEndTime(new Date()));
    }

    /**
     * 获取指定日期的结束时间字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getTodayEndTimeStr(Date date) {
        return getDateTimeStr(getTodayEndTime(date));
    }

    /**
     * 获得指定日期所在日的开始时间字符串
     *
     * @param date 指定日期
     * @return String 例如:2020-12-06 00:00:00
     */
    public static String getDateStartTimeStr(Date date) {
        String result = format(date, DATE_PATTERN);
        return result.concat(" ").concat(START_TIME);
    }

    /**
     * 获得指定日期所在日的结束时间字符串
     *
     * @param date 指定日期
     * @return String 例如:2020-12-06 23:59:59
     */
    public static String getDateEndTimeStr(Date date) {
        String result = format(date, DATE_PATTERN);
        return result.concat(" ").concat(END_TIME);
    }

    /**
     * 根据日历返回日期时间字符串
     *
     * @param calendar 日历
     * @return String 日期时间字符串
     */
    public static String getDateTimeStr(Calendar calendar) {
        StringBuffer buf = new StringBuffer("");

        buf.append(calendar.get(Calendar.YEAR));
        buf.append("-");
        buf.append(calendar.get(Calendar.MONTH) + 1 > 9 ? calendar.get(Calendar.MONTH) + 1 + ""
                : "0" + (calendar.get(Calendar.MONTH) + 1));
        buf.append("-");
        buf.append(calendar.get(Calendar.DAY_OF_MONTH) > 9 ? calendar.get(Calendar.DAY_OF_MONTH) + ""
                : "0" + calendar.get(Calendar.DAY_OF_MONTH));
        buf.append(" ");
        buf.append(calendar.get(Calendar.HOUR_OF_DAY) > 9 ? calendar.get(Calendar.HOUR_OF_DAY) + ""
                : "0" + calendar.get(Calendar.HOUR_OF_DAY));
        buf.append(":");
        buf.append(calendar.get(Calendar.MINUTE) > 9 ? calendar.get(Calendar.MINUTE) + ""
                : "0" + calendar.get(Calendar.MINUTE));
        buf.append(":");
        buf.append(calendar.get(Calendar.SECOND) > 9 ? calendar.get(Calendar.SECOND) + ""
                : "0" + calendar.get(Calendar.SECOND));
        return buf.toString();
    }

    /**
     * 获取今年的第一天
     *
     * @return Calendar 日历
     */
    public static Calendar getStartDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }

    /**
     * 获取今年的最后一天
     *
     * @return Calendar 日历
     */
    public static Calendar getEndDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        int i = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
        calendar.set(Calendar.DAY_OF_YEAR, i);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar;
    }

    /**
     * 获取本月的第一天
     *
     * @return Calendar 日历
     */
    public static Calendar getStartDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }

    /**
     * 获取本月的最后一天
     *
     * @return Calendar 日历
     */
    public static Calendar getEndDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        int i = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.DAY_OF_MONTH, i);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar;
    }

    /**
     * 获取本周的第一天,一个星期的第一天是星期一,最后一天是星期天
     *
     * @return Calendar 日历
     */
    public static Calendar getStartDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }

    /**
     * 获取本周的最后一天,一个星期的第一天是星期一,最后一天是星期天
     *
     * @return Calendar 日历
     */
    public static Calendar getEndDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);

        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar;
    }

    /**
     * 获取今天开始时间
     *
     * @return
     */
    public static Calendar getTodayStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar;
    }

    /**
     * 获取今天结束时间
     *
     * @return
     */
    public static Calendar getTodayEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar;
    }

    /**
     * 根据日期范围,获取按周期划分的日期区间
     *
     * @param startDateStr 开始日期(格式:2020-11-29)
     * @param endDateStr   结束日期(格式:2020-12-02)
     * @param pattern      日期格式(支持:DATE_PATTERN,MONTH_PATTERN,YEAR_PATTERN)
     * @return List<String> 区间集合 例如:[2020-11-29,2020-11-30,2020-12-01,2020-12-02]
     */
    public static List<String> getDateStrList(String startDateStr, String endDateStr, String pattern) {
        Date start = parse(startDateStr, pattern);
        Date end = parse(endDateStr, pattern);
        return getDateStrList(start, end, pattern);
    }

    /**
     * 根据日期范围,获取按周期划分的日期区间
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param pattern   日期格式(支持:DATE_PATTERN,MONTH_PATTERN,YEAR_PATTERN)
     * @return List<String> 区间集合 例如:[2020-11-29,2020-11-30,2020-12-01,2020-12-02]
     */
    public static List<String> getDateStrList(Date startDate, Date endDate, String pattern) {
        List<String> result = new ArrayList<>();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        if (DATE_PATTERN.equals(pattern)) {
            while (startDate.before(endDate) || startDate.equals(endDate)) {
                result.add(new SimpleDateFormat(DATE_PATTERN).format(calendar.getTimeInMillis()));
                calendar.add(Calendar.DATE, 1);
                startDate = calendar.getTime();
            }
        } else if (MONTH_PATTERN.equals(pattern)) {
            while (startDate.before(endDate) || startDate.equals(endDate)) {
                result.add(new SimpleDateFormat(MONTH_PATTERN).format(calendar.getTimeInMillis()));
                calendar.add(Calendar.MONTH, 1);
                startDate = calendar.getTime();
            }
        } else if (YEAR_PATTERN.equals(pattern)) {
            while (startDate.before(endDate) || startDate.equals(endDate)) {
                result.add(new SimpleDateFormat(YEAR_PATTERN).format(calendar.getTimeInMillis()));
                calendar.add(Calendar.YEAR, 1);
                startDate = calendar.getTime();
            }
        }
        return result;
    }

    /**
     * 获取当前日期前后num天的集合
     *
     * @param num 天数(正数:之后;负数:之前)
     * @return List<String> 前/后日期的集合(包含指定日期)
     */
    public static List<String> getDateStrList(int num) {
        return getDateStrList(new Date(), num, DATE_PATTERN);
    }

    /**
     * 获取指定日期前后num天的集合
     *
     * @param date 指定日期
     * @param num  天数(正数:之后;负数:之前)
     * @return List<String> 前/后日期的集合(包含指定日期)
     */
    public static List<String> getDateStrList(Date date, int num) {
        return getDateStrList(date, num, DATE_PATTERN);
    }

    /**
     * 获取指定日期前后num天的集合,带日期格式参数
     *
     * @param date    指定日期
     * @param num     天数(正数:之后;负数:之前)
     * @param pattern 日期格式
     * @return List<String> 前/后日期的集合(包含指定日期)  例如:[2020-11-29,2020-11-30,2020-12-01]
     */
    public static List<String> getDateStrList(Date date, int num, String pattern) {
        List<String> result = new ArrayList<>();
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        boolean flag = false;
        if (num < 0) {
            num = Math.abs(num);
            flag = true;
        }
        for (int i = 0; i < num; i++) {
            result.add(new SimpleDateFormat(pattern).format(c.getTimeInMillis()));
            c.add(Calendar.DATE, flag ? -1 : 1);
        }
        if (flag) {
            Collections.reverse(result);
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println("=======================");
        System.out.println(getYearStr());
        System.out.println(getMonthStr());
        System.out.println(getDayStr());
        System.out.println(getHourStr());
        System.out.println(getMinuteStr());
        System.out.println(getSecondStr());

        System.out.println(getDateTimeStr());
        System.out.println(getDateStr());
        System.out.println(getTimeStr());
        System.out.println(getDayOfWeekStr());
        System.out.println(getDayOfWeekStr(parse("2020-12-05", DATE_PATTERN)));
        System.out.println(getDateTimeStr(System.currentTimeMillis(), DATETIME_PATTERN));

        System.out.println("=======================");
        System.out.println(parse("2020-12-31", DATE_PATTERN));

        System.out.println("=======================");
        System.out.println(addYears(1));
        System.out.println(addYears(new Date(), -1));
        System.out.println(addMonths(1));
        System.out.println(addMonths(new Date(), -1));
        System.out.println(addWeeks(1));
        System.out.println(addWeeks(new Date(), -1));
        System.out.println(addDays(1));
        System.out.println(addDays(new Date(), -1));
        System.out.println(addHours(1));
        System.out.println(addHours(new Date(), -1));
        System.out.println(addMinutes(1));
        System.out.println(addMinutes(new Date(), -1));
        System.out.println(addSeconds(1));
        System.out.println(addSeconds(new Date(), -1));
        System.out.println(addMilliSeconds(1));
        System.out.println(addMilliSeconds(new Date(), -1));

        System.out.println("=======================");
        System.out.println(getYearsBetween(parse("2020-01-30", DATE_PATTERN), parse("2021-01-29", DATE_PATTERN)));
        System.out.println(getMonthsBetween(parse("2020-01-30", DATE_PATTERN), parse("2021-01-29", DATE_PATTERN)));
        System.out.println(getWeeksBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getDaysBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getHoursBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getMinutesBetween(parse("2020-01-30", DATE_PATTERN), parse("2020-02-06", DATE_PATTERN)));
        System.out.println(getSecondsBetween(parse("2020-12-06 19:47:00", DATETIME_PATTERN), parse("2020-12-06 19:47:50", DATETIME_PATTERN)));

        System.out.println("=======================");
        System.out.println(getCurrentSeason());

        System.out.println("=======================");
        System.out.println(getIntervalByDate(parse("2020-12-06 19:30:00", DATETIME_PATTERN)));
        System.out.println(getIntervalBySeconds(604800L));

        System.out.println("=======================");
        System.out.println(getCalendar(new Date()));
        System.out.println(getUTCTimeStr());

        System.out.println("=======================");
        System.out.println(timestampToStr(new Timestamp(System.currentTimeMillis())));

        System.out.println("=======================");
        System.out.println(compareNowDate("2020-12-07", DATE_PATTERN));
        System.out.println(compareDate(parse("2020-12-05", DATE_PATTERN), new Date()));
        System.out.println(compareDate("2020-12-05", "2020-12-06", DATE_PATTERN));

        System.out.println("=======================");
        System.out.println(isValidDate("2020-02-29 23:59:00"));
        System.out.println(isLastDayofMonth(parse("2020-11-01 00:00:00", DATETIME_PATTERN)));

        System.out.println("=======================");
        System.out.println(getYearStartTimeStr());
        System.out.println(getYearStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getYearEndTimeStr());
        System.out.println(getYearEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getMonthStartTimeStr());
        System.out.println(getMonthStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getMonthEndTimeStr());
        System.out.println(getMonthEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getWeekStartTimeStr());
        System.out.println(getWeekStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getWeekEndTimeStr());
        System.out.println(getWeekEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getTodayStartTimeStr());
        System.out.println(getTodayStartTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getTodayEndTimeStr());
        System.out.println(getTodayEndTimeStr(parse("2019-12-06", DATE_PATTERN)));
        System.out.println(getDateStartTimeStr(parse("2020-11-01 00:00:00", DATETIME_PATTERN)));
        System.out.println(getDateEndTimeStr(parse("2020-11-01 00:00:00", DATETIME_PATTERN)));

        System.out.println("=======================");
        List<String> strList1 = getDateStrList(3);
        for (String s : strList1) {
            System.out.println(s);
        }

        System.out.println("=======================");
        List<String> dayList = getDateStrList(parse("2020-11-29", DATE_PATTERN), 3);
        for (String s : dayList) {
            System.out.println(s);
        }

        System.out.println("=======================");
        List<String> dateList = getDateStrList("2020-11-29", "2020-12-06", DATE_PATTERN);
        for (String s : dateList) {
            System.out.println(s);
        }

        System.out.println("=======================");
        List<String> strList = getDateStrList(parse("2020-11-29", DATE_PATTERN), parse("2020-12-06", DATE_PATTERN), DATE_PATTERN);
        for (String s : strList) {
            System.out.println(s);
        }
    }

}

1.7.3Calendar日历
  • Calendar 代表了系统此刻日期对应的日历对象

  • Calendar 是一个抽象类,不能直接创建对象

  • 常用方法

    • public static Calendar getInstance() 返回一个日历类的对象

    • public int get(int field) 返回给定日历的值

    • public void set(int field,int value) 修改日历的某个字段信息

    • public abstract void add(int field,int amount) 根据日历的规则,将指定的时间量添加或减去给定的日历字段

    • public final void set(int year,int month,int date) 设置当前日历年月日

package ceshi;

import java.util.Calendar;

public class CalendarDemo {
    public static void main(String[] args) {
        //1、获取Calendar对象
        Calendar c = Calendar.getInstance(); //多态形式
        //2、public int get (int field) 根据给的日历字段返回值
   /*     int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1; //从0开始所以加个1
        int date = c.get(Calendar.DATE);
        System.out.println(year+"年"+month+"月"+date+"日"); //2021年7月7日*/
        
        //3、public void set(int field,int value) 	修改日历的某个字段信息
        //c.set(Calendar.YEAR,2099);
        // System.out.println(rightNow.get(Calendar.YEAR)); //2099
        
        //4、public abstract void add(int field,int amount):根据日历的规则,将指定的时间量添加或减去给定的日历字段
        //需求1:三年前
/*        c.add(Calendar.YEAR,-3);
        int year = c.get(Calendar.YEAR);
        System.out.println(year); //2018,减了三年*/

        //需求2:十年后,五天前
        /*c.add(Calendar.YEAR,10);
        c.add(Calendar.DATE,-5);

        System.out.println();
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int date = c.get(Calendar.DATE);
        System.out.println(year+"年"+month+"月"+date+"日"); //2031年7月2日*/

        //5、public final void set(int year,int month,int date):设置当前日历年月日
        c.set(2022,1,1);
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int date = c.get(Calendar.DATE);
        System.out.println(year+"年"+month+"月"+date+"日"); //2022年2月1日
    }
}

2 String类

2.1 String概括

  • String 类 在java.lang包下,所以使用的时候不需要导包
  • java程序中所有的双引号字符串,都是String这个类的对象
  • 特点:字符串不可变,它们的值在创建后不可改变

2.2 String构造方法

  • String():初始化新创建的String对象,以使其表示空字符序列。

  • String(char[] value):通过当前参数中的字符数组来构造新的String。

  • String(byte[] bytes):通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。==双引号直接写的字符串在常量池当中,new的不在池当中。地址值不同.==

  • String(byte[] bytes, int offset, int length):通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。//把字节数组的一部分转换为字符串。

  • String(char[] value, int offset, int count):分配一个新的 String,它包含取自字符数组参数一个子数组的字符。//把字符数组的一部分转换为字符串。

    ==把字节/字符数组的一部分转换为字符串 offset:数组的开始索引 length:转换的字节个数 count:转换的字符个数==

判断功能的方法:

  • boolean equals(Objectan Object):将此字符串与指定对象进行比较。

  • boolean equalsIgnoreCase(String anotherString):将此字符串与指定对象进行比较,忽略大小写。

    ==Object是”对象”的意思,也是一种引用类型。作为参数类型,表示任意对象都可以传递到方法中。==

获取功能的方法:

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

转换功能的方法:

  • char[] toCharArray():将此字符串转换为新的字符数组。
  • byte[] getBytes():使用平台的默认字符集将该String编码转换为新的字节数组。
  • String replaceAll(String regex, String replacement):成功则返回替换的字符串,失败则返回原始字符串。其中regex为匹配此字符串的正则表达式;replacement为用来替换每个匹配项的字符串。
  • String replace(CharSequence target, CharSequencere placement):将与target匹配的字符串使用replacement字符串替换。
  • CharSequence是一个接口,也是一种引用类型。作为参数类型,可以把String对象传递到方法中。

分割功能的方法:

  • String[] split(String regex):将此字符串按照给定的regex(规则)拆分为字符串数组。
  • split方法的参数其实是一个“正则表达式”,如果按照英文句点“.”进行切分,必须写”.”。
    将基本数据型态转换成String的static方法:
  • String.valueOf(boolean b) : 将 boolean 变量 b 转换成字符串。
  • String.valueOf(char c) : 将 char 变量 c 转换成字符串。
  • String.valueOf(char[] data) : 将 char 数组 data 转换成字符串。
  • String.valueOf(char[] data, int offset, int count) : 将 char 数组 data 中 由 data[offset] 开始取 count 个元素 转换成字符串。
  • String.valueOf(double d) : 将 double 变量 d 转换成字符串。
  • String.valueOf(float f) : 将 float 变量 f 转换成字符串。
  • String.valueOf(int i) : 将 int 变量 i 转换成字符串。
  • String.valueOf(long l) : 将 long 变量 l 转换成字符串。
  • String.valueOf(Object obj) : 将 obj 对象转换成 字符串, 等于 obj.toString()。
    将String转换成基本数据型态的方法:
    详情参考parseXxx系列方法。

public class Demo{
    public static void main(String[] args){
        //1.public String() 	创建一个空字符串对象,不包含任何内容
        String s1 = new String();
        System.out.println("s1:"+s1); //s1:(无内容)

        //2.public String(chas[] chs) 	根据字符数组内容,来创建字符串对象
        char[] chs = {'a','b','c'};
        String s2 = new String(chs);
        System.out.println("s2:"+s2); //s2:abc

        //3.public String(byte[] bys) 	根据字节数组内容,来创建字符串对象
        byte[] bys = {97,98,99}; //对应计算机底层字符
        String s3 = new String(bys);
        System.out.println("s3:"+s3); //s3:abc

        //4.String s = “abc”; 	直接赋值的方法创建字符串对象,内容就是abc
        String s4 = "abc";
        System.out.println("s4:"+s4); //s4:abc
    }
}

2.3 String对象的区别

1.通过 new 创建字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同

2.以 “ ” 方式给出的字符串,只要字符串的序列相同(顺序和大小写),无论在程序中出现多少次,JVM都只会建立一个String对象,并在字符串池维护

内存

image-20240312182518251

2.5 String字符串比较

  • 使用双等号作比较
    • 基本类型:比较的是数据值是否相同
    • 引用类型:比较的是地址值是否相同
  • 字符串是对象,它比较内容是否相同,是通过一个方法来实现的,这个方法叫做: equals()
  • 范例:
public class Demo{

  public static void main(String[] args){

     //构造方法的方式得到对象

     char[] chs = {'a','b','c'};

      String s1 = new String(chs);

      String s2 = new String(chs);
      //直接赋值的方法得到对象

      String s3 = "abc";

     String s4 = "abc";

```
    System.out.println(s1.equals(s2)); //true
    System.out.println(s1.equals(s3)); //true
    System.out.println(s3.equals(s4)); //true
}
```

}

StringBuilder

  • java.lang.StringBuilder字符串缓冲区 可变字符序列

构造方法:

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

常用方法:

  • StringBuilder append(…):添加任意类型数据的字符串形式,并返回当前对象自身。

  • 连锁编程:bu.append(“abc”).append(1).append(true).append(8.8).append(‘中’);

  • String toString():将当前StringBuilder对象转换为String对象。

  • public int length() 返回长度(字符出现的个数)
  • StringBuilder和String可以相互转换:String->StringBuilder:StringBuilder//StringBuilder->String:toString

  1. JDK5.0后提供了StringBuilder,等价StringBuffer 。
  2. 区别:StringBuilder线程不安全,StringBuffer线程安全, StringBuilder类是单线程,不提供同步,理论上效率更高
public class Demo {
    public static void main(String[] args) {
        //创建空白可改变字符串对象
        StringBuilder sb = new StringBuilder();
        System.out.println("sb:"+sb); //sb:
        System.out.println("sb.length():"+sb.length()); //sb.length():0

        //根据字符串内容创建对象
        StringBuilder sb2 = new StringBuilder("hello");
        System.out.println("sb2:"+sb2); //sb2:hello
        System.out.println("sb2.length():"+sb2.length()); //5
    }
}
public class Demo {
    public static void main(String[] args) {
        //创建对象
        StringBuilder sb = new StringBuilder();

        //1.public StringBuilder append(任意类型) 	添加数据,并返回对象本身
//        StringBuilder sb2 = sb.append("java");
//        System.out.println("sb:"+sb); //sb:java,因为返回的是对象本身所以sb赋值了java
//        System.out.println("sb2:"+sb2); //sb2:java
//        System.out.println(sb==sb2); //true

//        sb.append("java");
//        sb.append("word");
//        sb.append(100);
//        System.out.println("sb:"+sb); //sb:javaword100

        //链式编程
        sb.append("java").append("word").append(100);
        System.out.println("sb:"+sb); //sb:javaword100

        //2.public StringBuilder reverse() 	返回相反的字符序列
        sb.reverse();
        System.out.println("sb:"+sb); //sb:001drowavaj
    }
}

3.3 StringBuilder 和 String 相互转换

  1. StringBuilder 转换为 String
public String toString()	通过toString()可以把StringBuilder 转换为 String
  1. String 转换为 StringBuilder
public StringBuilder(String s)	通过构造方法就可以把String 转换为 StringBuilder
  • 范例
public class Demo {
    public static void main(String[] args) {
        //1.StringBulider 转换为 String
        StringBuilder sb = new StringBuilder();
        sb.append("hello");

        //public String toString() 	通过toString()可以把StringBuilder 转换为 String
        String s = sb.toString();
        System.out.println("s:"+s); //s:hello
    
        //2.String 转换为 StringBulider
        String s1 = "hello";
        //public StringBuilder(String s) 	通过构造方法就可以把String 转换为 StringBuilder
        StringBuilder sb1 = new StringBuilder(s1);
        System.out.println("sb1:"+sb1); //sb1:hello
    }

}

4 集合结构体系

image-20240312193951531

4 集合基础

  • 集合提供一种存储空间可变的存储模型,存储的数据容量可以改变

  • ArrayLis<>:

    • 可调整大小的数组实现

    • <>:是一种特殊的数据类型,泛型

    • 可储存重复元素

  • 怎么使用呢

    • 在出现E的地方我们使用引用数据类型替换即可
    • 举例:ArrayList、ArrayList

4.1 集合与数组的区别

  • 共同点:都是存储数据的容器
  • 不同点:数组的容量是固定的,集合的容量是可变的

4.2 ArrayList 构造方法和添加方法

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> array = new ArrayList<>();
        System.out.println(array); //[]

        //添加到集合末尾
        array.add("hello");
        array.add("word");
        array.add("java");
        System.out.println(array); //[hello, word, java]
    
        //指定位置,添加元素
        array.add(1,"javase");
        System.out.println(array); //[hello, javase, word, java]
    
        array.add(4,"javaee");
        System.out.println(array); //[hello, javase, word, java, javaee]
    
        array.add(6,"javaweb"); 
        System.out.println(array); //IndexOutOfBoundsException,不能中间跳一个位置
    }

}

4.3 ArrayList 常用方法

方法名 说明

  • public boolean remove(Object o) 删除指定的元素,返回删除是否成功
  • public E remove(int index) 删除指定索引处的元素,返回被删除的元素
  • public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
  • public E get(int index) 返回指定索引处的元素
  • public int size() 返回集合中元素的个数

范例:

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> array = new ArrayList<>();
        System.out.println(array); //[]

        //添加到集合末尾
        array.add("hello");
        array.add("word");
        array.add("java");
        System.out.println(array); //[hello, word, java]
    
        //1,public boolean remove(Object o) 	删除指定的元素,返回删除是否成功

//        System.out.println(array.remove("hello")); //true; 集合变为[word, java]
//        System.out.println(array.remove("javase")); //false; 集合变为[hello, word, java]

        //2,public E remove(int index) 	删除指定索引处的元素,返回被删除的元素

//        System.out.println(array.remove(1)); //word,集合变为[hello, java]

        //3,public E set(int index,E element) 	修改指定索引处的元素,返回被修改的元素

//        System.out.println(array.set(1,"javase")); //word;集合变为[hello, javase, java]

        //4,public E get(int index) 	返回指定索引处的元素

//        System.out.println(array.get(0)); //hello
//        System.out.println(array.get(1)); //word
//        System.out.println(array.get(2)); //java

        //5,public int size() 	返回集合中元素的个数
        System.out.println(array.size()); //3
    }

}

4.4 案例

4.4.1 案例1:存储字符串并遍历

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        //创建集合对象
        ArrayList<String> array = new ArrayList<>();

        //加元素
        array.add("java");
        array.add("天下");
        array.add("第一");
    
        for(int i=0;i<array.size();i++) {
            String s = array.get(i);
            System.out.print(s+" "); //java 天下 第一
        }
    }

}

4.4.2 案例2:存储学生对象并遍历

Student类
package ceshi;

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;
    }

}

测试类

package ceshi;

import java.util.ArrayList;

public class ArrayListStudent {
    public static void main(String[] args) {
        //定义集合对象
        ArrayList<Student> array = new ArrayList<Student>();

        //创建学生对象
        Student stu1 = new Student("小白",20);
        Student stu2 = new Student("小明",21);
        Student stu3 = new Student("小黑",22);
    
        //添加学生对象到集合中
        array.add(stu1);
        array.add(stu2);
        array.add(stu3);
    
        //遍历集合
        for(int i=0;i<array.size();i++) {
            Student s = array.get(i);
            System.out.println(s.getName()+","+s.getAge()); //小白,20
                                                            //小明,21
                                                            //小黑,22
        }
    }

}

5 Collection集合

5.1 Collection集合概述

  • 是单列集合的顶层接口,它表示一组对象,这些对象也称Collection元素
  • JDK不提供此接口的直接实现,它提供更具体的子接口(Set 和 List)实现
package ceshi;

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo {
    public static void main(String[] args) {
        //创建Collection集合对象
        Collection<String> c = new ArrayList<String>();

```
    //添加元素
    c.add("hello");
    c.add("world");
    c.add("java");
    System.out.println(c); //[hello, world, java]
}
```

}

5.2 Collection集合常用方法(查看所有源码快捷键)

方法名	说明
public boolean add(E e)	把给定的元素添加到当前集合中
public boolean remove(E e)	把给定的对象在当前集合中删除
public void clear()	清空集合中所有的元素
public boolean contains(Object obj) [kənˈteɪnz] 包括	判断当前集合中是否存在指定的对象
public boolean isEmpty() [ˈenpti]	判断当前集合是否为空
public int size()	返回集合中元素的个数
public Object[] toArray( )	把集合中的元素,储存到数组中
  • 快捷键:Alt+7 打开源码中所有方法
package ceshi;

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo {
    public static void main(String[] args) {
        //创建Collection集合对象
        Collection<String> c = new ArrayList<String>();

        //1、public boolean add(E e) 	把给定的元素添加到当前集合中
        c.add("hello");
        c.add("hello");
        System.out.println(c); //[hello, hello] ;ArrayList可以存储重复元素
    
        //2、public boolean remove(E e) 	把给定的对象在当前集合中删除
        /*System.out.println(c.remove("hello")); //true
        System.out.println(c.remove("java")); //false
        System.out.println(c); //[hello]*/
    
        //3、public void clear() 	清空集合中所有的元素
        /*c.clear();
        System.out.println(c); //[]*/
    
        //4、public boolean contains(Object obj) 	判断当前集合中是否存在指定的对象
        /*System.out.println(c.contains("java")); //false
        System.out.println(c.contains("hello")); //true*/
    
        //5、public boolean isEmpty() 	判断当前集合是否为空

//        System.out.println(c.isEmpty()); //false

        //6、public int size() 	返回集合中元素的个数

//        System.out.println(c.size()); //2

        //7、public Object[] toArray( 	把集合中的元素,储存到数组中
        Object[] arr = c.toArray();
        for(int i= 0;i< arr.length;i++) {
            System.out.print(arr[i]+","); //hello,hello
        }
        
    }

}

5.3 Collection集合的遍历

Collection 集合遍历有三种方法:

  • 迭代器
  • foreach(增强for循环)
  • DK 1.8 开始的新技术 Lambda 表达式(了解)

5.3.1 Iterator[‘lɪtəreɪtə]迭代器遍历集合

  • lterator:迭代器,集合的专用遍历方式
  • Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
  • 迭代器是通过集合的**iterator()**方法得到的,所以我们说它是依赖于集合而存在的

Iterator中的常用方法

方法名	说明
E next()	获取迭代中的下一个元素
boolean hasNext()	如果迭代具有更多元素,则返回true
package ceshi;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class IteratorDemo {
    public static void main(String[] args) {
        Collection<String>  c = new ArrayList<String>();

        c.add("java");
        c.add("天下");
        c.add("无敌");
    
        //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator0方法得到
        Iterator<String> it = c.iterator(); //c.iterator();按下Ctrl+alt+v
        /*public Iterator<E> iterator() {
            return new ArrayList.Itr(); //返回的是实现类的对象
        }
    
        private class Itr implements Iterator<E> {...}
        */
    
        //E next()
        /*System.out.println(it.next()); //java
        System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next()); //NoSuchElementException:表示请求的元素不存在*/
    
        //boolean hasNext() 	如果迭代具有更多元素,则返回true
        /*if(it.hasNext()) {
            System.out.println(it.next()); //java
        }
        if(it.hasNext()) {
            System.out.println(it.next()); //天下
        }
        if(it.hasNext()) {
            System.out.println(it.next()); //无敌
        }
        if(it.hasNext()) {
            System.out.println(it.next()); //无输出
        } */
    
        //while循环改良
        while(it.hasNext()) {
            String s = it.next();
            System.out.println(s);  //java
                                    //天下
                                    //无敌
        }
    }

}

案例

package ceshi;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionDemo {
    public static void main(String[] args) {
        //2、创建Collection集合对象
        Collection<Student> c = new ArrayList<Student>();

        //3、创建学生对象
        Student s1 = new Student("y1", 10);
        Student s2 = new Student("y2", 20);
        Student s3 = new Student("y3", 30);
    
        //4、把学生添加到集合
        c.add(s1);
        c.add(s2);
        c.add(s3);
    
        //5、遍历集合
        Iterator<Student> it = c.iterator(); //必须集合添加完毕后创建迭代器对象
        while (it.hasNext()) {
            Student s = it.next();
            System.out.println(s.getName() + "," + s.getAge());
            /*
            y1,10
            y2,20
            y3,30
            */
        }
    }

}

5.4 Collections工具类

  • 包:java.util.Collections
  • Collections 并不属于集合,而是用来操作集合的工具类

常用方法(全是静态修饰,用类名调用)
方法名 说明

  • public static <T extends Comparable<?super T>> void sort(List list) 将指定的列表按升序排序
  • public static void reverse(List<?> list) 反转指定列表中元素顺序
  • public static void shuffle(List<?> list) 使用默认的随机源随机排序指定的列表
package ceshi;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MapDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();

```
    list.add(30);
    list.add(20);
    list.add(50);
    list.add(10);
    list.add(40);
    System.out.println(list); //[30, 20, 50, 10, 40]

    //1,public static <T extends Comparable<?super T>> void sort(List list) 	将指定的列表按升序排序
    /*Collections.sort(list);
    System.out.println(list); //[10, 20, 30, 40, 50]*/

    //2,public static void reverse(List<?> list) 	反转指定列表中元素顺序
    /*Collections.reverse(list);
    System.out.println(list); //[40, 10, 50, 20, 30]*/

    //3,public static void shuffle(List<?> list) 	使用默认的随机源随机排序指定的列表
    Collections.shuffle(list);
    System.out.println(list);
    //第一次运行[10, 40, 30, 50, 20]
    //第二次运行[10, 30, 20, 50, 40]
}
```

}

6 List集合

  • List系列集合:添加的元素是有序,可重复,有索引
  • ArrayList: 添加的元素是有序,可重复,有索引
  • LinkedList: 添加的元素是有序,可重复,有索引
  • Vector :是线程安全的,速度慢,开发中很少使用

6.1 List集合概述和特点

List集合概述

  1. 有序集合(也称为序列),用户可以精确控制列表中每个元索的插入位置。用户可以通过整数索引访问元素,并获取列表中的元素
  2. 与Set集合不同,List集合允许重复的元素

List集合特点

  1. 有序: 存储和取出的元素顺序一致
  2. 可重复: 存储的元素可以重复
package ceshi;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        //创建集合对象
        List<String> list = new ArrayList<>();

        //添加元素
        list.add("java");
        list.add("天下");
        list.add("无敌");
        list.add("java");
    
        System.out.println(list); //[java, 天下, 无敌, java]
    
        //迭代器遍历
        Iterator<String> it = list.iterator();
        while(it.hasNext()) {
            String s = it.next();
            System.out.println(s);
            /*java
            天下
            无敌
            java*/
        }
    }

}

6.2 List集合的特有方法

方法名 说明

  • public void add(int index,E element) 该集合中的指定位置上插入元素
  • public E remove(int index) 删除列表中指定位置的元素,返回被删除的元素
  • public E set(int index,E element) 修改指定索引的元素,返回被修改的元素
  • public E get(int index) 返回集合中指定位置的元素
package ceshi;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        //创建集合对象
        List<String> list = new ArrayList<>();

        //添加元素
        list.add("java");
        list.add("天下");
        list.add("无敌");
        list.add("java");
        System.out.println(list); //[java, 天下, 无敌, java]
    
        //1、public void add(int index,E element) 	该集合中的指定位置上插入元素
        list.add(1,"javase");
        System.out.println(list); //[java, javase, 天下, 无敌, java]
    
        //2、public E remove(int index) 	删除列表中指定位置的元素,返回被删除的元素
        System.out.println(list.remove(1)); //javase
        System.out.println(list); //[java, 天下, 无敌, java]
    
        //3、public E set(int index,E element) 	修改指定索引的元素,返回被修改的元素
        System.out.println(list.set(0,"java1")); //java
        System.out.println(list); //[java1, 天下, 无敌, java]
    
        //4、public E get(int index) 	返回集合中指定位置的元素
        System.out.println(list.get(2)); //无敌
    
        //for循环遍历
        for(int i=0;i< list.size();i++) {
            //5,public E get(int index)	返回集合中指定位置的元素
            String s = list.get(i);
            System.out.println(s);
            /*java1
            天下
            无敌
            java*/
        }
    }

}

案例

测试类

package ceshi;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        //2、创建集合对象
        List<Student> list = new ArrayList<Student>();
        //3、创建学生对象
        Student s1 = new Student("y1",10);
        Student s2 = new Student("y2",20);
        Student s3 = new Student("y3",30);
        //4、学生对象添加到集合
        list.add(s1);
        list.add(s2);
        list.add(s3);

```
    //5、遍历集合:迭代器方法
    Iterator<Student> it = list.iterator();
    while(it.hasNext()) {
        Student s = it.next();
        System.out.println(s.getName()+","+s.getAge());
        /*y1,10
        y2,20
        y3,30*/
    }

    //5、遍历集合:for循环
    for(int i=0;i<list.size();i++) {
        Student ss = list.get(i);
        System.out.println(ss.getName()+","+ss.getAge());
        /*y1,10
        y2,20
        y3,30*/
    }
}
```

}

6.3 ListIterator迭代器

Lstlterator:列表迭代器

  • 通过List集合的listterator()方法得到,所以说它是List集合特有的迭代器
  • 用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

常用方法

  • list.listIterator() 得到 listIterator 迭代器
  • E next() 返回迭代中的下一个元素
  • boolean hasNext() 如果迭代具有更多元素,则返回true
  • E previous() [ˈpriːviəs] 返回列表中的上一个元素
  • boolean hasPrevious() 如果此列表迭代器在相反方向遍历列表时具有更多元索,则返回true
  • void add(E e) 将指定的元索插入列表
package ceshi;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("java");
        list.add("python");
        list.add("scala");
    
        //通过list集合的listIterator() 方法得到迭代器
        /*ListIterator<String> lit = list.listIterator();
        while(lit.hasNext()) {
            String s = lit.next();
            System.out.println(s);
            *//*java
            python
            scala*//*
        }
        System.out.println("---------");
    
        //逆向遍历
        *//*E previous0 	返回列表中的上一个元素
        boolean hasPrevious() 	如果此列表迭代器在相反方向遍历列表时具有更多元索,则返回true*//*
        while(lit.hasPrevious()) {
            String s = lit.previous();
            System.out.println(s);
            *//*scala
            python
            java*//*
        }*/
    
        //获取列表迭代器
        ListIterator<String> lit = list.listIterator();
        while(lit.hasNext()) {
            String s = lit.next();
            if(s.equals("java")) {
                lit.add("world");
            }
        }
        System.out.println(list); //[java, world, python, scala]
    }

}

6.4 foreach(增强for循环)

增强for:简化数组和Collection集合的遍历

实现Iterable接口的类允许其对象成为增强型 for语句的目标
它是JDK5之后出现的,其内部原理是一个Iterator迭代器
格式

for(元素类型  变量名: 数组名或collection集合){ 
    
}
//范例
int[] arr = {1,2,3,4,5};
for(int i : arr) {
    System.out.println(i);
}

范例:

package ceshi;

import java.util.ArrayList;
import java.util.List;

public class ForDemo {
    public static void main(String[] args) {
        //int类型数组
        int[] arr = {1,2,3,4,5};
        for(int i : arr) {
            System.out.println(i);
            /*
            1
            2
            3
            4
            5*/
        }
        //String类型数组
        String[] strArray = {"java","python","scala"};
        for(String s : strArray) {
            System.out.println(s);
            /*java
            python
            scala*/
        }
    //集合
    List<String> list = new ArrayList<>();
    list.add("y1");
    list.add("y2");
    list.add("y3");
    for(String lt:list) {
        System.out.println(lt);
        /*y1
        y2
        y3*/
    }

    //判断:内部原理是一个Iterator迭代器
    for(String s:list) {
        if(s.equals("y1")) {
            list.add("y4"); //ConcurrentModificationException:并发修改异常
        }
    }
}

}

6.5 案例:List集合存储学生对象用三种方式遍历

测试类

package ceshi;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();

        Student s1 = new Student("y1",10);
        Student s2 = new Student("y2",20);
        Student s3 = new Student("y3",30);
    
        list.add(s1);
        list.add(s2);
        list.add(s3);
    
        //迭代器方式
        Iterator<Student> it = list.iterator();
        while(it.hasNext()) {
            Student s = it.next();
            System.out.println(s.getName()+","+s.getAge());
        }
        System.out.println("----------");


        //for带索引方式
        for(int i =0;i<list.size();i++) {
            Student s = list.get(i);
            System.out.println(s.getName()+","+s.getAge());
        }
        System.out.println("----------");
    
        //增强for
        for(Student s: list) {
            System.out.println(s.getName()+","+s.getAge());
        }
    }

}

6.6 List集合子类特点

  • ArrayList:底层数据结构数组实现,查询快,增删慢
  • LinkedList:底层数据结构链表实现,查询慢,增删快

范例:分别用ArrayList和LinkedList存储字符串并遍历

package ceshi;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {
        //1、创建ArrayList集合对象
        ArrayList<String> arraylist = new ArrayList<>();
        arraylist.add("java");
        arraylist.add("python");
        arraylist.add("scala");

        //增强for
        for(String s: arraylist) {
            System.out.println(s);
        }
        System.out.println("-------");
        //普通for循环
        for(int i=0;i< arraylist.size();i++) {
            String s = arraylist.get(i);
            System.out.println(s);
        }
        System.out.println("-------");
        //迭代器的方式
        Iterator<String> it = arraylist.iterator();
        while(it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-------");


        //2、创建LinkedList集合对象
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("a");
        linkedList.add("b");
        linkedList.add("c");
        //增强for
        for(String s:linkedList) {
            System.out.println(s);
        }
        System.out.println("-------");
        //普通for
        for(int i=0;i< linkedList.size();i++) {
            String s = linkedList.get(i);
            System.out.println(s);
        }
        System.out.println("-------");
        //迭代器
        Iterator<String> it1 = linkedList.iterator();
        while(it1.hasNext()) {
            String s = it1.next();
            System.out.println(s);
        }
    }

}

6.7 LinkedList集合特有方法

方法名 说明

  • public void addFirst(E,e) 在该列表开头插入指定的元素
  • public void addLast(E,e) 将指定的元索追加到此列表的末尾
  • public E getFirst() 返回此列表中的第一个元索
  • public E getLast() 返回此列表中的最后一个元素
  • public E removeFirst 从此列表中删除并返回第一个元素
  • public E removeLast 从此列表中删除并返回最后一个元素
package ceshi;

import java.util.LinkedList;

public class LinkedListDemo {
    public static void main(String[] args) {
        //创建集合对象
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("java");
        linkedList.add("python");
        linkedList.add("scala");
        System.out.println(linkedList); //[java, python, scala]

        //1、public void addFirst(E,e) 	在该列表开头插入指定的元素
        linkedList.addFirst("1");
        System.out.println(linkedList); //[1, java, python, scala]
    
        //2、public void addLast(E,e) 	将指定的元索追加到此列表的末尾
        linkedList.addLast("5");
        System.out.println(linkedList); //[1, java, python, scala, 5]
    
        //3、public E getFirst() 	返回此列表中的第一个元索
        System.out.println(linkedList.getFirst()); //1
    
        //4、public E getLast() 	返回此列表中的最后一个元素
        System.out.println(linkedList.getLast()); //5
    
        //5、public E removeFirst 	从此列表中删除并返回第一个元素
        System.out.println(linkedList.removeFirst()); //1
        System.out.println(linkedList);//[java, python, scala, 5]
    
        //6、public E removeLast 	从此列表中删除并返回最后一个元素
        System.out.println(linkedList.removeLast()); //5
        System.out.println(linkedList); //[java, python, scala]
    }

}

7 Set集合

7.1 Set集合的概述和特点

Set集合的特点

  • 不包含重复元素的集合
  • 没有带索引的方法,所以不能使用普通for循环
  • Set集合是接口通过实现类实例化(多态的形式)
  • HashSet:添加的元素是无序,不重复,无索引的
  • LinkedHashSet: 添加的元素是有序,不重复,无索引的
  • TreeSet: 不重复,无索引,按照大小默认升序排列
package ceshi;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        //创建Set集合对象
        Set<String> set = new HashSet<>();

        //添加元素
        set.add("java");
        set.add("python");
        set.add("scala");
        //不包含重复元素
        set.add("java");
    
        //两种遍历方式
        for(String s:set) {
            System.out.println(s);
            /*python
            java
            scala*/
        }
        System.out.println("--------");
    
        Iterator<String> it = set.iterator();
        while(it.hasNext()) {
            String s = it.next();
            System.out.println(s);
            /*python
            java
            scala*/
        }
    }

}

7.2 哈希值

  • 哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
  • Object类中有一个方法可以获取对象的哈希值
  • public int hashCode():返回对象的哈希码值

对象的哈希值特点

同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。而重写hashCode0方法,可以实现让不同对象的哈希值相同
package ceshi;

public class HashDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s1 = new Student("y1",10);

        //同一个对象多次调用hashCode()方法哈希值相同
        System.out.println(s1.hashCode()); //460141958
        System.out.println(s1.hashCode()); //460141958
        System.out.println("---------");
    
        //默认情况下,不同对象哈希值不同;重写hashCode()方法就可以使哈希值相同
        Student s2 = new Student("y2",20);
        System.out.println(s2.hashCode()); //1163157884
        System.out.println("---------");
    
        System.out.println("java".hashCode()); //3254818
        System.out.println("python".hashCode()); //-973197092
        System.out.println("scala".hashCode()); //109250886
        System.out.println("---------");
    
        System.out.println("无".hashCode()); //26080
        System.out.println("敌".hashCode()); //25932
    }

}

7.3 数据结构之哈希表

JDK8之前,底层采用数组+链表实现,可以说是一个元索为链表的数组(哈希表 = 数组 + 链表 + (哈希算法))
JDK8以后,在长度比较长的时候,底层实现了优化(哈希表 = 数组 + 链表 + 红黑树 + (哈希算法))
当链表长度超过 8 时,将链表转换为红黑树,这样大大减少了查找时间

7.4 HashSet集合概述和特点

HashSet集合特点

  • 底层数据结构是哈希表
  • 对集合的迭代顺序不作任何保证 ,也就是说不保证存储和取出的元素顺序一致
  • 没有带索引的方法,所以不能使用普通for循环遍历
  • 由于是Set集合, 所以是不包含重复元素的集合
package ceshi;

import java.util.HashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet<String> hs = new HashSet<>();

        hs.add("java");
        hs.add("python");
        hs.add("scala");
    
        hs.add("scala");
    
        for(String s:hs) {
            System.out.println(s);
            /*python
            java
            scala*/
        }
    
    }

}

7.5 HashSet集合保证元素唯一性源码分析(重点面试常考)

HashSet<String> hs = new HashSet<>();

​    hs.add("java");
​    hs.add("python");
​    hs.add("scala");

​    hs.add("scala");

​    for(String s:hs) {
​        System.out.println(s);
​        /*python
​        java
​        scala*/
​    }

public boolean add(E e) {
   return map.put(e, PRESENT)==null;
}

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true); //上个方法的返回的值是hash(key)的值
}
//hash值和元素的hashCode()方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
              boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //如果哈希表未初始化就对其初始化
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    //根据对象的哈希值计算对象的存储位置,
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null); //如果该位置没有元素,就存储新元素
    //有元素就走else
    else {
        Node<K,V> e; K k;
        //存入的元素和以前的元素比哈希值
        if (p.hash == hash && 
            //二、如果哈希值相同,调用对象的equals()比较内容是否相同
            //1、如果内容不同equals()返回false,就走一把元素添加到集合
            //2、如果内容相同返回true,说明元素重复,走e = p;不存储
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        //一、如果哈希值不同,就走else存储元素到集合
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null); //新元素添加到集合
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

HashSet集合存储元素:要保证元素唯一性需要重写hashCode()和equals()方法

案例

Student类

package ceshi;

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;
}

//重写快捷键:Fn+Alt+insert,选择equals() and hashCode()
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Student student = (Student) o;

    if (age != student.age) return false;
    return name != null ? name.equals(student.name) : student.name == null;
}

@Override
public int hashCode() {
    int result = name != null ? name.hashCode() : 0;
    result = 31 * result + age;
    return result;
}
```

}

测试类

package ceshi;

import java.util.HashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet<Student> hs = new HashSet<>();

        Student s1 = new Student("y1",10);
        Student s2 = new Student("y2",20);
        Student s3 = new Student("y3",30);
        Student s4 = new Student("y3",30);
    
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
    
        for(Student s: hs) {
            System.out.println(s.getName()+","+s.getAge());
            /*y3,30
            y2,20
            y1,10
            y3,30;s4内容和s3重复并存入了,需要重写hashCode()和equals()
            */
    
            //重写后
            /*
            y1,10
            y3,30
            y2,20*/
        }
    }

}

7.6 LinkedHashSet集合概述和特点

LinkedHashSet集合特点

  • 哈希表和链表实现的Set接口, 具有可预测的迭代次序
  • 由链表保证元素有序, 也就是说元索的存储和取出顺序是一致的
  • 由哈希表保证元索唯一, 也就是说没有重复的元素
package ceshi;

import java.util.LinkedHashSet;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();

        linkedHashSet.add("java");
        linkedHashSet.add("python");
        linkedHashSet.add("scala");
        linkedHashSet.add("scala");
    
        for(String s:linkedHashSet) {
            System.out.println(s);
            /*java
            python
            scala*/
        }
    }

}

7.7 TreeSet集合概述和特点

TreeSet集合特点

  1. 元素有序, 这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法

  2. TreeSet():根据其元素的自然排序进行排序

  3. TreeSet(Comparator comparator):根据指定的比较器进行排序

  4. 没有带索引的方法,所以不能使用普通for循环遍历

  5. 由于是Set集合,所以不包含重复元素的集合

package ceshi;

import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();

```
    //jdk5以后添加元素自动装箱int》integer
    ts.add(10);
    ts.add(40);
    ts.add(30);
    ts.add(50);
    ts.add(20);

    ts.add(30);

    for(Integer i:ts) {
        System.out.println(i);
        /*
        10
        20
        30
        40
        50*/
    }

}
```

}

7.8 自然排序Comarable的使用

存储学生对象并遍历,创建TreeSet集合使用无参构造方法

要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

结论:

用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
Student类

package ceshi;

public class Student implements Comparable<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 int compareTo(Student s) {

//        return 0; //返回0说明元素是重复的,只能存一个元素
//        return 1; //整数是升序排序
//        return -1; //负数是倒叙排序
        //按照年龄排序
        int num = this.age-s.age; //this是s2,s是s1
        //年龄相同时,按照名字字母排序
        int num2 = num==0 ? this.name.compareTo(s.name):num;
        return num2;
    }
}

测试

package ceshi;

import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();

        Student s1 = new Student("y1",10);
        Student s2 = new Student("y3",30);
        Student s3 = new Student("y2",20);
        Student s4 = new Student("y4",40);
    
        Student s5 = new Student("a4",40); //判断按字母排序
    
        Student s6 = new Student("y4",40); //判断会存储重复值吗
    
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
    
        for(Student s:ts) {
            System.out.println(s.getName()+","+s.getAge());
            /*y1,10
            y2,20
            y3,30
            a4,40
            y4,40*/
        }
    }

}

7.9 比较器排序Comparator[kəmˈpɜrətər]的使用

存储学生对象并遍历,创建TreeSet集合使用带参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元索进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,T o2)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

package ceshi;

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;
    }

}

测试

package ceshi;

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num==0? s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });

        Student s1 = new Student("y2",20);
        Student s2 = new Student("y1",10);
        Student s3 = new Student("y3",30);
        Student s4 = new Student("y4",40);
    
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
    
        for(Student s:ts) {
            System.out.println(s.getName()+","+s.getAge());
        }
    }

}

7.10 案例:不重复随机数

package ceshi;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

public class SetDemo {
    public static void main(String[] args) {
//        Set<Integer> set = new HashSet<>();
        Set<Integer> set = new TreeSet<>();

        Random r = new Random();
        //判断集合是否《10
        while(set.size()<10) {
            int number = r.nextInt(20)+1;
            set.add(number); //把随机数添加到集合
        }
    
        for (Integer i:set) {
            System.out.print(i+" "); //1(哈希set集合):16 17 2 20 8 9 10 11 14 15
            //2(TreeSet集合):1 3 4 5 6 7 8 10 16 19 
        }
    }

}

8 Map集合

  1. HashMap: 元素按照键是无序,不重复,无索引,值不做要求
  2. LinkedHashMap: 元素按照键是有序,不重复,无索引,值不做要求

8.1 Map集合概述和特点

  • Map集合是一种双列集合,每个元素包含两个值
  • Interface Map<K,V>; K:键的类型,V:值的类型
  • Map集合的每个元素的格式:key = value(键值对元素)
  • Map集合也被称为“键值对集合”
  • Map集合特点:
  • Map 集合的键是无序,不重复,无索引的
  • Map 集合后面重复的键对应的元素会覆盖前面的整个元素

创建Map集合对象:
多态的方式
具体的实现类HashMap

package ceshi;

import java.util.HashMap;
import java.util.Map;

public class MapDemo {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();

        map.put("y1","10");
        map.put("y2","20");
        map.put("y2","30"); //键和前面相同时,会替换前面的值
        map.put("y3","30");
        System.out.println(map); //{y1=10, y3=30, y2=30}
    }

}

8.2 Map集合的基本方法

方法名 说明

  1. public V put(K key, V value) 添加元素
  2. public V remove(Object key) 根据键删除键值对元素
  3. public void clear() 移除所有键值对元素
  4. public boolean containKey(Object key) [kənˈteɪn] 判断集合是否包含指定的键
  5. public boolean containValue(Object value) 判断集合是否包含指定的值
  6. public boolean isEmpty() 判断集合是否为空
  7. public int size() 集合的长度,也就是集合中键值对个数
package ceshi;

import java.util.HashMap;
import java.util.Map;

public class MapDemo {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();

        //1,public V put(K key, V value) 	添加元素
        map.put("y1","10");
        map.put("y2","20");
        map.put("y3","30");
        System.out.println(map); //{y1=10, y2=20, y3=30}
    
        //2,public V remove(Object key) 	根据键删除键值对元素
        /*map.remove("y2");
        System.out.println(map); //{y1=10, y3=30}
        */
    
        //3,public void clear() 	移除所有键值对元素
       /* map.clear();
        System.out.println(map); //{}
        */
    
        //4,public boolean containKey(Object key) [kənˈteɪn] 	判断集合是否包含指定的键
        /*System.out.println(map.containsKey("y2")); //ture
        System.out.println(map.containsKey("y4")); //false*/
    
        //5,public boolean containValue(Object value) 	判断集合是否包含指定的值

//        System.out.println(map.containsValue("10")); //true

        //6,public boolean isEmpty() 	判断集合是否为空

//        System.out.println(map.isEmpty()); //false

        //7,public int size() 	集合的长度,也就是集合中键值对个数
        System.out.println(map.size()); //3
    }

}

8.3 Map集合的获取方法(重点)

方法名 说明

  1. public V get(Object key) 根据键获取值
  2. public Set keySet() 获取所有键的集合,存储到Set集合中
  3. public Collection values() 获取所有值的集合,存储到Collection集合中
  4. public Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合(Set集合)
package ceshi;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();

        //public V put(K key, V value) 	添加元素
        map.put("y1","10");
        map.put("y2","20");
        map.put("y3","30");
        System.out.println(map); //{y1=10, y2=20, y3=30}
    
        //1,public V get(Object key) 	根据键获取值
        System.out.println(map.get("y1")); //10
        System.out.println(map.get("y4")); //null
    
        //2,public Set<K> keySet() 	获取所有键的集合,存储到Set集合中
        Set<String> key = map.keySet();
        for(String s:key) {
            System.out.println(s);
            /*y1
            y2
            y3*/
        }
    
        //3,public Collection<V> values() 	获取所有值的集合,存储到Collection集合中
        Collection<String> vlaues = map.values();
        for(String s:vlaues) {
            System.out.println(s);
            /*10
            20
            30*/
        }
    
        //4,public Set<Map.Entry<K,V>> entrySet() 	获取所有键值对对象的集合(Set集合)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for(Map.Entry<String, String> s:entries) {
            System.out.println(s);
            /*
            y1=10
            y2=20
            y3=30*/
        }
    }

}

8.4 Map集合的遍历

Map 集合遍历有三种方式:

  1. “键找值”的方式遍历
  2. “键值对”的方式遍历
  3. Lambda 表达式(JDK1.8开始之后的新技术)

8.4.1 “键找值”的方式遍历(常用)

  1. 1、获取所有键的集合:用keySet()方法实现
  2. 2、遍历键的集合,获取到每一个键:用增强for遍历实现
  3. 3、根据键去找值:在增强for中,用get(Object key)方法实现
package ceshi;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();

        //public V put(K key, V value) 	添加元素
        map.put("y1", "10");
        map.put("y2", "20");
        map.put("y3", "30");
        System.out.println(map); //{y1=10, y2=20, y3=30}
    
        //1、获取所有键的集合:用keySet()方法实现
        Set<String> keySet = map.keySet();
    
        //2、遍历键的集合,获取到每一个键:用增强for遍历实现
        for (String key : keySet) {
            //3、根据键去找值:在增强for中,用get(Object key)方法实现
            String value = map.get(key);
            System.out.println(key + "=" + value);
            /*
            y1=10
            y2=20
            y3=30*/
        }
    }

}

8.4.2 “键值对”的方式遍历

  1. 获取所有键值对对象的集合:Set<Map.Entry<K,V>> entrySet()
  2. 遍历键值对对象的集合,得到每一个键值对对象:用增强for实现,得到每一个Map.Entry
  3. 根据键值对对象获取键和值:在增强for中,用geKey()得到键;用getValue()得到值
package ceshi;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();

        //public V put(K key, V value) 	添加元素
        map.put("y1", "10");
        map.put("y2", "20");
        map.put("y3", "30");
        System.out.println(map); //{y1=10, y2=20, y3=30}
    
        //1、获取所有键值对对象的集合:Set<Map.Entry<K,V>> entrySet()
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
    
        //2、遍历键值对对象的集合,得到每一个键值对对象:用增强for实现,得到每一个Map.Entry
        for(Map.Entry<String, String> me:entrySet) {
            //3、根据键值对对象获取键和值:在增强for中,用geKey()得到键;用getValue()得到值
            String key = me.getKey();
            String value = me.getValue();
            System.out.println(key+"="+value);
            /*
            y1=10
            y2=20
            y3=30*/
        }
    }

}

8.4.3 Lambda [ˈlæmdə] 表达式方式遍历

package ceshi;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();

        //public V put(K key, V value) 	添加元素
        map.put("y1", "10");
        map.put("y2", "20");
        map.put("y3", "30");
        System.out.println(map); //{y1=10, y2=20, y3=30}
    
        map.forEach((k , v) -> {
            System.out.println(k+"="+v);
            /*
            y1=10
            y2=20
            y3=30*/
        });
    }

}

8.5 Map集合存储自定义类型

Map集合的键和值都可以存储自定义类型
如果希望Map集合认为自定义类型的键对象重复了,必须重写对象的hashCode()和equals()方法

8.6 LinkedHashMap(HashMap子类)

LinkedHashMap集合是有序不重复的键值对集合

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        Map<String , Integer> map = new LinkedHashMap<>();
        map.put("y1",10);
        map.put("y2",20);
        map.put("y3",30); 
        map.put("y3",100); //键不变,只是替换其值
        

        System.out.println(map);// {y1=10, y2=20, y3=100}   
    }

}

8.7 TreeMap

TreeMap 集合按照键是可排序不重复的键值对集合(默认升序)

8.8 案例

8.8.1 集合遍历

package ceshi;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args) {
        //创建HashMap集合对象
        HashMap<String,Student> hm =new HashMap<>();

        Student s1 = new Student("y1",10);
        Student s2 = new Student("y2",20);
        Student s3 = new Student("y3",30);
    
        hm.put("itheima1",s1);
        hm.put("itheima2",s2);
        hm.put("itheima3",s3);
    
        //键找值
        Set<String> keySet = hm.keySet();
        for(String key:keySet) {
            Student value = hm.get(key);
            System.out.println(key+","+value.getName()+","+value.getAge());
            /*itheima3,y3,30
            itheima1,y1,10
            itheima2,y2,20*/
        }
        System.out.println("---------");
    
        //键值对
        Set<Map.Entry<String, Student>> entrySet= hm.entrySet();
        for(Map.Entry<String, Student> me:entrySet) {
            String key = me.getKey();
            Student value = me.getValue();
            System.out.println(key+","+value.getName()+","+value.getAge());
            /*itheima3,y3,30
            itheima1,y1,10
            itheima2,y2,20*/
        }
    
    }

}

8.8.2 集合嵌套之 ArrayList嵌套HashMap

package ceshi;

import java.util.*;

public class MapDemo {
    public static void main(String[] args) {
        //1,创建ArrayList集合对象
        ArrayList<HashMap<String,String>> array = new ArrayList<>();

        //2,创建HashMap集合,并添加键值对元素
        HashMap<String,String> hm1 = new HashMap<>();
        hm1.put("y1","10");
        HashMap<String,String> hm2 = new HashMap<>();
        hm1.put("y2","20");
        HashMap<String,String> hm3 = new HashMap<>();
        hm1.put("y3","30");
    
        //3,把HashMap作为元素添加到Arraylist
        array.add(hm1);
        array.add(hm2);
        array.add(hm3);
    
        //遍历Arraylist
        for(HashMap<String,String> hm:array) {
            Set<String> keySet = hm.keySet();
            for(String key:keySet) {
                String value = hm.get(key);
                System.out.println(key+","+value);
                /*y1,10
                y2,20
                y3,30*/
            }
        }
    }

}

8.8.3 统计字符串中每个字符出现的次数

9 泛型

9.1 泛型的概述和好处

泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型

这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口

泛型定义格式:

<类型>:指定一种类型的格式。这里的类型可以看成是形参
<类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用时候给定的类型可以看成是实参, 并粗实参的类型只能是引用数据类型
JDK 1.7开始之后,泛型后面的申明可以省略不写

泛型和集合都只能支持引用数据类型,不支持基本数据类型

ArrayList<String> lists = new ArrayList<String>();
ArrayList<String> lists = new ArrayList<>(); 
// JDK 1.7开始之后,泛型后面的申明可以省略不写!!

泛型的好处:
把运行的错误提前到编译时期
避免了强制类型转换

Collection<String> c = new ArrayList<>();

        c.add("java");

//        c.add(100); //报错
//        c.add(false); //报错

9.2 泛型类

泛型类的概念:使用了泛型定义的类就是泛型类
常用泛型变量:T、E、V、K等形式的参数用来表示泛型
格式

修饰符 class 类名<泛型变量>{}
//范例
public class Generic<T> {}
  1. 泛型类的核心思想:是把出现泛型变量的地方全部替换成传输的真实数据类型

泛型类

package ceshi;

public class Generic<T> {
    private T t;

    public T getT() {
        return t;
    }
    public void setT(T t) {
        this.t = t;
    }

}

测试类

package ceshi;

public class GenericDemo {
    public static void main(String[] args) {
        Generic<String> g1 = new Generic<>();
        g1.setT("y1");

        Generic<Integer> g2 = new Generic<>();
        g2.setT(20);
    
        System.out.println(g1.getT()+","+g2.getT()); //y1,20
    
        Generic<Boolean> g3 = new Generic<>();
        g3.setT(true);
        System.out.println(g3.getT()); //true
    }

}

9.3 泛型方法

泛型方法定义格式

修饰符 <类型> 返回值类型 方法名(类型 变量名){}
//范例
public <T> void show(T t) {}

泛型方法定义

package ceshi;

/*public class Generic {
    public void show(String s) {
        System.out.println(s);
    }
    public void show(Integer i) {
        System.out.println(i);
    }
    public void show(Boolean b) {
        System.out.println(b);
    }
}*/

//泛型类改进
/*
public class Generic<T> {
    public void show(T t) {
        System.out.println(t);
    }
}
*/

//泛型方法
public class Generic {
    public <T> void show (T t) {
        System.out.println(t);
    }
}


测试类
package ceshi;

public class GenericDemo {
    public static void main(String[] args) {
        /*Generic g1 = new Generic();
        g1.show("y1");
        g1.show(30);
        g1.show(true);*/

        //泛型类
        /*Generic<String> g1 = new Generic<>();
        g1.show("y1");
    
        Generic<Integer> g2 = new Generic<>();
        g2.show(10);*/
    
        //泛型方法
        Generic g = new Generic();
        g.show("y1");
        g.show(10);
        g.show(true);
        g.show(13.14);
        /*y1
        10
        true
        13.14*/
    
    }

}

9.4 泛型接口

泛型接口定义格式

修饰符 interface 接口名称<类型> {}
//范例
public interface Generic<T> {}

泛型接口

package ceshi;

public interface Generic<T> {
    void show(T t);
}

实现类

package ceshi;

public class GenericImpl<T> implements Generic<T>{
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

测试类

package ceshi;

public class GenericDemo {
    public static void main(String[] args) {
        GenericImpl g1 = new GenericImpl();
        g1.show("y1");
        g1.show(10);
    }
}

9.5 类型通配符

为了表示各种泛型List的父类,可以使用类型通配符

类型通配符: <?>

List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限

类型通配符 上限: <? extends类型>
List<? extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限

类型通配符 下限::<?super 类型>
List<? super Number>:它表示的类型是Number或者其父类型

package ceshi;

import java.util.ArrayList;
import java.util.List;

public class GenericDemo {
    public static void main(String[] args) {
        //类型通配符: <?>
        List<?> list1 = new ArrayList<Number>();
        List<?> list2 = new ArrayList<String>();
        List<?> list3 = new ArrayList<Integer>();

        //类型通配符上限: <? extends类型>

//        List<? extends Number> list4 = new ArrayList<Object>(); 报错,超过上限
        List<? extends Number> list5 = new ArrayList<Number>();
        List<? extends Number> list6 = new ArrayList<Integer>();

        //类型通配符 下限::<?super 类型>
        List<? super Number> list7 = new ArrayList<Object>();
        List<? super Number> list8 = new ArrayList<Number>();

//        List<? super Number> list9 = new ArrayList<Integer>(); 报错
    }
}

9.6 可变参数

可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
格式:修饰符 返回值类型 方法名(数据类型…变量名){ }
范例:public static int sum(int…a) {}
注意事项
这里的变量其实是一个数组
一个方法有多个参数,包含可变参数,可变参数放最后
范例:public static int sum(int b,int…a) {}

package ceshi;

import java.util.ArrayList;
import java.util.List;

public class GenericDemo {
    public static void main(String[] args) {
        System.out.println(sum(10,20));
        System.out.println(sum(10,20,30));
        System.out.println(sum(10,20,30,40));
        /*
        30
        60
        100*/
    }
    public static int sum(int...a) { //a为数组
        int sum =0;
        for(int i:a) {
            sum +=i;
        }
        return sum;
    }
    //一个方法有多个参数,可变参数放最后
    /*public static int sum(int b,int...a) {
        return 0;
    }*/
}

9.7 可变参数的使用

1、Arrays工具类中有一个静态方法:

public static List asList(T… a):返回由指定数组支持的固定大小的列表
返回的集合不能做增删操作,可以做修改
2、List接口中有一个静态方法:(JDK9以上)

public static List of(E… elements):返回包含任意数元素的不可变列表
返回的集合不能做增删改操作
3、Set接口中有一个静态方法: (JDK9以上)

  • public static Set of(E…. elements):返回一个包含任意数量元素的不可变集合

在给元素的时候,不能给重复值
返回的集合不能做增删操作,没有修改方法

package ceshi;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class GenericDemo {
    public static void main(String[] args) {
        //1、public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
/*        List<String> list = Arrays.asList("java", "python", "scala");
        System.out.println(list); //[java, python, scala]

//        list.add("javase"); //UnsupportedOperationException;不支持请求操作
//        list.remove("java"); //UnsupportedOperationException;不支持请求操作
        list.set(0,"javase");
        System.out.println(list); //[javase, python, scala]*/

        //2、public static <E> List<E> of(E... elements):返回包含任意数元素的不可变列表
        List<String> list = List.of("java","python","scala","java")
        System.out.println(list); //[javase, python, scala,java]
        
        //list.add("javaee"); //UnsupportedOperationException
        //list.remove("java"); //UnsupportedOperationException
        //list.set(0,"javaee") //UnsupportedOperationException
        
        //3、public static <E> Set<E> of(E.... elements):返回-一个包含任意数量元素的不可变集合
        //Set<String> set = Arrays.of("java", "python", "scala","java"); //set集合不能重复
        Set<String> set = Arrays.of("java", "python", "scala");
        System.out.println(set); //[java, python, scala]
        
        //set.add("javaee"); //UnsupportedOperationException
        //set.remove("java"); //UnsupportedOperationException
    
    }

}****