Java常用类方法总结——System,Class,Random,Date,TimeUtil,TimeZone,Modifier,Parameter,Field,Method,Math,Locale

Class – 01 – System类常用方法解析

一、System 类定义

  • System 类为 Java 的系统类,位于 java.lang 包中
  • System 类的构造方法由 private 进行修饰,因此无法被实例化
  • System 类提供了标准输入流、标准输出流和错误输出流;此外还提供了访问操作系统环境变量、访问虚拟机环境变量、复制数组、垃圾回收等一系列实用方法

二、System 类常用方法

  • System.currentTimeMillis()
    • 获取当前时间戳,单位为毫秒

  • System.nanoTime()
    • 获取当前时间戳,单位为纳秒

  • System.lineSeparator()
    • 行分隔符,等同于 System.getProperty(“line.separator”)

  • System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

    • 拷贝数组,共五个参数

      参数 含义
      src 源数组
      srcPos 源数组开始截取的位置,从 0 开始
      dest 目标数组
      destPos 目标数组开始拷贝的位置,从 0 开始
      length 截取长度

  • System.gc()
    • 内部调用了 Runtime.getRuntime().gc() 方法,在回收垃圾对象前调用其 finalize() 方法,释放占用的内存资源
    • 告诉虚拟机准备进行 GC,但什么时候进行 GC,由虚拟机根据内存情况自主决定

  • System.runFinalization()
    • 内部调用了 Runtime.getRuntime().runFinalization() 方法
    • 虚拟机会尽最大努力去调用垃圾对象的 finalize() 方法,但不能保证其一定执行

  • System.load(String filepath)
    • 用于加载库文件,参数为库文件的绝对路径
    • 库文件 (动态链接库(ddl: Dynamic Link Library))
      • 是一个包含可由多个程序同时使用的代码和数据的库,实现了程序模块化

  • System.loadLibrary(String libname)
    • 用于加载库文件,参数为库文件名
    • 该库文件必须在 java.library.path 所指向的路径中

  • System.mapLibraryName(String libname)
    • 将库名称映射到特定的字符串中

  • System.exit(int status)
    • 终止目前正在运行的Java虚拟机
    • 参数为 0:正常终止
    • 参数非 0:异常终止

  • System.getenv()
    • 获取操作系统的环境变量 (即本地系统中的环境变量)
    • 参数为空:获取操作系统的所有环境变量
    • 参数不为空:获取操作系统的指定环境变量 (例如:参数为 “path”)

  • System.getProperties()
    • 获取虚拟机 (JVM) 的所有环境变量

  • System.getProperty(String key)

    • 获取虚拟机 (JVM) 的指定环境变量

      含义
      ava.version 获取 java 运行环境版本
      ava.vendor 获取 java 运行环境供应商
      ava.vendor.url 获取 java 运行环境供应商的URL
      ava.home 获取 java 安装路径
      ava.vm.specification.version 获取 java 虚拟机规范版本
      ava.vm.specification.vendor 获取 java 虚拟机规范供应商
      ava.vm.specification.name 获取 java 虚拟机规范名称
      ava.vm.version 获取 java 虚拟机实现版本
      ava.vm.vendor 获取 java 虚拟机实现供应商
      ava.vm.name 获取 java 虚拟机实现名称
      ava.specification.version 获取 java 运行时环境规范版本
      ava.specification.vender 获取 java 运行时环境规范供应商
      ava.specification.name 获取 java 运行时环境规范名称
      ava.class.version 获取 java 类格式版本号
      ava.class.path 获取 java 类路径
      ava.library.path 获取加载库时搜索的路径列表
      ava.io.tmpdir 获取默认的临时文件路径
      ava.ext.dirs 获取一个或多个扩展目录的路径
      s.name 获取操作系统的名称
      s.arch 获取操作系统的构架
      s.version 获取操作系统的版本
      ile.separator 获取文件分隔符
      ath.separator 获取路径分隔符
      ine.separator 获取行分隔符
      ser.name 获取用户名称
      ser.home 获取用户主目录
      ser.dir 获取用户当前工作目录

    • System.setProperties(Properties props)

      • 设置虚拟机 (JVM) 的环境变量 (批量)

        Properties prop = new Properties();
        prop.setProperty("aaa", "bbb");
        System.setProperties(prop);
        System.out.println(System.getProperty("aaa"));
        

  • System.setProperty(String key, String value)

    • 设置虚拟机 (JVM) 的环境变量 (单个)

      System.setProperty("aaa", "bbb");
      System.out.println(System.getProperty("aaa"));
      

  • System.clearProperty(String key)
    • 清除设置的虚拟机 (JVM) 的环境变量

  • System.console()

    • 从控制台设备读取字符信息,只能通过命令执行,在 IDE 中会报错

      Console console = System.console();
      System.out.println("please input your name:");
      String name = console.readLine();
      System.out.println("please input password:");
      char[] chars = console.readPassword();
      String password = String.valueOf(chars);
      System.out.println("your name:" + name + " your password:" + password);
      
    • 在cmd中先用 javac 命令进行编译,再用 java 命令进行运行

      这里写图片描述


  • System.setIn(InputStream in)
    • 重新分配标准输入流

  • System.setErr(PrintStream err)
    • 重新分配标准错误输出流

  • System.setOut(PrintStream out)
    • 重新分配标准输出流

  • System.err
    • 标准错误输出流,没有缓存,会立即输出

  • System.out
    • 标准输出流,有缓存,不一定会立即输出

  • System.identityHashCode(Object obj)

    • 根据对象内存地址来计算得到哈希值

    • 注意,这里需要与 hashCode() 方法进行区分

      • 当一个类没有重写 Object 类的 hashCode() 方法时,其 hashCode() 方法与 identityHashCode() 方法得到的值是一致的
      • 当一个类重写了 Object 类的 hashCode() 方法时,则其 hashCode() 方法得到的值由其实现逻辑决定,一般不再与 identityHashCode() 方法得到的值相同
      • 当 null 调用 hashCode() 方法时,会报空指针异常;当调用 identityHashCode(null) 方法时,会返回 0
      // 由于Apple并没有覆盖hashCode()方法,所以两方法得到的哈希值相等
      Apple apple = new Apple();
      System.out.println(apple.hashCode()); // 21685669
      System.out.println(System.identityHashCode(apple)); // 21685669
      1234
      
      // 由于String类覆盖了hashCode()方法,所以两方法得到的哈希值不相等
      String str = "123";
      System.out.println(str.hashCode()); // 48690
      System.out.println(System.identityHashCode(str)); // 21685669
      
      // 由于str1和str2两者的值相同,所以两者hashCode()方法得到的哈希值相等
      // 由于str1和str2两者指向的是常量池中的同一对象,所以两者identityHashCode()方法得到的哈希值相等
      String str1 = "123";
      String str2 = "123";
      System.out.println(str1.hashCode()); // 48690
      System.out.println(str2.hashCode()); // 48690
      System.out.println(System.identityHashCode(str1)); // 21685669
      System.out.println(System.identityHashCode(str2)); // 21685669
      
      // 由于str1和str2两者的值相同,所以两者hashCode()方法得到的哈希值相等
      // 由于str1和str2两者是不同的两个对象,所以两者identityHashCode()方法得到的哈希值不相等
      String str1 = new String("123");
      String str2 = new String("123");
      System.out.println(str1.hashCode()); // 48690
      System.out.println(str2.hashCode()); // 48690
      System.out.println(System.identityHashCode(str1)); // 21685669
      System.out.println(System.identityHashCode(str2)); // 2133927002
      

  • System.setSecurityManager(SecurityManager securityManager)
    • 设置安全管理器,接收一个 SecurityManager 类型的参数

  • System.getSecurityManager()
    • 获取安全管理器

  • System.inheritedChannel()
    • 返回从创建此 Java 虚拟机的实体继承得到的 channel


Class – 02 – Arrays类常用方法解析

一、Arrays 类的定义

  • Arrays类位于 java.util 包中,主要包含了操纵数组的各种方法

二、Arrays 类的常用方法

  • Arrays.asList(T… data)

    注意:该方法返回的是 Arrays 内部静态类 ArrayList,而不是我们平常使用的 ArrayList,,该静态类 ArrayList 没有覆盖父类的 add(), remove() 等方法,所以如果直接调用,会报 UnsupportedOperationException 异常

    • 将数组转换为集合,接收一个可变参

      List<Integer> list = Arrays.asList(1, 2, 3);
      list.forEach(System.out::println); // 1 2 3
      
      Integer[] data = {
              
              1, 2, 3};
      List<Integer> list = Arrays.asList(data);
      list.forEach(System.out::println); // 1 2 3
      
    • 如果将基本数据类型的数组作为参数传入,该方法会把整个数组当作一个元素

      int[] data = {
              
              1, 2, 3};
      List<int[]> list = Arrays.asList(data);
      System.out.println(list.size()); // 1
      System.out.println(Arrays.toString(list.get(0))); // [1, 2, 3]
      
  • Arrays.fill(Object[] array, Object obj)

    • 用指定元素填充整个数组 (会替换掉数组中原来的元素)

      Integer[] data = {
              
              1, 2, 3, 4};
      Arrays.fill(data, 9);
      System.out.println(Arrays.toString(data)); // [9, 9, 9, 9]
      
  • Arrays.fill(Object[] array, int fromIndex, int toIndex, Object obj)

    • 用指定元素填充数组,从起始位置到结束位置,取头不取尾 (会替换掉数组中原来的元素)

      Integer[] data = {
              
              1, 2, 3, 4};
      Arrays.fill(data, 0, 2, 9);
      System.out.println(Arrays.toString(data)); // [9, 9, 3, 4]
      

  • Arrays.sort(Object[] array)

    • 对数组元素进行排序 (串行排序)

      String[] data = {
              
              "1", "4", "3", "2"};
      System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
      Arrays.sort(data);
      System.out.println(Arrays.toString(data)); // [1, 2, 3, 4]
      
  • Arrays.sort(T[] array, Comparator comparator)

    • 使用自定义比较器,对数组元素进行排序 (串行排序)

      String[] data = {
              
              "1", "4", "3", "2"};
      System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
      // 实现降序排序,返回-1放左边,1放右边,0保持不变
      Arrays.sort(data, (str1, str2) -> {
              
              
          if (str1.compareTo(str2) > 0) {
              
              
      		return -1;
          } else {
              
              
              return 1;
          }
      });
      System.out.println(Arrays.toString(data)); // [4, 3, 2, 1]
      
  • Arrays.sort(Object[] array, int fromIndex, int toIndex)

    • 对指定范围内的数组元素进行排序 (串行排序)

      String[] data = {
              
              "1", "4", "3", "2"};
      System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
      // 对下标[0, 3)的元素进行排序,即对1,4,3进行排序,2保持不变
      Arrays.sort(data, 0, 3);
      System.out.println(Arrays.toString(data)); // [1, 3, 4, 2]
      
  • Arrays.sort(T[] array, int fromIndex, int toIndex, Comparator c)

    • 使用自定义比较器,对指定范围内的数组元素进行排序 (串行排序)

      String[] data = {
              
              "1", "4", "3", "2"};
      System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
      // 对下标[0, 3)的元素进行降序排序,即对1,4,3进行降序排序,2保持不变
      Arrays.sort(data, 0, 3, (str1, str2) -> {
              
              
      	if (str1.compareTo(str2) > 0) {
              
              
      		return -1;
      	} else {
              
              
      		return 1;
      	}
      });
      System.out.println(Arrays.toString(data)); // [4, 3, 1, 2]
      

  • Arrays.parallelSort(T[] array)

    注意:其余重载方法与 Arrays.sort() 相同

    • 对数组元素进行排序 (并行排序),当数据规模较大时,会有更好的性能

      String[] data = {
              
              "1", "4", "3", "2"};
      Arrays.parallelSort(data);
      System.out.println(Arrays.toString(data)); // [1, 2, 3, 4]
      

  • Arrays.binarySearch(Object[] array, Object key)

    注意:在调用该方法之前,必须先调用 Arrays.sort() 方法进行排序,如果数组没有排序,那么结果是不确定的,此外如果数组中包含多个指定元素,则无法保证将找到哪个元素

    • 使用二分法查找数组内指定元素的索引值

    • 这里需要先看下 binarySearch() 方法的源码,对了解该方法有很大的帮助

      image
      image

    • 从源码中可以看到

      • 当搜索元素是数组元素时,返回该元素的索引值
      • 当搜索元素不是数组元素时,返回 - (索引值 + 1)
    • 具体的用法可以看下面的例子

      • 搜索元素是数组元素,返回该元素索引值

        Integer[] data = {
                  
                  1, 3, 5, 7};
        Arrays.sort(data);
        System.out.println(Arrays.binarySearch(data, 1)); // 0
        
      • 搜索元素不是数组元素,且小于数组中的最小值

        Integer[] data = {
                  
                  1, 3, 5, 7};
        Arrays.sort(data);
        // 此时程序会把数组看作 {0, 1, 3, 5, 7},此时0的索引值为0,则搜索0时返回 -(0 + 1) = -1
        System.out.println(Arrays.binarySearch(data, 0)); // -1
        
      • 搜索元素不是数组元素,且大于数组中的最大值

        Integer[] data = {
                  
                  1, 3, 5, 7};
        Arrays.sort(data);
        // 此时程序会把数组看作 {1, 3, 5, 7, 9},此时9的索引值为4,则搜索8时返回 -(4 + 1) = -5
        System.out.println(Arrays.binarySearch(data, 9)); // -5
        
      • 搜索元素不是数组元素,但在数组范围内

        Integer[] data = {
                  
                  1, 3, 5, 7};
        Arrays.sort(data);
        // 此时程序会把数组看作 {1, 2, 3, 5, 7},此时2的索引值为1,则搜索2时返回 -(1 + 1) = -2
        System.out.println(Arrays.binarySearch(data, 2)); // -2
        
  • Arrays.binarySearch(Object[] array, int fromIndex, int toIndex, Object obj)

    • 使用二分法查找数组内指定范围内的指定元素的索引值

      Integer[] data = {
              
              1, 3, 5, 7};
      Arrays.sort(data);
      // {1, 3},3的索引值为1
      System.out.println(Arrays.binarySearch(data, 0, 2, 3)); // 1
      

  • Arrays.copyOf(T[] original, int newLength)

    • 拷贝数组,其内部调用了 System.arraycopy() 方法,从下标 0 开始,如果超过原数组长度,则会用 null 进行填充

      Integer[] data1 = {
              
              1, 2, 3, 4};
      Integer[] data2 = Arrays.copyOf(data1, 2);
      System.out.println(Arrays.toString(data2)); // [1, 2]
      Integer[] data3 = Arrays.copyOf(data1, 5);
      System.out.println(Arrays.toString(data3)); // [1, 2, 3, 4, null]
      

  • Arrays.copyOfRange(T[] original, int from, int to)

    • 拷贝数组,指定起始位置和结束位置,如果超过原数组长度,则会用 null 进行填充

      Integer[] data1 = {
              
              1, 2, 3, 4};
      Integer[] data2 = Arrays.copyOfRange(data1, 0, 2);
      System.out.println(Arrays.toString(data2)); // [1, 2]
      Integer[] data2 = Arrays.copyOfRange(data1, 0, 5);
      System.out.println(Arrays.toString(data2)); // [1, 2, 3, 4, null]
      

  • Arrays.equals(Object[] array1, Object[] array2)

    • 判断两个数组是否相等

      • 数组元素为基本数据类型时,依次比较值
      • 数组元素为引用数据类型时,依次调用元素的 equals() 方法进行比较
    • 即如果两个数组被认为是相等的,则两个数组中应包含相同顺序的相同元素

      Integer[] data1 = {
              
              1, 2, 3};
      Integer[] data2 = {
              
              1, 2, 3};
      System.out.println(Arrays.equals(data1, data2)); // true
      

  • Arrays.deepEquals(Object[] array1, Object[] array2)

    • 判断两个多维数组是否相等

      • 数组元素为基本数据类型时,依次比较值
      • 数组元素为引用数据类型时,依次调用元素的 equals() 方法进行比较
    • 即如果两个多维数组被认为是相等的,则两个多维数组中应包含相同顺序的相同元素

      Integer[][] data1 = {
              
              {
              
              1,2,3}, {
              
              1,2,3}};
      Integer[][] data2 = {
              
              {
              
              1,2,3}, {
              
              1,2,3}};
      System.out.println(Arrays.deepEquals(data1, data2)); // true
      

  • Arrays.hashCode(Object[] array)

    • 返回数组的哈希值

      Integer[] data = {
              
              1, 2, 3};
      System.out.println(Arrays.hashCode(data)); // 30817
      

  • Arrays.deepHashCode(Object[] array)

    • 返回多维数组的哈希值

      Integer[][] data = {
              
              {
              
              1, 2, 3}, {
              
              1, 2, 3}};
      System.out.println(Arrays.deepHashCode(data)); // 987105
      

  • Arrays.toString(Object[] array)

    • 返回数组元素的字符串形式

      Integer[] data = {
              
              1, 2, 3};
      System.out.println(Arrays.toString(data)); // [1, 2, 3]
      

  • Arrays.deepToString(Object[] array)

    • 返回多维数组元素的字符串形式

      Integer[][] data = {
              
              {
              
              1, 2, 3}, {
              
              1, 2, 3}};
      System.out.println(Arrays.deepToString(data)); // [[1, 2, 3], [1, 2, 3]]
      

  • Arrays.setAll(T[] array, IntFunction generator)

    • 让数组中的所有元素,串行地使用方法提供的生成器函数来计算每个元素 (一元操作)

      Integer[] data = {
              
              1, 2, 3, 4};
      // i为索引值
      Arrays.setAll(data, i -> data[i] * 2);
      System.out.println(Arrays.toString(data)); // [2, 4, 6, 8]
      

  • Arrays.parallelSetAll(T[] array, IntFunction generator)

    • 让数组中的所有元素,并行地使用方法提供的生成器函数来计算每个元素 (一元操作),当数据规模较大时,会有更好的性能

      Integer[] data = {
              
              1, 2, 3, 4};
      // i为索引值
      Arrays.parallelSetAll(data, i -> data[i] * 2);
      System.out.println(Arrays.toString(data)); // [2, 4, 6, 8]
      

  • Arrays.parallelPrefix(T[] array, BinaryOperator op)

    • 让数组中的所有元素,并行地使用方法提供的生成器函数来计算每个元素 (二元操作),当数据规模较大时,会有更好的性能

      Integer[] data = {
              
              2, 3, 4, 5};
      // 第一个元素2不变,将其与第二个元素3一起作为参数x, y传入,得到乘积6,作为数组新的第二个元素
      // 再将6和第三个元素4一起作为参数x, y传入,得到乘积24,作为数组新的第三个元素,以此类推
      Arrays.parallelPrefix(data, (x, y) -> x * y);
      System.out.println(Arrays.toString(data)); // [2, 6, 24, 120]
      
  • Arrays.parallelPrefix(T[] array, int fromIndex, int toIndex, BinaryOperator op

    • 让指定范围内的数组元素,并行地使用方法提供的生成器函数来计算每个元素 (二元操作),当数据规模较大时,会有更好的性能

      Integer[] data = {
              
              2, 3, 4, 5};
      // 第一个元素2不变,将其与第二个元素3一起作为参数x, y传入,得到乘积6,作为数组新的第二个元素
      // 再将6和第三个元素4一起作为参数x, y传入,得到乘积24,作为数组新的第三个元素,以此类推
      Arrays.parallelPrefix(data, 0, 3, (x, y) -> x * y);
      System.out.println(Arrays.toString(data)); // [2, 6, 24, 5]
      

  • Arrays.spliterator(T[] array)

    • 返回数组的分片迭代器,用于并行地遍历数组

      public class Students {
              
              
      
          private String name;
      
          private Integer age;
      
          public Students(String name, Integer age) {
              
              
              this.name = name;
              this.age = age;
          }
      	// 省略get、set方法
      }
      
      public static void main(String[] args) {
              
              
          Students[] data = new Students[5];
          IntStream.range(0,5).forEach(i -> data[i] = new Students("小明"+i+"号", i));
          // 返回分片迭代器
          Spliterator<Students> spliterator = Arrays.spliterator(data);
          spliterator.forEachRemaining(stu -> {
              
              
              System.out.println("学生姓名: " + stu.getName() + "  " + "学生年龄: " + stu.getAge());
              // 学生姓名: 小明0号  学生年龄: 0
      		// 学生姓名: 小明1号  学生年龄: 1
      		// 学生姓名: 小明2号  学生年龄: 2
      		// 学生姓名: 小明3号  学生年龄: 3
      		// 学生姓名: 小明4号  学生年龄: 4
          });
      }
      

  • Arrays.stream(T[] array)

    • 返回数组的流 (Stream),然后我们就可以使用 Stream 相关的许多方法了

      Integer[] data = {
              
              1, 2, 3, 4};
      List<Integer> list = Arrays.stream(data).collect(toList());
      System.out.println(list); // [1, 2, 3, 4]
      


Class – 03 – Random类常用方法详解析

一、Random 类的定义

  • Random 类位于 java.util 包中,主要用于生成伪随机数

  • Random 类将 种子数 作为随机算法的起源数字,计算生成伪随机数,其与生成的随机数字的区间无关

  • 创建 Random 实例时,若没有指定种子数,则会以当前时间作为种子数,来计算生成伪随机数

  • 拥有相同种子的 Random 实例,在相同次数下,生成的伪随机数完全相同

    Random random1 = new Random(10);
    Random random2 = new Random(10);
    System.out.println(random1.nextInt()); // -1157793070
    System.out.println(random2.nextInt()); // -1157793070
    

二、Random 类的常用方法

  • random.nextBoolean()

    • 用于从该随机数生成器的序列中得到下一个伪均匀分布的 boolean 值

      Random random = new Random();
      System.out.println(random.nextBoolean()); // true
      

  • random.nextBytes()

    • 用于生成随机 byte 值并将其放入用户提供的 byte 数组中

    • 生成的随机 byte 数等于 byte 数组的长度

      Random random = new Random();
      byte[] data = new byte[5];
      random.nextBytes(data);
      System.out.println(Arrays.toString(data)); // [29, 73, -58, -60, -101]
      

  • random.nextDouble()

    • 用于从该随机数生成器的序列中得到下一个伪均匀分布在 0.0 到 1.0 之间的 double 值,[0.0, 1.0)

      Random random = new Random();
      System.out.println(random.nextDouble()); // 0.07169148591770946
      

  • random.nextFloat()

    • 用于从该随机数生成器的序列中得到下一个伪均匀分布在 0.0 到 1.0 之间的 float 值,[0.0, 1.0)

      Random random = new Random();
      System.out.println(random.nextFloat()); // 0.35473615
      

  • random.nextInt()

    • 用于从该随机数生成器的序列中得到下一个伪均匀分布的 int 值

      Random random = new Random();
      System.out.println(random.nextInt()); // 1414623307
      
  • random.nextInt(int bound)

    • 用于从该随机数生成器的序列中得到下一个 0 到结束值之间伪均匀分布的 int 值,[0, 结束值)

      Random random = new Random();
      System.out.println(random.nextInt(10)); // 5
      

  • random.nextGaussian()

    • 用于从该随机数生成器的序列中得到下一个伪均匀分布的 double 值

    • 生成的 double 值符合均值为 0,方差为 1 的正态分布 (高斯分布)

      Random random = new Random();
      System.out.println(random.nextGaussian()); // 0.48039371890232446
      

  • random.setSeed(long seed)

    • 设置随机种子

      Random random = new Random();
      random.setSeed(10);
      

  • random.ints()

    • 用于得到一个有效无限的伪随机 int 值流

      Random random = new Random();
      IntStream ints = random.ints();
      ints.forEach(System.out::println);
      
  • random.ints(long streamSize)

    • 用于得到一个有限长度的伪随机 int 值流

      Random random = new Random();
      IntStream ints = random.ints(5);
      // -673281150 1081958281 -1955726845 133657651 -773829503
      ints.forEach(value -> System.out.print(value + " "));
      
  • random.ints(int randomNumberOrigin, int randomNumberBound)

    • 用于得到一个有效无限的范围在起始值到结束值之间的伪随机 int 值流,[起始值, 结束值)

      Random random = new Random();
      IntStream ints = random.ints(1, 5);
      ints.forEach(System.out::println);
      
  • random.ints(long streamSize, int randomNumberOrigin, int randomNumberBound)

    • 用于得到一个有限长度的范围在起始值到结束值之间的伪随机 int 值流,[起始值, 结束值)

      Random random = new Random();
      IntStream ints = random.ints(5, 1, 5);
      ints.forEach(value -> System.out.print(value + " ")); // 4 2 1 4 1
      

  • random.longs()

    • 用于得到一个有效无限的伪随机 long 值流

      Random random = new Random();
      LongStream longs = random.longs();
      longs.forEach(System.out::println);
      
  • random.longs(long streamSize)

    • 用于得到一个有限长度的伪随机 long 值流

      Random random = new Random();
      LongStream longs = random.longs(5);
      // -4253735830085011397 -81131290106869012 8737071083795249766 2189971428068815599 -6480079951366618766
      longs.forEach(value -> System.out.print(value + " "));
      
  • random.longs(int randomNumberOrigin, int randomNumberBound)

    • 用于得到一个有效无限的范围在起始值到结束值之间的伪随机 long 值流,[起始值, 结束值)

      Random random = new Random();
      LongStream longs = random.longs(1, 5);
      longs.forEach(System.out::println);
      
  • random.longs(long streamSize, int randomNumberOrigin, int randomNumberBound)

    • 用于得到一个有限长度的范围在起始值到结束值之间的伪随机 long 值流,[起始值, 结束值)

      Random random = new Random();
      LongStream longs = random.longs(5, 1, 5);
      longs.forEach(value -> System.out.print(value + " ")); // 1 1 3 1 4 
      

  • random.doubles()

    • 用于得到一个有效无限的伪随机 double 值流

      Random random = new Random();
      DoubleStream doubles = random.doubles();
      doubles.forEach(System.out::println);
      
  • random.doubles(long streamSize)

    • 用于得到一个有限长度的伪随机 double 值流

      Random random = new Random();
      DoubleStream doubles = random.doubles(5);
      // 0.8920930039742779 0.17890662178269223 0.4357034705163628 0.923875379269902 0.935716401915742 
      doubles.forEach(value -> System.out.print(value + " "));
      
  • random.doubles(int randomNumberOrigin, int randomNumberBound)

    • 用于得到一个有效无限的范围在起始值到结束值之间的伪随机 double 值流,[起始值, 结束值)

      Random random = new Random();
      DoubleStream doubles = random.doubles(1, 5);
      doubles.forEach(System.out::println);
      
  • random.doubles(long streamSize, int randomNumberOrigin, int randomNumberBound)

    • 用于得到一个有限长度的范围在起始值到结束值之间的伪随机 double 值流,[起始值, 结束值)

      Random random = new Random();
      DoubleStream doubles = random.doubles(5, 1, 5);
      // 1.3129824412519966 3.844270928219007 2.2465511715951845 3.2396684494598116 3.5435450122721313 
      doubles.forEach(value -> System.out.print(value + " "));
      


Class – 04 – Date类常用方法解析

一、Date 类的定义

  • Date 类位于 java.util 包中,主要用来封装当前的日期和时间

  • Date 类提供两个构造函数来实例化 Date 对象 (其余构造方法已经过时了)

    • Date()
      • 使用当前日期和时间来初始化对象
    • Date(long milliseconds)
      • 接收一个 long 类型的参数,该参数是从 1970-01-01 00:00:00.000 到当前时间的毫秒数
    Date date = new Date();
    // 打印Date对象
    // Sat:表示周六
    // Aug:表示八月
    // GMT:格林威治标准时间
    // GMT+08:00:东八区即标准北京时间
    System.out.println(date); // Sat Aug 11 17:03:32 GMT+08:00 2018
    

二、Date 类的常用方法

  • getTime()

    • 获取时间毫秒数

      Date date = new Date();
      System.out.println(date.getTime()); // 1533978518866
      

  • setTime(long milliseconds)

    • 设置时间毫秒数

      Date date = new Date();
      date.setTime(100);
      System.out.println(date); // Thu Jan 01 08:00:00 GMT+08:00 1970
      

  • equals(Object obj)

    • 用于比较两个时间是否相等

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-10 08:08:123");
      Date date2 = sdf.parse("2018-08-10 08:08:123");
      System.out.println(date1.equals(date2)); // true
      
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-10 08:08:123");
      Date date2 = sdf.parse("2018-08-11 08:08:123");
      System.out.println(date1.equals(date2)); // false
      

  • after(Date when)

    • 校验目标日期是否在参数日期之后

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-10 08:08:123");
      Date date2 = sdf.parse("2018-08-09 08:08:123");
      System.out.println(date1.after(date2)); // true
      

  • before(Date when)

    • 校验目标日期是否在参数日期之前

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-10 08:08:123");
      Date date2 = sdf.parse("2018-08-09 08:08:123");
      System.out.println(date1.before(date2)); // false
      

  • compareTo(Date anotherDate)

    • 对两个Date对象进行比较

    • 如果目标日期等于参数日期,则返回 0

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-10 08:08:123");
      Date date2 = sdf.parse("2018-08-10 08:08:123");
      System.out.println(date1.compareTo(date2)); // 0
      
    • 如果目标日期在参数日期之后,则返回 1

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-11 08:08:123");
      Date date2 = sdf.parse("2018-08-10 08:08:123");
      System.out.println(date1.compareTo(date2)); // 1
      
    • 如果目标日期在参数日期之前,则返回 -1

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      Date date1 = sdf.parse("2018-08-09 08:08:123");
      Date date2 = sdf.parse("2018-08-10 08:08:123");
      System.out.println(date1.compareTo(date2)); // -1
      

  • toInstant()

    • Instant 输出的是标准时间,即格林威治标准时间,而 Date 输出的是北京时间,两者相差 8 个小时

    • 返回一条时间线上与此日期相同的一个点

      Date date = new Date();
      // Instant:java8的新特性,表示时间线中的一个特定时刻
      Instant instant = date.toInstant();
      // 标准时间,精确到纳秒 
      System.out.println(instant); // 2018-08-11T03:11:59.110Z
      // 将标准时间修改为北京时间,即+8小时
      System.out.println(instant.plusMillis(TimeUnit.HOURS.toMillis(8))); // 2018-08-11T11:11:59.110Z
      // 北京时间,精确到毫秒
      System.out.println(date); // Sat Aug 11 11:11:59 GMT+08:00 2018
      


Class – 05 – TimeUnit类常用方法解析

一、TimeUnit类的定义

  • TimeUnit 类位于 java.util.concurrent 包中,是一个枚举类,主要用于时间颗粒度的转换与线程的延时

  • TimeUnit 包含以下七个枚举常量

    常量名 含义
    NANOSECONDS 纳秒,等于 $1 * 10^{-9}s$
    MICROSECONDS 微秒,等于 $1 * 10^{-6}s$
    MILLISECONDS 毫秒,等于 $1 * 10^{-3}s$
    SECONDS
    MINUTES
    HOURS
    DAYS

二、TimeUnit 类常用方法

  • toDays(long duration)

    • 将指定颗粒度的时间转换为天数

      // 将1天转换为天数
      System.out.println(TimeUnit.DAYS.toDays(1)); // 1
      

  • toHours(long duration)

    • 将指定颗粒度的时间转换为小时数

      // 将1天转换为小时数
      System.out.println(TimeUnit.DAYS.toHours(1)); // 24
      

  • toMinutes(long duration)

    • 将指定颗粒度的时间转换为分数

      // 将1天转换为分数
      System.out.println(TimeUnit.DAYS.toMinutes(1)); // 1440
      

  • toSeconds(long duration)

    • 将指定颗粒度的时间转换为秒数

      // 将1天转换为秒数
      System.out.println(TimeUnit.DAYS.toSeconds(1)); // 86400
      

  • toMillis(long duration)

    • 将指定颗粒度的时间转换为毫秒数

      // 将1天转换为毫秒数
      System.out.println(TimeUnit.DAYS.toMillis(1)); // 86400000
      

  • toMicros(long duration)

    • 将指定颗粒度的时间转换为微秒数

      // 将1天转换为微秒数
      System.out.println(TimeUnit.DAYS.toMicros(1)); // 86400000000
      

  • toNanos(long duration)

    • 将指定颗粒度的时间转换为纳秒数

      // 将1天转换为纳秒数
      System.out.println(TimeUnit.DAYS.toNanos(1)); // 86400000000000
      

  • convert(long sourceDuration, TimeUnit sourceUnit)

    • 将参数颗粒度时间转换为指定颗粒度时间

      // 将48小时转换为天数
      System.out.println(TimeUnit.DAYS.convert(48, TimeUnit.HOURS)); // 2
      

  • compareTo(E o)

    • 比较两个枚举常量的索引值大小,返回一个差值

      image

      // [NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS]
      System.out.println(Arrays.toString(TimeUnit.values())); 
      // DAYS的索引值为6
      System.out.println(TimeUnit.DAYS.ordinal()); //6
      // MINUTES的索引值为4
      System.out.println(TimeUnit.MINUTES.ordinal()); // 4
      System.out.println(TimeUnit.DAYS.compareTo(TimeUnit.MINUTES)); // 2
      System.out.println(TimeUnit.MINUTES.compareTo(TimeUnit.DAYS)); // -2
      

  • sleep(long timeout)

    • 提供了可读性更好的线程休眠操作,使线程休眠指定时间颗粒度的时间,通常用来替换 Thread.sleep()

    • 当使用 Thread.sleep() 方法时,由于输入的参数为毫秒数,所以很难直观地看出当前线程具体休眠了多长时间

      Thread.sleep(2000);
      // 休眠2秒钟 (时间颗粒度为秒)
      TimeUnit.SECONDS.sleep(2);
      // 休眠2分钟 (时间颗粒度为分)
      TimeUnit.MINUTES.sleep(2)
      

  • timedJoin(Thread thread, long timeout)

    • 对指定线程,休眠指定时间颗粒度的时间

      // 对当前线程休眠2秒
      TimeUnit.SECONDS.timedJoin(Thread.currentThread(), 2);
      

  • timedWait(Object obj, long timeout)

    • 对指定对象,休眠指定时间颗粒度的时间

      public class Test {
              
              
      	// 此处需要使用synchronized关键字将方法锁住
          public synchronized void show() throws InterruptedException {
              
              
              TimeUnit.SECONDS.timedWait(this, 2);
              System.out.println("HelloWorld");
          }
          
      	public static void main(String[] args) throws InterruptedException {
              
              
              Test test = new Test();
              // 2秒之后执行
              test.show();
          }
      }
      


Class – 06 – TimeZone类常用方法详解析

一、TimeZone 类的定义

  • TimeZone 类位于 java.util 包中,是一个抽象类,主要包含了对于时区的各种操作,可以进行计算时间偏移量或夏令时等操作

二、TimeZone 类常用方法

  • getAvailableIDs()

    • 获取Java支持的所有时区 ID

      System.out.println(Arrays.toString(TimeZone.getAvailableIDs()));
      
      // Asia/Shanghai, Asia/Chongqing, Asia/Hong_Kong, Asia/Macao, ...
      
  • getAvailableIDs(int rawOffset)

    • 根据 时间偏移量 来获取时区 ID

      // 东八区时间,与标准时间相差8小时
      System.out.println(Arrays.toString(TimeZone.getAvailableIDs(8*60*60*1000)));
      
      // [Asia/Brunei, Asia/Choibalsan, Asia/Chongqing, Asia/Chungking, Asia/Harbin,
      // Asia/Hong_Kong, Asia/Irkutsk, Asia/Kuala_Lumpur, Asia/Kuching, Asia/Macao, 
      // Asia/Macau, Asia/Makassar, Asia/Manila, Asia/Shanghai, Asia/Singapore, 
      // Asia/Taipei, Asia/Ujung_Pandang, Asia/Ulaanbaatar, Asia/Ulan_Bator, 
      // Australia/Perth, Australia/West, CTT, Etc/GMT-8, Hongkong, PRC, Singapore]
      

  • getDefault()

    • 获取当前系统的默认时区,中国默认为东八区

      System.out.println(TimeZone.getDefault()); 
      
      // sun.util.calendar.ZoneInfo[id="GMT+08:00",offset=28800000,
      // dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
      

  • setDefault(TimeZone zone)

    • 设置当前系统的默认时区

      TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
      System.out.println(TimeZone.getDefault());
      
      // sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,
      // dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
      

  • getTimeZone(String ID)

    • 根据时区 ID 来获取其对应的时区

      System.out.println(TimeZone.getTimeZone("GMT+08:00"));
      
      // sun.util.calendar.ZoneInfo[id="GMT+08:00",offset=28800000,
      // dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
      
  • getTimeZone(ZoneId zoneId)

    • 根据 ZoneId 对象来获取其对应的时区

      System.out.println(TimeZone.getTimeZone(ZoneId.of("GMT+08:00")));
      
      // sun.util.calendar.ZoneInfo[id="GMT+08:00",offset=28800000,
      // dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
      

  • getDisplayName()

    • 获取该 TimeZone 对象的时区名称

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getDisplayName()); // 中国标准时间
      
  • getDisplayName(Locale locale)

    • 获取该 TimeZone 对象的时区名称,并根据 Locale 对象进行国际化

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getDisplayName()); // 中国标准时间
      System.out.println(timeZone.getDisplayName(Locale.ENGLISH)); // China Standard Time
      
  • getDisplayName(boolean daylight, int style)

    • 获取该 TimeZone 对象的时区名称

    • daylight

      • true:指定夏令时名称
      • false:指定标准时间名称
    • style

      • TimeZone.LONG:显示全称
      • TimeZone.SHORT:显示简称
      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getDisplayName()); // 中国标准时间
      System.out.println(timeZone.getDisplayName(false, TimeZone.LONG)); // 中国标准时间
      System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT)); // CST (China Standard Time)  
      
  • getDisplayName(boolean daylight, int style, Locale locale)

    • 获取该 TimeZone 对象的时区名称,并根据 Locale 对象进行国际化

    • daylight

      • true:指定夏令时名称
      • false:指定标准时间名称
    • style

      • TimeZone.LONG:显示全称
      • TimeZone.SHORT:显示简称
      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getDisplayName()); // 中国标准时间
      System.out.println(timeZone.getDisplayName(false, TimeZone.LONG, Locale.ENGLISH)); // China Standard Time
      

  • getID()

    • 获取该 TimeZone 对象的时区 ID

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getID()); // Asia/Shanghai
      

  • setID(String ID)

    • 设置该 TimeZone 对象的时区 ID

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      timeZone.setID("Asia/Chongqing");
      System.out.println(timeZone.getID()); // Asia/Chongqing
      

  • getOffset(long date)

    • 获取该时间所在时区的时间偏移量

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getOffset(System.currentTimeMillis())); // 28800000
      

  • getDSTSavings()

    • 在夏令时规则生效时,返回相对于标准时间提前的毫秒数

    • 如果此时区不实施夏令时,则为 0

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      // 中国没有夏令时,故为0
      System.out.println(timeZone.getDSTSavings()); // 0
      

  • getRawOffset()

    • 获取时间原始偏移量,该值不受夏令时的影响,故称为时间原始偏移量

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.getRawOffset()); // 28800000
      

  • setRawOffset(int offsetMillis)

    • 设置时间原始偏移量

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      timeZone.setRawOffset(25200000);
      System.out.println(timeZone.getRawOffset()); // 25200000
      

  • toZoneId()

    • 将 TimeZone 对象转换为 ZoneId 对象

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      ZoneId zoneId = timeZone.toZoneId();
      System.out.println(zoneId); // Asia/Shanghai
      

  • useDaylightTime()

    • 查询此时区是否使用夏令时

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.useDaylightTime()); // false
      

  • inDaylightTime(Date date)

    • 查询给定的日期是否在此时区的夏令时中

      TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
      System.out.println(timeZone.inDaylightTime(new Date())); // false
      

  • hasSameRules(TimeZone other)

    • 如果两时区仅时区 ID 不同,但具有相同的规则和时间偏移量,则返回 true

    • 如果另一个时区为空,则返回 false

      TimeZone timeZone1 = TimeZone.getTimeZone("Asia/Shanghai");
      TimeZone timeZone2 = TimeZone.getTimeZone("Asia/Chongqing");
      System.out.println(timeZone1.hasSameRules(timeZone2)); // true
      


Class – 07 – Modifier类常用方法解析

一、Modifier 类的定义

  • Modifier 类 (修饰符工具类) 位于 java.lang.reflect 包中,用于判断和获取某个类、变量或方法的修饰符

  • Modifier 类将各个修饰符表示为相对应的整数,在源码中用 16 进制进行表示

    修饰符 静态常量 16 进制表示
    public Modifier.PUBLIC 0x00000001 (1)
    private Modifier.PRIVATE 0x00000002 (2)
    protected Modifier.PROTECTED 0x00000004 (4)
    static Modifier.STATIC 0x00000008 (8)
    final Modifier.FINAL 0x00000010 (16)
    synchronized Modifier.SYNCHRONIZED 0x00000020 (32)
    volatile Modifier.VOLATILE 0x00000040 (64)
    transient Modifier.TRANSIENT 0x00000080 (128)
    native Modifier.NATIVE 0x00000100 (256)
    interface Modifier.INTERFACE 0x00000200 (512)
    abstract Modifier.ABSTRACT 0x00000400 (1024)
    strict Modifier.STRICT 0x00000800 (2048)

二、Modifier 类常用方法

  • Modifier.toString(int mod)

    • 返回一个字符串,该字符串表示该整数参数所代表的修饰符

    • 通过 & 运算,来确定所代表的修饰符

    • 例如:7 的二进制表示为 111

      • & 上 Modifier.PUBLIC 的值 (0x00000001) 不为 0,则说明有 public 修饰符
      • & 上 Modifier.PRIVATE 的值 (0x00000002) 不为 0,则说明有 private 修饰符
      • & 上 Modifier.PROTECTED 的值 (0x00000004) 不为 0,则说明有 protected 修饰符
      System.out.println(Modifier.toString(1)); // public
      System.out.println(Modifier.toString(3)); // public private
      System.out.println(Modifier.toString(7)); // public private protected
      
    • 源码如下

      image


  • Modifier.constructorModifiers()

    • 返回可用于修饰构造方法的修饰符所代表的整数

    • 构造方法修饰符:public、protected、private

      System.out.println(Modifier.constructorModifiers()); // 7
      // public protected private
      System.out.println(Modifier.toString(Modifier.constructorModifiers()));
      

  • Modifier.classModifiers()

    • 返回可用于修饰类的修饰符所代表的整数

    • 类修饰符:public、protected、private、abstract、static、final、strictfp

      System.out.println(Modifier.classModifiers()); // 3103
      // public protected private abstract static final strictfp
      System.out.println(Modifier.toString(Modifier.classModifiers()));
      

  • Modifier.fieldModifiers()

    • 返回可用于修饰字段的修饰符所代表的整数

    • 字段修饰符:public、protected、private、static、final、transient、volatile

      System.out.println(Modifier.fieldModifiers()); // 223
      // public protected private static final transient volatile
      System.out.println(Modifier.toString(Modifier.fieldModifiers()));
      

  • Modifier.interfaceModifiers()

    • 返回可用于修饰接口的修饰符所代表的整数

    • 接口修饰符:public、protected、private、abstract、static、strictfp

      System.out.println(Modifier.interfaceModifiers()); // 3087
      // public protected private abstract static strictfp
      System.out.println(Modifier.toString(Modifier.interfaceModifiers()));
      

  • Modifier.methodModifiers()

    • 返回可用于修饰方法的修饰符所代表的整数

    • 方法修饰符:public、protected、private、abstract、static、final、synchronized、native、strictfp

      System.out.println(Modifier.methodModifiers()); // 3391
      // public protected private abstract static final synchronized native strictfp
      System.out.println(Modifier.toString(Modifier.methodModifiers()));
      

  • Modifier.parameterModifiers()

    • 返回可用于修饰参数的修饰符所代表的整数

    • 参数修饰符:final

      System.out.println(Modifier.parameterModifiers()); // 16
      System.out.println(Modifier.toString(Modifier.parameterModifiers())); // final
      

  • Modifier.isPublic(int mod)
    • 判断整数参数是否包括 public 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isPrivate(int mod)
    • 判断整数参数是否包括 private 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isProtected(int mod)
    • 判断整数参数是否包括 protected 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isStatic(int mod)
    • 判断整数参数是否包括 static 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isFinal(int mod)
    • 判断整数参数是否包括 finale 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isSynchronized(int mod)
    • 判断整数参数是否包括 synchronized 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isVolatile(int mod)
    • 判断整数参数是否包括 volatile 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isTransient(int mod)
    • 判断整数参数是否包括 transient 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isNative(int mod)
    • 判断整数参数是否包括 native 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isInterface(int mod)
    • 判断整数参数是否包括 interface 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isAbstract(int mod)
    • 判断整数参数是否包括 abstract 修饰符,如果包含则返回 true,否则返回 false

  • Modifier.isStrict(int mod)
    • 判断整数参数是否包括 strict 修饰符,如果包含则返回 true,否则返回 false

public class ModifierTest {
    
    

    public static final String data = "123";
    
    public static void main(String[] args) throws Exception {
    
    
        int modifiers = ModifierTest.class.getDeclaredField("data").getModifiers();
        System.out.println(Modifier.isPublic(modifiers)); // true
        System.out.println(Modifier.isPrivate(modifiers)); // false
        System.out.println(Modifier.isProtected(modifiers)); // false
        System.out.println(Modifier.isStatic(modifiers)); // true
        System.out.println(Modifier.isFinal(modifiers)); // true
        System.out.println(Modifier.isSynchronized(modifiers)); // false
        System.out.println(Modifier.isVolatile(modifiers)); // false
        System.out.println(Modifier.isTransient(modifiers)); // false
        System.out.println(Modifier.isNative(modifiers)); // false
        System.out.println(Modifier.isInterface(modifiers)); // false
        System.out.println(Modifier.isAbstract(modifiers)); // false
        System.out.println(Modifier.isStrict(modifiers)); // false
    }
}


Class – 08 – Parameter类常用方法解析

一、Parameter 类的定义

  • Parameter 类位于 java.lang.reflect 包中,主要用于在程序运行状态中,动态地获取参数信息

  • 在 JDK8.0 之前,编译器会忽略我们编写代码时设定的参数名,因此会得到像 arg0、arg1 这样无意义的参数名,比如:当我们使用 mybatis 时,我们会用到 @Param 注解来使 mybatis 保留参数名称

  • 在 JDK8.0 及之后,Java 在语言层面 (使用反射 API 和 Parameter.getName() 方法) 和字节码层面 (使用新的 javac 编译器以及 -parameters 参数) 提供了支持,不过为了保证向下兼容,在 JDK8.0 及之后的版本中该特性是默认关闭的

  • 在 IDEA 中我们可以通过以下设置来完成
    在这里插入图片描述

  • 如果使用了 maven,可以配置 maven 的编译插件

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
            <compilerArgument>-parameters</compilerArgument>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
    
  • 示例如下

    public class ParameterTest {
          
          
    
        public void test(String key, String value) {
          
          }
    
        public static void main(String[] args) throws Exception {
          
          
            Method method = ParameterTest.class.getMethod("test", String.class, String.class);
            Parameter[] parameters = method.getParameters();
            for (Parameter parameter : parameters) {
          
          
                // 正常编译得到: arg0 arg1
                // 加入-parameters后编译得到: key value
                System.out.println(parameter.getName());
            }
        }
    }
    

二、Parameter 类常用方法

  • getAnnotatedType()

    • 返回一个 AnnotatedType 对象,该对象表示使用类型来指定由该参数对象表示的形式参数的类型

    • 通过其 getType() 方法,我们可以获取到对应的形参类型

      public class ParameterTest {
              
              
      
          public void test(String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              for (Parameter parameter : parameters) {
              
              
                  AnnotatedType annotatedType = parameter.getAnnotatedType();
                  // class java.lang.String
                  // class java.lang.String
                  System.out.println(annotatedType.getType());
              }
          }
      }
      

  • getAnnotation(Class annotationClass)

    • 如果该参数对象存在指定类型的注解,则返回该注解,否则返回 null

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同

      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface ParameterAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      public class ParameterTest {
              
              
      
          public void test(@ParameterAnnotation(key = "key", value = "value") String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              ParameterAnnotation annotation = parameters[0].getAnnotation(ParameterAnnotation.class);
              // @lang.reflect.Parameter.ParameterAnnotation(key=key, value=value)
              System.out.println(annotation);
          }
      }
      

  • getDeclaredAnnotation(Class annotationClass)
    • 如果该参数对象存在指定类型的注解,则返回该注解,否则返回 null
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同

  • getAnnotationsByType(Class annotationClass)

    • 如果该参数对象存在指定类型的注解,则返回该注解数组,否则返回 null

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同

    • getAnnotationsByType() 方法与 getAnnotation() 方法的区别在于:getAnnotationsByType() 方法会检查修饰该参数对象的注解是否为可重复类型注解,如果是则会返回修饰该参数对象的一个或多个注解

    • @Repeatable 用于声明注解为可重复类型注解

    • 当声明为可重复类型注解后,如果参数注解仍为一个,则 getAnnotation() 方法会正常返回,如果参数注解为多个,则 getAnnotation() 方法会返回 null

      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      // @Repeatable: 声明该注解为可重复类型注解
      @Repeatable(RepeatableAnnotation.class)
      public @interface ParameterAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      @interface RepeatableAnnotation {
              
              
          ParameterAnnotation[] value();
      }
      	
      public class ParameterTest {
              
              
      
          public void test(@ParameterAnnotation(key = "key1", value = "value1")
                           @ParameterAnnotation(key = "key2", value = "value2") String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              ParameterAnnotation annotation = parameters[0].getAnnotation(ParameterAnnotation.class);
              // null
              System.out.println(parameters[0].getAnnotation(ParameterAnnotation.class));
              ParameterAnnotation[] annotationsByType = parameters[0].getAnnotationsByType(ParameterAnnotation.class);
              // [@lang.reflect.ParameterAnnotation(key=key1, value=value1), @lang.reflect.ParameterAnnotation(key=key2, value=value2)]
              System.out.println(Arrays.toString(annotationsByType));
          }
      }
      
      

  • getDeclaredAnnotationsByType(Class annotationClass)
    • 如果该参数对象存在指定类型的注解,则返回该注解数组,否则返回null
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同

  • getAnnotations()

    • 返回该参数对象上的所有注解,如果没有注解,则返回空数组

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同

      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface ParameterAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface TestAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      public class ParameterTest {
              
              
      
          public void test(@ParameterAnnotation(key = "key1", value = "value1")
                           @TestAnnotation(key = "key2", value = "value2") String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              Annotation[] annotations = parameters[0].getAnnotations();
              // [@lang.reflect.ParameterAnnotation(key=key1, value=value1), @lang.reflect.TestAnnotation(key=key2, value=value2)]
              System.out.println(Arrays.toString(annotations));
          }
      }
      
      

  • getDeclaredAnnotations()
    • 返回该参数对象上的所有注解,如果没有注解,则返回空数组
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同

  • getModifiers()

    • 返回修饰该参数对象修饰符的整数形式,使用 Modifier 类对其进行解码

      public class ParameterTest {
              
              
      
          public void test(final String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              // final
              System.out.println(Modifier.toString(parameters[0].getModifiers()));
          }
      }
      
      

  • getName()

    • 返回参数对象名称

      public class ParameterTest {
              
              
      
          public void test(String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              for (Parameter parameter : parameters) {
              
              
                  // 正常编译得到: arg0 arg1
                  // 加入-parameters后编译得到: key value
                  System.out.println(parameter.getName());
              }
          }
      }
      
      

  • getParameterizedType()

    • 返回一个类型对象,该对象表示该参数对象表示的泛型参数的类型 (保留泛型)

      public class ParameterTest<T> {
              
              
      
          public void test(T t, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", Object.class, String.class);
              Parameter[] parameters = method.getParameters();
              // T
              System.out.println(parameters[0].getParameterizedType().getTypeName());
          }
      }
      

  • getType()

    • 返回一个 Class 对象,该 Class 对象表示该参数对象表示的声明参数的类型 (擦除泛型)

      public class ParameterTest<T> {
              
              
      
          public void test(T t, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", Object.class, String.class);
              Parameter[] parameters = method.getParameters();
              // class java.lang.Object
              System.out.println(parameters[0].getType());
          }
      }
      

  • isAnnotationPresent(Class annotationClass)

    • 如果该参数对象上有指定类型的注解,则返回 true,否则为 false

      public class ParameterTest {
              
              
      
          public void test(@ParameterAnnotation(key = "key", value = "value") String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              // true
              System.out.println(parameters[0].isAnnotationPresent(ParameterAnnotation.class));
          }
      }
      
    • 如果该参数对象上的注解类型为可重复类型注解,则需要标明可重复注解而不是其子注解,才会返回 true,否则为 false

      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      @Repeatable(RepeatableAnnotation.class)
      public @interface ParameterAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.PARAMETER)
      @Retention(RetentionPolicy.RUNTIME)
      @interface RepeatableAnnotation {
              
              
          ParameterAnnotation[] value();
      }
      
      public class ParameterTest {
              
              
      
          public void test(@ParameterAnnotation(key = "key1", value = "value1")
                           @ParameterAnnotation(key = "key2", value = "value2") final String key, String value) {
              
              
          }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              // false
              System.out.println(parameters[0].isAnnotationPresent(ParameterAnnotation.class));
              // true
              System.out.println(parameters[0].isAnnotationPresent(RepeatableAnnotation.class));
          }
      }
      

  • isVarArgs()

    • 如果该参数对象表示 可变参,则返回 true,否则为 false

      public class ParameterTest {
              
              
      
          public void test(String key, String ... values) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String[].class);
              Parameter[] parameters = method.getParameters();
              // false
              System.out.println(parameters[0].isVarArgs());
              // true
              System.out.println(parameters[1].isVarArgs());
          }
      }
      

  • isNamePresent()

    • 如果该参数对象根据类文件能获取到名称,则返回 true,否则为 false

    • 当我们带上 -parameters 参数时,该参数对象就有了名称

      public class ParameterTest {
              
              
      
          public void test(String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              // 正常编译得到: false arg0
              // 加入-parameters 后编译得到: true key
              System.out.println(parameters[0].isNamePresent() + " " + parameters[0].getName());
          }
      }
      

  • getDeclaringExecutable()

    • 返回声明该参数对象的可执行文件

      public class ParameterTest {
              
              
      
          public void test(String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              // public void lang.reflect.ParameterTest.test(java.lang.String,java.lang.String)
              System.out.println(parameters[0].getDeclaringExecutable());
          }
      }
      

  • isImplicit()

    • 如果该参数对象为隐式参数,则返回 true,否则为 false

    • Java 编译器会为内部类的构造方法创建一个隐式参数

      public class ParameterTest {
              
              
      
          class InnerClass {
              
              
          
              public InnerClass(String key) {
              
              
              
              }
          }
      
          public static void main(String[] args) throws Exception {
              
              
              Constructor<InnerClass> declaredConstructor = InnerClass.class.getConstructor(ParameterTest.class, String.class);
              Parameter[] parameters = declaredConstructor.getParameters();
              for (Parameter parameter : parameters) {
              
              
                  // 【final lang.reflect.ParameterTest this$0】 isImplicit() ===> true
                  // 【java.lang.String key】 isImplicit() ===> false
                  System.out.println("【" + parameter + "】 isImplicit() ===> " + parameter.isImplicit());
              }
          }
      }
      
      

  • isSynthetic()

    • 如果该参数对象为合成参数,则返回 true,否则为 false

      public class ParameterTest {
              
              
      
          public void test(String key, String value) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = ParameterTest.class.getMethod("test", String.class, String.class);
              Parameter[] parameters = method.getParameters();
              // false
              System.out.println(parameters[0].isSynthetic());
          }
      }
      
      


Class – 09 – Field类常用方法解析

一、Field 类的定义

  • Field 类位于 java.lang.reflect 包中,主要用于在程序运行状态中,动态地获取或设置字段信息

二、Field 类常用方法

  • getAnnotatedType()

    • 返回一个 AnnotatedType 对象,该对象表示使用类型来指定由该字段对象表示的字段的类型

    • 通过其 getType() 方法,我们可以获取到对应的字段类型

      public class FieldTest {
              
              
      
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              AnnotatedType annotatedType = field.getAnnotatedType();
              // class java.lang.String
              System.out.println(annotatedType.getType());
          }
      }
      

  • getAnnotation(Class annotationClass)

    • 如果该字段对象存在指定类型的注解,则返回该注解,否则返回 null

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同

      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface FieldAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      public class FieldTest {
              
              
      
          @FieldAnnotation(key = "key", value = "value")
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              FieldAnnotation annotation = field.getAnnotation(FieldAnnotation.class);
              // @lang.reflect.FieldAnnotation(key=key, value=value)
              System.out.println(annotation);
          }
      }
      

  • getDeclaredAnnotation(Class annotationClass)
    • 如果该字段对象存在指定类型的注解,则返回该注解,否则返回 null
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同

  • getAnnotationsByType(Class annotationClass)

    • 如果该字段对象存在指定类型的注解,则返回该注解数组,否则返回 null

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同

    • getAnnotationsByType() 方法与 getAnnotation() 方法的区别在于:getAnnotationsByType() 方法会检查修饰该字段对象的注解是否为可重复类型注解,如果是则会返回修饰该字段对象的一个或多个注解

    • @Repeatable 用于声明注解为可重复类型注解

    • 当声明为可重复类型注解后,如果字段注解仍为一个,则 getAnnotation() 方法会正常返回,如果字段注解为多个,则 getAnnotation() 方法会返回 null

      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      @Repeatable(RepeatableAnnotation.class)
      public @interface FieldAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      @interface RepeatableAnnotation {
              
              
      
          FieldAnnotation[] value();
      }
      
      public class FieldTest {
              
              
      
          @FieldAnnotation(key = "key1", value = "value1")
          @FieldAnnotation(key = "key2", value = "value2")
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // null
              System.out.println(field.getAnnotation(FieldAnnotation.class));
              FieldAnnotation[] annotationsByType = field.getAnnotationsByType(FieldAnnotation.class);
              // [@com.xj.FieldAnnotation(key=key1, value=value1), @com.xj.FieldAnnotation(key=key2, value=value2)]
              System.out.println(Arrays.toString(annotationsByType));
          }
      }
      
      

  • getDeclaredAnnotationsByType(Class annotationClass)
    • 如果该字段对象存在指定类型的注解,则返回该注解数组,否则返回 null
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同

  • getAnnotations()

    • 返回该字段对象上的所有注解,如果没有注解,则返回空数组

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同

      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface FieldAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface TestAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      public class FieldTest {
              
              
      
          @FieldAnnotation(key = "key1", value = "value1")
          @TestAnnotation(key = "key2", value = "value2")
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              Annotation[] annotations = field.getAnnotations();
              // [@lang.reflect.FieldAnnotation(key=key1, value=value1), @lang.reflect.TestAnnotation(key=key2, value=value2)]
              System.out.println(Arrays.toString(annotations));
          }
      }
      
      

  • getDeclaredAnnotations()
    • 返回该字段对象上的所有注解,如果没有注解,则返回空数组
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同

  • getModifiers()

    • 返回修饰该字段对象修饰符的整数形式,使用 Modifier 类对其进行解码

      public class FieldTest {
              
              
      
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // private
              System.out.println(Modifier.toString(field.getModifiers()));
          }
      }
      
      

  • getName()

    • 返回字段对象名称

      public class FieldTest {
              
              
      
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // name
              System.out.println(field.getName());
          }
      }
      
      

  • getType()

    • 返回一个 Class 对象,该 Class 对象表示该字段对象表示的声明字段的类型 (擦除泛型)

      public class FieldTest<T> {
              
              
      
          private T name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // class java.lang.Object
              System.out.println(field.getType());
          }
      }
      
      

  • getGenericType()

    • 返回一个 Type 对象,该 Type 对象表示该字段对象表示的声明字段的类型 (保留泛型)

      public class FieldTest<T> {
              
              
      
          private T name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // T
              System.out.println(field.getGenericType());
          }
      }
      
      

  • isAnnotationPresent(Class annotationClass)

    • 如果该字段对象上有指定类型的注解,则返回 true,否则为 false

      public class FieldTest {
              
              
      
          @FieldAnnotation(key = "key", value = "value")
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // true
              System.out.println(field.isAnnotationPresent(FieldAnnotation.class));
          }
      }
      

  • getDeclaringClass()

    • 返回该字段对象表示的字段所在类的 Class 对象

      public class FieldTest {
              
              
      
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              Class<?> declaringClass = field.getDeclaringClass();
              // class lang.reflect.FieldTest
              System.out.println(declaringClass);
          }
      }
      

  • isEnumConstant()

    • 如果该字段对象表示枚举类型的元素,则返回 true,否则返回 false

      public class FieldTest {
              
              
      
          private String name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // false
              System.out.println(field.isEnumConstant());
          }
      }
      

  • toString()

    • 返回该字段对象的字符串表示形式 (擦除泛型)

      public class FieldTest<T> {
              
              
      
          private T name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // private java.lang.Object lang.reflect.FieldTest.name
              System.out.println(field.toString());
          }
      }
      

  • toGenericString()

    • 返回该字段对象的字符串表示形式 (保留泛型)

      public class FieldTest<T> {
              
              
      
          private T name;
      
          public static void main(String[] args) throws Exception {
              
              
              Field field = FieldTest.class.getDeclaredField("name");
              // private T lang.reflect.FieldTest.name
              System.out.println(field.toGenericString());
          }
      }
      

  • isSynthetic()

    • 如果该字段对象为合成字段,则返回 true,否则为 false

    • 编译器在编译的时候,会在内部类中生成一个字段,该字段指向一个外部类的实例

      public class FieldTest {
              
              
      
          private String name;
      
          private class InnerClass {
              
              
          
          }
      
          public static void main(String[] args) throws Exception {
              
              
              InnerClass innerClass = new FieldTest().new InnerClass();
              Field[] fields = innerClass.getClass().getDeclaredFields();
              for (Field field : fields) {
              
              
                  // 【final lang.reflect.FieldTest lang.reflect.FieldTest$InnerClass.this$0】 isSynthetic(): true
                  System.out.println("【" + field + "】" + " isSynthetic(): " + field.isSynthetic());
              }
          }
      }
      
    • InnerClass 内部类反编译得到如下结果,生成了一个 this$0 的字段

      class FieldTest$InnerClass {
              
              
          private FieldTest$InnerClass(FieldTest var1) {
              
              
              this.this$0 = var1;
          }
      }
      
    • 有关 synthetic 的相关内容,小伙伴可以看下这里


  • isAccessible()

    • 获取该字段对象的可访问标志

      public class FieldTest {
              
              
      
          private String name;
      
          public String getName() {
              
              
              return name;
          }
      
          public void setName(String name) {
              
              
              this.name = name;
          }
      }
      
      public class Test {
              
              
      
          public static void main(String[] args) throws Exception {
              
              
              FieldTest fieldTest = new FieldTest();
              fieldTest.setName("小明");
              Field[] declaredFields = FieldTest.class.getDeclaredFields();
              for (Field declaredField : declaredFields) {
              
              
                  // false
                  System.out.println(declaredField.isAccessible());
              }
          }
      }
      

  • setAccessible(boolean flag)

    • 设置该字段对象的可访问标志

    • 在其他类里获取该类的私有成员变量时,需要设置访问标志为 true,否则会报异常

      public class FieldTest {
              
              
      
          private String name;
      
          public String getName() {
              
              
              return name;
          }
      
          public void setName(String name) {
              
              
              this.name = name;
          }
      }
      
      public class Test {
              
              
      
          public static void main(String[] args) throws Exception {
              
              
              FieldTest fieldTest = new FieldTest();
              fieldTest.setName("小明");
              Field[] declaredFields = FieldTest.class.getDeclaredFields();
              for (Field declaredField : declaredFields) {
              
              
                  declaredField.setAccessible(true);
                  // 小明
                  System.out.println(declaredField.get(fieldTest));
              }
          }
      }
      

  • getChar(Object obj)
    • 获取 char 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 char 类型的值

  • getByte(Object obj)
    • 获取 byte 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 byte 类型的值

  • getShort(Object obj)
    • 获取 short 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 short 类型的值

  • getInt(Object obj)
    • 获取 int 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 int 类型的值

  • getLong(Object obj)
    • 获取 long 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 long 类型的值

  • getFloat(Object obj)
    • 获取 float 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 float 类型的值

  • getDouble(Object obj)
    • 获取 double 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 double 类型的值

  • getBoolean(Object obj)
    • 获取 boolean 类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为 boolean 类型的值

  • getBoolean(Object obj)
    • 获取 Object 类型的静态或实例字段的值,如果是基本数据类型,则会将该值将自动包装在对象中

public class FieldTest {
    
    

    private char charField = 'A';
    private byte byteField = 110;
    private short shortField = 111;
    private int intField = 112;
    private long longField = 113;
    private float floatField = 1.23F;
    private double doubleField = 1.23;
    private boolean booleanField = true;
    private Object objField = "哈哈哈";

    public static void main(String[] args) throws Exception {
    
    
        Class<FieldTest> fieldTestClass = FieldTest.class;
        /**
         * 获取char类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为char类型的值
         */
        Field charField = fieldTestClass.getDeclaredField("charField");
        FieldTest charFieldTest = new FieldTest();
        System.out.println(charField.getChar(charFieldTest)); // A
        charField.setChar(charFieldTest, 'B');
        System.out.println(charField.getChar(charFieldTest)); // B

        /**
         * 获取byte类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为byte类型的值
         */
        Field byteField = fieldTestClass.getDeclaredField("byteField");
        FieldTest byteFieldTest = new FieldTest();
        System.out.println(byteField.getByte(byteFieldTest)); // 110
        byteField.setByte(byteFieldTest, (byte) 120);
        System.out.println(byteField.getByte(byteFieldTest)); // 120

        /**
         * 获取short类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为short类型的值
         */
        Field shortField = fieldTestClass.getDeclaredField("shortField");
        FieldTest shortFieldTest = new FieldTest();
        System.out.println(shortField.getShort(shortFieldTest)); // 111
        shortField.setShort(shortFieldTest, (short) 888);
        System.out.println(shortField.getShort(shortFieldTest)); // 888

        /**
         * 获取int类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为int类型的值
         */
        Field intField = fieldTestClass.getDeclaredField("intField");
        FieldTest intFieldTest = new FieldTest();
        System.out.println(intField.getInt(intFieldTest)); // 112
        intField.setInt(intFieldTest, 888);
        System.out.println(intField.getInt(intFieldTest)); // 888

        /**
         * 获取long类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为long类型的值
         */
        Field longField = fieldTestClass.getDeclaredField("longField");
        FieldTest longFieldTest = new FieldTest();
        System.out.println(longField.getLong(longFieldTest)); // 113
        longField.setLong(longFieldTest, 888L);
        System.out.println(longField.getLong(longFieldTest)); // 888

        /**
         * 获取float类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为float类型的值
         */
        Field floatField = fieldTestClass.getDeclaredField("floatField");
        FieldTest floatFieldTest = new FieldTest();
        System.out.println(floatField.getFloat(floatFieldTest)); // 1.23
        floatField.setFloat(floatFieldTest, 1.88F);
        System.out.println(floatField.getFloat(floatFieldTest)); // 1.88

        /**
         * 获取double类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为double类型的值
         */
        Field doubleField = fieldTestClass.getDeclaredField("doubleField");
        FieldTest doubleFieldTest = new FieldTest();
        System.out.println(doubleField.getDouble(doubleFieldTest)); // 1.23
        doubleField.setDouble(doubleFieldTest, 1.88);
        System.out.println(doubleField.getDouble(doubleFieldTest)); // 1.88

        /**
         * 获取boolean类型的静态或实例字段的值,或通过扩展转换将另一个基本数据类型转换为boolean类型的值
         */
        Field booleanField = fieldTestClass.getDeclaredField("booleanField");
        FieldTest booleanFieldTest = new FieldTest();
        System.out.println(booleanField.getBoolean(booleanFieldTest)); // true
        booleanField.setBoolean(booleanFieldTest, false);
        System.out.println(booleanField.getBoolean(booleanFieldTest)); // false

        /**
         * 获取Object类型的静态或实例字段的值,如果是基本数据类型,则会将该值将自动包装在对象中
         */
        Field objField = fieldTestClass.getDeclaredField("objField");
        FieldTest objFieldTest = new FieldTest();
        System.out.println(objField.get(objFieldTest)); // 哈哈哈
        objField.set(objFieldTest, "啊啊啊");
        System.out.println(objField.get(objFieldTest)); // 啊啊啊
    }
}




Class – 10 – Method类常用方法解析

一、Method 类的定义

  • Method 类位于 java.lang.reflect 包中,主要用于在程序运行状态中,动态地获取方法信息

二、Method 类常用方法

  • getAnnotatedReturnType()

    • 返回一个 AnnotatedType 对象,该对象表示使用类型来指定由该可执行文件表示的方法或构造函数的返回类型

      public class MethodTest {
              
              
          
          public String test() {
              
              
              return null;
          }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              AnnotatedType annotatedReturnType = method.getAnnotatedReturnType();
              // class java.lang.String
              System.out.println(annotatedReturnType.getType());
          }
      }
      
  • getAnnotatedExceptionTypes()

    • 返回一个 AnnotatedType 对象数组,这些对象表示使用类型来指定由该可执行文件表示的方法或构造函数声明的异常

      public class MethodTest {
              
              
          
          public void test() throws NullPointerException, ClassNotFoundException {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              AnnotatedType[] annotatedExceptionTypes = method.getAnnotatedExceptionTypes();
              for (AnnotatedType annotatedExceptionType : annotatedExceptionTypes) {
              
              
                  // class java.lang.NullPointerException
                  // class java.lang.ClassNotFoundException
                  System.out.println(annotatedExceptionType.getType());
              }
          }
      }
      

  • getAnnotatedReceiverType()

    • 返回一个 AnnotatedType 对象,该对象表示使用类型来指定该可执行对象表示的方法或构造函数的接收者类型

      public class MethodTest {
              
              
          
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              AnnotatedType annotatedReceiverType = method.getAnnotatedReceiverType();
              // class lang.reflect.MethodTest
              System.out.println(annotatedReceiverType.getType());
          }
      }
      
  • getAnnotation(Class annotationClass)

    • 如果该方法对象存在指定类型的注解,则返回该注解,否则返回 null

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同

      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MethodAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      public class MethodTest {
              
              
          
          @MethodAnnotation(key = "key", value = "value")
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              MethodAnnotation annotation = method.getAnnotation(MethodAnnotation.class);
              // @lang.reflect.MethodAnnotation(value=value, key=key)
              System.out.println(annotation);
          }
      }
      
  • getDeclaredAnnotation(Class annotationClass)

    • 如果该方法对象存在指定类型的注解,则返回该注解,否则返回 null
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotation() 方法与 getDeclaredAnnotation() 方法作用相同
  • getAnnotationsByType(Class annotationClass)

    • 如果该方法对象存在指定类型的注解,则返回该注解数组,否则返回 null

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同

    • getAnnotationsByType() 方法与 getAnnotation() 方法的区别在于:getAnnotationsByType() 方法会检查修饰该方法对象的注解是否为可重复类型注解,如果是则会返回修饰该方法对象的一个或多个注解

    • @Repeatable 用于声明注解为可重复类型注解

    • 当声明为可重复类型注解后,如果方法注解仍为一个,则 getAnnotation() 方法会正常返回,如果方法注解为多个,则 getAnnotation() 方法会返回 null

      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      @Repeatable(RepeatableAnnotation.class)
      public @interface MethodAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      @interface RepeatableAnnotation {
              
              
          MethodAnnotation[] value();
      }
      
      public class MethodTest {
              
              
          
          @MethodAnnotation(key = "key1", value = "value1")
          @MethodAnnotation(key = "key2", value = "value2")
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              // null
              System.out.println(method.getAnnotation(MethodAnnotation.class));
              MethodAnnotation[] annotationsByType = method.getAnnotationsByType(MethodAnnotation.class);
              // [@lang.reflect.MethodAnnotation(value=value1, key=key1), @lang.reflect.MethodAnnotation(value=value2, key=key2)]
              System.out.println(Arrays.toString(annotationsByType));
          }
      }
      
  • getDeclaredAnnotationsByType(Class annotationClass)

    • 如果该方法对象存在指定类型的注解,则返回该注解数组,否则返回 null
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同
  • getAnnotations()

    • 返回该方法对象上的所有注解,如果没有注解,则返回空数组

    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同

      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MethodAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface TestAnnotation {
              
              
      
          String key();
      
          String value();
      }
      
      public class MethodTest {
              
              
          
          @MethodAnnotation(key = "key1", value = "value1")
          @TestAnnotation(key = "key2", value = "value2")
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              Annotation[] annotations = method.getAnnotations();
              for (Annotation annotation : annotations) {
              
              
                  // @lang.reflect.MethodAnnotation(value=value1, key=key1)
                  // @lang.reflect.Parameter.TestAnnotation(key=key2, value=value2)
                  System.out.println(annotation);
              }
          }
      }
      
  • getDeclaredAnnotations()

    • 返回该方法对象上的所有注解,如果没有注解,则返回空数组
    • 只有类级别的注解会被继承得到,对于其他对象而言,getAnnotations() 方法与 getDeclaredAnnotations() 方法作用相同
  • getModifiers()

    • 返回修饰该方法对象修饰符的整数形式,使用 Modifier 类对其进行解码

      public class MethodTest {
              
              
          
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              // public
              System.out.println(Modifier.toString(method.getModifiers()));
          }
      }
      
  • getName()

    • 返回方法对象名称

      public class MethodTest {
              
              
          
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              // test
              System.out.println(method.getName());
          }
      }
      
  • isAnnotationPresent(Class annotationClass)

    • 如果该方法对象上有指定类型的注解,则返回 true,否则为 false

      public class MethodTest {
              
              
      
          @MethodAnnotation(key = "key", value = "value")
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              // true
              System.out.println(method.isAnnotationPresent(MethodAnnotation.class));
          }
      }
      
  • isVarArgs()

    • 如果该方法对象的参数中存在 可变参,则返回 true,否则为 false

      public class MethodTest {
              
              
      
          public void test(String ... args) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test", String[].class);
              // true
              System.out.println(method.isVarArgs());
          }
      }
      
  • getDeclaringClass()

    • 返回该方法对象表示的方法所在类的 Class 对象

      public class MethodTest {
              
              
      
          public void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              Class<?> declaringClass = method.getDeclaringClass();
              // class lang.reflect.MethodTest
              System.out.println(declaringClass);
          }
      }
      
  • getAnnotatedParameterTypes()

    • 返回一个 AnnotatedType 对象数组,这些对象表示使用类型来指定由该可执行文件表示的方法或构造函数的形式参数类型

      public class MethodTest {
              
              
      
          public void test(String name, Integer age) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test", String.class, Integer.class);
              AnnotatedType[] annotatedParameterTypes = method.getAnnotatedParameterTypes();
              for (AnnotatedType annotatedParameterType : annotatedParameterTypes) {
              
              
                  // class java.lang.String
                  // class java.lang.Integer
                  System.out.println(annotatedParameterType.getType());
              }
          }
      }
      
  • getParameterAnnotations()

    • 返回一组注解数组,这些注解以声明顺序修饰该方法对象的参数

      public class MethodTest {
              
              
      
          public void test(@ParameterAnnotation(key = "key1", value = "value1") String name,
                           @ParameterAnnotation(key = "key2", value = "value2") Integer age) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test", String.class, Integer.class);
              Annotation[][] parameterAnnotations = method.getParameterAnnotations();
              // [[@lang.reflect.ParameterAnnotation(key=key1, value=value1)], [@lang.reflect.ParameterAnnotation(key=key2, value=value2)]]
              System.out.println(Arrays.deepToString(parameterAnnotations));
          }
      }
      
  • getParameterCount()

    • 返回该方法对象的参数个数 (无论是显式声明的还是隐式声明的或不声明的)

      public class MethodTest {
              
              
      
          public void test(String name, Integer age) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test", String.class, Integer.class);
              // 2
              System.out.println(method.getParameterCount());
          }
      }
      
  • getParameters()

    • 返回一个参数对象数组,该数组表示该方法对象的所有参数

      public class MethodTest {
              
              
      
          public void test(String name, Integer age) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test", String.class, Integer.class);
              Parameter[] parameters = method.getParameters();
              for (Parameter parameter : parameters) {
              
              
                  // java.lang.String name
                  // java.lang.Integer age
                  System.out.println(parameter);
              }
          }
      }
      
  • getDefaultValue()

    • 返会该注解方法对象表示的成员默认值

    • 如果成员属于基本数据类型,则返回对应的包装类实例

    • 如果没有默认值或者该方法实例不表示注解方法,则返回 null

      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MethodAnnotation {
              
              
      
          String key() default "default key";
      
          String value() default "default value";
      }
      
      public class MethodTest {
              
              
      
          public static void main(String[] args) throws Exception {
              
              
              Method key = MethodAnnotation.class.getMethod("key");
              Method value = MethodAnnotation.class.getMethod("value");
              Object defaultValue1 = key.getDefaultValue();
              Object defaultValue2 = value.getDefaultValue();
              // default key
              System.out.println(defaultValue1);
              // default value
              System.out.println(defaultValue2);
          }
      }
      
  • getParameterTypes()

    • 返回一个 Class 对象数组,该数组以声明顺序表示该方法对象的参数对象 (擦除泛型)

      public class MethodTest<T> {
              
              
      
          public void test(T t, LinkedList<Integer> list) {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test", Object.class, LinkedList.class);
              Class<?>[] parameterTypes = method.getParameterTypes();
              // [class java.lang.Object, class java.util.LinkedList]
              System.out.println(Arrays.toString(parameterTypes));
          }
      }
      
  • getReturnType()

    • 返回一个 Class 对象,该 Class 对象表示该方法对象的返回对象 (擦除泛型)

      public class MethodTest<T> {
              
              
      
          public T test(T t) {
              
              
              return t;
          }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test", Object.class);
              Class<?> returnType = method.getReturnType();
              // class java.lang.Object
              System.out.println(returnType);
          }
      }
      
  • getGenericReturnType()

    • 返回一个 Type 对象,该 Type 对象表示该方法对象的返回类型 (保留泛型)

      public class MethodTest<T> {
              
              
      
          public T test(T t) {
              
              
              return t;
          }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test", Object.class);
              Type genericReturnType = method.getGenericReturnType();
              // T
              System.out.println(genericReturnType);
          }
      }
      
  • getExceptionTypes()

    • 返回一个 Class 对象数组,该数组表示由该方法对象抛出的异常对象 (擦除泛型)

      public class MethodTest<T> {
              
              
      
          public <T extends Exception> void test() throws T, NullPointerException {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test");
              Class<?>[] exceptionTypes = method.getExceptionTypes();
              // [class java.lang.Exception, class java.lang.NullPointerException]
              System.out.println(Arrays.toString(exceptionTypes));
          }
      }
      
      
  • getGenericExceptionTypes()

    • 返回一个 Type 对象数组,该数组表示由该方法对象抛出的异常类型 (保留泛型)

      public class MethodTest<T> {
              
              
      
          public <T extends Exception> void test() throws T, NullPointerException {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test");
              Type[] genericExceptionTypes = method.getGenericExceptionTypes();
              // [T, class java.lang.NullPointerException]
              System.out.println(Arrays.toString(genericExceptionTypes));
          }
      }
      
      
  • getTypeParameters()

    • 返回一个 TypeVariable 对象数组,该数组表示该方法对象声明列表上的类型变量数组

      public class MethodTest<T, V> {
              
              
      
          public <T, V> void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test");
              TypeVariable<Method>[] typeParameters = method.getTypeParameters();
              // [T, V]
              System.out.println(Arrays.toString(typeParameters));
          }
      }
      
      
  • toString()

    • 返回该方法对象的字符串表示形式 (擦除泛型)

      public class MethodTest<T, V> {
              
              
      
          public <T, V> void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test");
              // public void lang.reflect.MethodTest.test()
              System.out.println(method.toString());
          }
      }
      
  • toGenericString()

    • 返回该方法对象的字符串表示形式 (保留泛型)

      public class MethodTest<T, V> {
              
              
      
          public <T, V> void test() {
              
              }
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test");
              // public <T,V> void lang.reflect.MethodTest.test()
              System.out.println(method.toGenericString());
          }
      }
      
      
  • isAccessible()

    • 获取该方法对象的可访问标志

      public class MethodTest {
              
              
      
          private void test() {
              
              }
      }
      
      public class Test {
              
              
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              // false
              System.out.println(method.isAccessible());
          }
      }
      
  • setAccessible(boolean flag)

    • 设置该方法对象的可访问标志

    • 在其他类里调用该方法对象时,如果该方法为私有方法,需要设置访问标志为 true,否则会报异常

      public class MethodTest {
              
              
      
          private void test() {
              
              }
      }
      
      public class Test {
              
              
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getDeclaredMethod("test");
              method.setAccessible(true);
              // test
              System.out.println(method.getName());
          }
      }
      
      
  • isDefault()

    • 判断该方法对象是否为默认方法,如果是则返回 true,否则为 false

      public interface Interface {
              
              
      
          default void test() {
              
              
              System.out.println("这是一个默认方法");
          }
      }
      
      public class MethodTest implements Interface {
              
              
      
          public static void main(String[] args) throws Exception {
              
              
              Method method = MethodTest.class.getMethod("test");
              // true
              System.out.println(method.isDefault());
          }
      }
      
      
  • isSynthetic()

    • 判断该方法对象是否为合成方法,如果是则返回 true,否则为 false

    • 在内部类 InnerClass 中,name 是一个私有属性,而我们在外部类 MethodTest 中,直接引用了这个属性,因此编译器会生成一个合成方法,用于绕开 private 私有属性的限制

      public class MethodTest {
              
              
      
          private class InnerClass {
              
              
              private String name = "小明";
          }
      
          public static void main(final String[] arguments) {
              
              
              InnerClass innerClass = new MethodTest().new InnerClass();
              // name: 小明
              System.out.println("name: " + innerClass.name);
      
              Method[] declaredMethods = innerClass.getClass().getDeclaredMethods();
              for (Method declaredMethod : declaredMethods) {
              
              
                  // 【static java.lang.String lang.reflect.MethodTest$InnerClass.access$100(lang.reflect.MethodTest$InnerClass)】 isSynthetic(): true
                  System.out.println("【" + declaredMethod + "】" + " isSynthetic(): " + declaredMethod.isSynthetic());
              }
          }
      }
      
    • 有关 synthetic 的相关内容,小伙伴可以看下这里

  • isBridge()

    • 判断该方法对象是否桥接方法,如果是则返回 true,否则为 false

    • 桥接方法: 是 JDK1.5 引入泛型后,为了使 Java 的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法

      public interface Interface<T> {
              
              
      
          T test(T t);
      }
      
      public class MethodTest implements Interface<String> {
              
              
      
          @Override
          public String test(String str) {
              
              
              return str;
          }
      
          public static void main(final String[] arguments) {
              
              
              Method[] declaredMethods = MethodTest.class.getDeclaredMethods();
              for (Method declaredMethod : declaredMethods) {
              
              
                  //【public static void lang.reflect.MethodTest.main(java.lang.String[])】 isBridge(): false
                  //【public java.lang.String lang.reflect.MethodTest.test(java.lang.String)】 isBridge(): false
                  //【public java.lang.Object lang.reflect.MethodTest.test(java.lang.Object)】 isBridge(): true
                  System.out.println("【" + declaredMethod + "】" + " isBridge(): " + declaredMethod.isBridge());
              }
          }
      }
      
    • 有关 bridge 的相关内容,小伙伴可以看下这里



Class – 11 – Math类常用方法解析

一、Math 类定义

  • Math 类位于 java.lang 包中,主要提供了一些常用的数学函数和计算

二、Math 类常用方法

  • 三角函数运算

    • Math.toDegrees(double angrad)

      • 将弧度转换为角度

        System.out.println(Math.toDegrees(1.5707963267948966)); // 90.0
        

    • Math.toRadians(double angdeg)

      • 将角度转换为弧度

        System.out.println(Math.toRadians(90)); // 1.5707963267948966
        

    • Math.sins(double a)

      • 计算正弦值

        // 先将30°转换为弧度,再计算其正弦值,30°的正弦值为0.5
        System.out.println(Math.sin(Math.toRadians(30))); // 0.49999999999999994约等于0.5
        

    • Math.asin(double a)

      • 计算反正弦值

        // 先求出值为0.5的反正弦值(弧度),再将弧度转换为角度
         System.out.println(Math.toDegrees(Math.asin(0.5))); // 30.000000000000004约等于30°
        

    • Math.cos(double a)

      • 计算余弦值

        // 先将60°转换为弧度,再计算其余弦值,60°的余弦值为0.5
        System.out.println(Math.cos(Math.toRadians(60))); // 0.5000000000000001约等于0.5
        

    • Math.acos(double a)

      • 计算反余弦值

        // 先求出值为0.5的反余弦值(弧度),再将弧度转换为角度
        System.out.println(Math.toDegrees(Math.acos(0.5))); // 60.00000000000001约等于60°
        

    • Math.tan(double a)

      • 计算正切值

      • 30°的正切值: $\frac{1}{\sqrt{3}}$

        // 先将30°转换为弧度,再计算其正切值
        System.out.println(Math.tan(Math.toRadians(30))); // 0.5773502691896257
        

    • Math.atan(double a)

      • 计算反正切值

        // 先求出值为0.5的反正切值(弧度),再将弧度转换为角度
        System.out.println(Math.toDegrees(Math.atan(0.5773502691896257))); // 29.999999999999996约等于30°
        

    • Math.sinh(double x)

      • 计算双曲正弦值

      • 双曲正弦值表达式:$\frac{e^x - e^{-x}}{2}$

        System.out.println(Math.sinh(1)); // 1.1752011936438014
        

    • Math.cosh(double x)

      • 计算双曲余弦值

      • 双曲余弦值表达式:$\frac{e^x + e^{-x}}{2}$

        System.out.println(Math.cosh(1)); // 1.543080634815244
        

    • Math.tanh(double x)

      • 计算双曲正切值

      • 双曲正切值表达式:$\frac{e^x - e^{-x}}{e^x + e^{-x}}$

        System.out.println(Math.tanh(1)); // 0.7615941559557649
        

    • Math.atan2(double y, double x)

      • 计算指定点与极坐标的弧度

      • 指定点的y轴坐标为$\sqrt{3}$,x 轴坐标为 1,其与 (0, 0) 所成的角度为 60°

        System.out.println(Math.toDegrees(Math.atan2(Math.sqrt(3), 1))) // 59.99999999999999约等于60°
        

  • 算术运算

    • Math.addExact(int x, int y)

      • 计算两参数之和,参数类型:int 或 long

        System.out.println(Math.addExact(1, 2)); // 3
        

    • Math.subtractExact(int x, int y)

      • 计算两参数之差(第一个参数 - 第二个参数),参数类型:int 或 long

        System.out.println(Math.subtractExact(3, 2)); // 1
        

    • Math.multiplyExact(int x, int y)

      • 计算两参数的乘积,参数类型:int 或 long

        System.out.println(Math.multiplyExact(2, 3)); // 6
        

    • Math.floorMod(int x, int y)

      • 计算两参数相除的余数(第一个参数 / 第二个参数),参数类型:int 或 long

        System.out.println(Math.floorMod(2, 3)); // 2
        

    • Math.floorDiv(int x, int y)

      • 计算小于或等于商的最大整数值,参数类型:int 或 long

        System.out.println(Math.floorDiv(4, 3)); // 1
        

    • Math.pow(double a, double b)

      • 计算 a 的 b 次幂,$a^b$

        System.out.println(Math.pow(2, 3)); // 8.0
        

    • Math.exp(double a)

      • 计算自然常数 e 的 a 次幂,$e^a$

        System.out.println(Math.exp(1)); // 2.718281828459045
        

    • Math.sqrt(double a)

      • 计算平方根,$\sqrt{a}$

        System.out.println(Math.sqrt(16)); // 4.0
        

    • Math.cbrt(double a)

      • 计算立方根,$\sqrt[3]{a}$

        System.out.println(Math.cbrt(8)); // 2.0
        

    • Math.hypot(double x, double y)

      • 计算两个参数平方和的平方根,$\sqrt{x^2 + y^2}$

        System.out.println(Math.hypot(6, 8)); // 10.0
        

    • Math.log(double x)

      • 计算以 e 为底的对数 (自然对数),$\log{e^x}$$\ln{x}$

        System.out.println(Math.log(Math.E)); // 1.0
        

    • Math.log10(double x)

      • 计算以 10 为底的对数,$\log{10^x}$$\lg{x}$

        System.out.println(Math.log10(100)); // 2.0
        

    • Math.log1p(double x)

      • 计算以 e 为底,1 与参数之和为指数的对数,$\log{e^{1 + x}}$$\ln{(1 + x)}$

        System.out.println(Math.log1p(Math.E - 1)); // 1.0
        

    • Math.expm1(double x)

      • 计算 e 的 x 次幂 - 1, $\log{e^x-1}$$\ln{x} - 1$

        System.out.println(Math.expm1(1) + 1); // 2.718281828459045
        

    • Math.scalb(float x, int y)

      • 计算 x 乘以 2 的 y 次幂,$x*2^y$

        System.out.println(Math.scalb(2, 3)); // 16.0
        

    • Math.IEEEremainder(double x, double y)

      • 按照 IEEE 754 标准的规定,对两个参数进行余数运算,余数的算术值等于 $x - y × n$

      • 其中 n 为最接近 $x/y$ 的商的整数

      • 如果两个整数同样接近,则选其中的偶数

      • 如果余数为 0,那么它的符号与第一个参数的符号相同

        System.out.println(Math.IEEEremainder(105, 10)); // 5.0
        System.out.println(Math.IEEEremainder(106, 10)); // -4.0
        

  • 取整运算

    • Math.ceil(double x)

      • 向上取整,返回大于该值的最近 double 值

        System.out.println(Math.ceil(1.23)); // 2.0
        System.out.println(Math.ceil(-1.23)); // -1.0
        

    • Math.floor(double x)

      • 向下取整,返回小于该值的最近 double 值

        System.out.println(Math.floor(1.23)); // 1.0
        System.out.println(Math.floor(-1.23)); // -2.0
        

    • Math.round(double x)

      • 四舍五入取整,参数类型:double、float

        System.out.println(Math.round(1.43)); // 1
        System.out.println(Math.round(1.53)); // 2
        System.out.println(Math.round(-1.43)); // -1
        System.out.println(Math.round(-1.53)); // -2
        

  • 随机运算

    • Math.random()

      • 内部调用了 Random.nextDouble() 方法,生成一个伪均匀分布在 0.0 到 1.0 之间的 double 值

        System.out.println((int)(Math.random() * 10 + 1)); // 生成范围再[1, 11)之间的伪随机数
        

  • 符号运算

    • Math.abs(int x)

      • 计算绝对值,参数类型:int、long、float、double

        System.out.println(Math.abs(-1)); // 1
        

    • Math.negateExact(int x)

      • 计算相反值,参数类型:int、long

        System.out.println(Math.negateExact(-1)); // 1
        

    • Math.signum(double x)

      • 如果参数为 0.0,则返回 0.0

      • 如果参数大于 0.0,则返回 1.0

      • 如果参数小于 0.0,则返回 -1.0

      • 参数类型:float、double

        System.out.println(Math.signum(0.1)); // 1.0
        System.out.println(Math.signum(0.0)); // 0.0
        System.out.println(Math.signum(-0.1)); // -1.0
        

    • Math.copySign(double magnitude, double sign)

      • 获取带有第二个浮点参数符号的第一个浮点参数,参数类型:(double, double)、(float, float)

        System.out.println(Math.copySign(1.1, -0.1)); // -1.1
        

  • 大小运算

    • Math.max(int x, int y)

      • 获取两个参数中的最大值,参数类型:int、long、float、double

        System.out.println(Math.max(1, 2)); // 2
        

    • Math.min(int x, int y)

      • 获取两个参数中的最小值,参数类型:int、long、float、double

        System.out.println(Math.min(1, 2)); // 1
        

    • Math.decrementExact(int x)

      • 获取该参数递减之后的数,参数类型:int、long

        System.out.println(Math.decrementExact(2)); // 1
        

    • Math.incrementExact(int x)

      • 获取该参数递增之后的数,参数类型:int、long

        System.out.println(Math.incrementExact(1)); // 2
        

    • Math.nextUp(double x)

      • 获取比参数略大的相邻浮点数,参数类型:float、double

        System.out.println(Math.nextUp(1.1)); // 1.1000000000000003
        

    • Math.nextDown(double x)

      • 获取比参数略小的相邻浮点数,参数类型:float、double

        System.out.println(Math.nextDown(1.1)); // 1.0999999999999999
        

    • Math.nextAfter(double start, double direction)

      • 获取第一个参数和第二个参数之间与第一个参数相邻的浮点数,参数类型:(double, double)、(float, double)

        System.out.println(Math.nextAfter(1.2, 1.3)); // 1.2000000000000002
        

    • Math.rint(double x)

      • 获取与参数最接近的double值

        System.out.println(Math.rint(1.4)); // 1.0
        System.out.println(Math.rint(1.5)); // 2.0
        System.out.println(Math.rint(-1.4)); // -1.0
        System.out.println(Math.rint(-1.5)); // -2.0
        

  • 其他运算

    • Math.ulp(double x)

      • 获取参数的 ulp 值,ulp 值是该浮点值与下一个数值较大的浮点值之间的正距离,参数类型:float、double

        System.out.println(Math.ulp(0.1)); // 1.3877787807814457E-17
        

    • Math.getExponent(double x)

      • 获取在表示浮点数时使用的无偏指数,参数类型:float、double

        System.out.println(Math.getExponent(1024)); // 10
        


Class – 12 – Locale类常用方法解析

一、Locale 类定义

  • Locale 类位于 java.util 包中,主要用于语言的国际化
  • Locale 表示语言环境,每一个 Locale 对象都代表了一个特定的地理、政治或文化区域
  • Locale 类提供了三种方式来获取 Locale 对象
    • 使用 Locale.getDefault() 方法
      • 获取默认 Locale
    • 使用 Locale 类提供的静态对象
      • 如:Locale.CHINA
    • 使用构造方法
      • Locale(String language)
      • Locale(String language, String country)
      • Locale(String language, String country, String variant)

二、Locale 类常用方法

  • 实例方法

    • getLanguage()

      • 获取当前 Locale 的语言代码

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getLanguage()); // zh
        

    • getCountry()

      • 获取当前 Locale 的国家/地区代码

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getCountry()); // CN
        

    • getScript()

      • 获取当前 Locale 的脚本

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getScript()); // ""
        

    • getVariant()

      • 获取当前 Locale 的语言变体 (可以理解为方言,如:粤语 (yue))

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getVariant()); // yue
        

    • getDisplayLanguage()

      • 获取适合展示给用户的 Locale 语言名称

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayLanguage()); // 中文
        
    • getDisplayLanguage(Locale inLocale)

      • inLocale

        • 需要展示的 Locale
      • 获取适合展示给用户的 Locale 语言名称,并根据 inLocale 进行本地化

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayLanguage(Locale.CHINA)); // 中文
        System.out.println(locale.getDisplayLanguage(Locale.US)); // Chinese
        

    • getDisplayCountry()

      • 获取适合展示给用户的 Locale 国家/地区名称

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayCountry()); // 中国
        
    • getDisplayCountry(Locale inLocale)

      • inLocale

        • 需要展示的 Locale
      • 获取适合展示给用户的 Locale 国家/地区名称,并根据 inLocale 进行本地化

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayCountry(Locale.CHINA)); // 中国
        System.out.println(locale.getDisplayCountry(Locale.US)); // China
        

    • getDisplayScript()

      • 获取适合展示给用户的 Locale 脚本名称

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayScript()); // ""
        
    • getDisplayScript(Locale inLocale)

      • inLocale

        • 需要展示的 Locale
      • 获取适合展示给用户的 Locale 脚本名称,并根据 inLocale 进行本地化

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayScript(Locale.CHINA)); // ""
        System.out.println(locale.getDisplayScript(Locale.US)); // ""
        

    • getDisplayVariant()

      • 获取适合展示给用户的 Locale 语言变体名称 (可以理解为方言)

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayVariant()); // yue
        
    • getDisplayVariant(Locale inLocale)

      • inLocale

        • 需要展示的 Locale
      • 获取适合展示给用户的 Locale 语言变体名称 (可以理解为方言),并根据 inLocale 进行本地化

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayVariant(Locale.CHINA)); // yue
        System.out.println(locale.getDisplayVariant(Locale.US)); // yue
        

    • getDisplayName()

      • 获取适合展示给用户的 Locale 名称

      • 是 getDisplayLanguage()、getDisplayScript()、getDisplayCountry()、getDisplayVariant() 四个方法返回值组成的一个字符串

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayName()); // 中文 (中国,yue)
        
    • getDisplayName(Locale inLocale)

      • inLocale

        • 需要展示的 Locale
      • 获取适合展示给用户的 Locale 名称,并根据 inLocale 进行本地化

      • 是 getDisplayLanguage()、getDisplayScript()、getDisplayCountry()、getDisplayVariant() 四个方法返回值组成的一个字符串

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getDisplayName(Locale.CHINA)); // 中文 (中国,yue)
        System.out.println(locale.getDisplayName(Locale.US)); // Chinese (China,yue)
        

    • getISO3Country()

      • 获取当前 Locale 的国家/地区代码的三字母缩写 (多用于国际上的正式场合)

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getISO3Country()); // CHN
        

    • getISO3Language()

      • 获取当前 Locale 的语言代码的三字母缩写 (多用于国际上的正式场合)

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getISO3Language()); // zho
        

    • stripExtensions()

      • 获取当前 Locale 不带扩展的副本

      • 如果当前 Locale 没有扩展名,则返回此 Locale

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.stripExtensions()); // zh_CN_yue
        

    • toLanguageTag()

      • 获取当前 Locale 设置的格式完好的语言标记

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.toLanguageTag()); // zh-CN-x-lvariant-yue
        

    • hasExtensions()

      • 如果当前 Locale 带有扩展,则返回 true;否则返回 false

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.hasExtensions()); // false
        

    • getExtensionKeys()

      • 获取与当前 Locale 相关联的扩展键值集

      • 如果当前 Locale 不带有扩展,则返回空的扩展键值集 (返回的集合是不可修改的,且键值都是小写的)

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getExtensionKeys()); // []
        

    • getUnicodeLocaleKeys()

      • 获取与当前 Locale 相关联的 Unicode 语言环境键值集

      • 如果当前 Locale 没有,则返回空的 Unicode 语言环境键值集 (返回的集合是不可修改的,且键值都是小写的)

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getUnicodeLocaleKeys()); // []
        

    • getUnicodeLocaleAttributes()

      • 获取与当前 Locale 相关联的 Unicode 语言环境属性集

      • 如果当前 Locale 没有,则返回空的 Unicode 语言环境属性集 (返回的集合是不可修改的)

        Locale locale = new Locale("zh", "CN", "yue");
        System.out.println(locale.getUnicodeLocaleAttributes()); // []
        

    • getExtension(char key)

      • key

        • 扩展的 key 值
      • 获取与当前 Locale 相关联的指定 key 值的扩展

      • 如果没有与该 key 值相关联的扩展,则返回 null

      • 为了格式整齐, key 值不区分大小写,且必须从 [0-9A-Za-z] 中取值

        Locale locale = new Locale("zh", "CN", "yue");
        locale.getExtension('A'); // ""
        

    • getUnicodeLocaleType(String key)

      • key

        • Unicode Locale 的 key 值
      • 获取与当前 Locale 相关联的指定 key 值的 Unicode 语言环境类型

      • 若果 key 值未定义,则返回 null

      • 为了格式整齐, key 值为两个字符,不区分大小写,且必须从 [0-9A-Za-z] 中取值

        Locale locale = new Locale("zh", "CN", "yue");
        locale.getUnicodeLocaleType("AA"); // ""
        

  • 静态方法

    • Locale.getDefault()

      • 获取默认 Locale

        System.out.println(Locale.getDefault()); // zh_CN
        

    • setDefault(Locale newLocale)

      • newLocale

        • 新的默认 Locale
      • 设置默认 Locale

        Locale.setDefault(new Locale("zh", "CN", "yue"));
        System.out.println(Locale.getDefault()); // zh_CN_yue
        

    • Locale.getAvailableLocales()

      • 获取所有可获得的 Locale

        System.out.println(Arrays.toString(Locale.getAvailableLocales()));
        
        // [, ar_AE, ar_JO, ar_SY, hr_HR, fr_BE, es_PA, mt_MT, es_VE, bg, zh_TW, it, ko, 
        // uk, lv, da_DK, es_PR, vi_VN, en_US, sr_ME, sv_SE, es_BO, en_SG, ar_BH, pt, 
        // ar_SA, sk, ar_YE, hi_IN, ga, en_MT, fi_FI, et, sv, cs, sr_BA_#Latn, el, uk_UA,
        // hu, fr_CH, in, es_AR, ar_EG, ja_JP_JP_#u-ca-japanese, es_SV, pt_BR, be,
        // is_IS, cs_CZ, es, pl_PL, tr, ca_ES, sr_CS, ms_MY, hr, lt, es_ES, es_CO, bg_BG, 
        // sq, fr, ja, sr_BA, is, es_PY, de, es_EC, es_US, ar_SD, en, ro_RO, en_PH, 
        // ca, ar_TN, sr_ME_#Latn, es_GT, sl, ko_KR, el_CY, es_MX, ru_RU, es_HN, zh_HK, 
        // no_NO_NY, hu_HU, th_TH, ar_IQ, es_CL, fi, ar_MA, ga_IE, mk, tr_TR, et_EE,
        // ar_QA, sr__#Latn, pt_PT, fr_LU, ar_OM, th, sq_AL, es_DO, es_CU, ar, ru, en_NZ, 
        // sr_RS, de_CH, es_UY, ms, el_GR, iw_IL, en_ZA, th_TH_TH_#u-nu-thai, hi,
        // fr_FR, de_AT, nl, no_NO, en_AU, vi, nl_NL, fr_CA, lv_LV, de_LU, es_CR, ar_KW, 
        // sr, ar_LY, mt, it_CH, da, de_DE, ar_DZ, sk_SK, lt_LT, it_IT, en_IE, zh_SG, 
        // ro, en_CA, nl_BE, no, pl, zh_CN, ja_JP, de_GR, sr_RS_#Latn, iw, en_IN, ar_LB, 
        // es_NI, zh, mk_MK, be_BY, sl_SI, es_PE, in_ID, en_GB]
        

    • Locale.getISOCountries()

      • 获取 ISO 3166 标准中定义的所有国家/地区代码

        System.out.println(Arrays.toString(Locale.getISOCountries()));
        
        // [AD, AE, AF, AG, AI, AL, AM, AN, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, 
        // BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BY, BZ, CA, CC, CD, 
        // CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, 
        // DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, 
        // GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, 
        // IM, IN, IO, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KP, KR, KW, KY, 
        // KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, 
        // MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, 
        // NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, 
        // RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, SS, 
        // ST, SV, SX, SY, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TR, TT, TV, TW, TZ, 
        // UA, UG, UM, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, YE, YT, ZA, ZM, ZW]
        

    • Locale.getISOLanguages()

      • 获取 ISO 639 标准中定义的所有语言代码

        // [aa, ab, ae, af, ak, am, an, ar, as, av, ay, az, ba, be, bg, bh, bi, bm, bn, bo, br, 
        // bs, ca, ce, ch, co, cr, cs, cu, cv, cy, da, de, dv, dz, ee, el, en, eo, es, et, eu, fa, 
        // ff, fi, fj, fo, fr, fy, ga, gd, gl, gn, gu, gv, ha, he, hi, ho, hr, ht, hu, hy, hz, ia, 
        // id, ie, ig, ii, ik, in, io, is, it, iu, iw, ja, ji, jv, ka, kg, ki, kj, kk, kl, km, kn, 
        // ko, kr, ks, ku, kv, kw, ky, la, lb, lg, li, ln, lo, lt, lu, lv, mg, mh, mi, mk, ml, mn, 
        // mo, mr, ms, mt, my, na, nb, nd, ne, ng, nl, nn, no, nr, nv, ny, oc, oj, om, or, os, pa, 
        // pi, pl, ps, pt, qu, rm, rn, ro, ru, rw, sa, sc, sd, se, sg, si, sk, sl, sm, sn, so, sq, 
        // sr, ss, st, su, sv, sw, ta, te, tg, th, ti, tk, tl, tn, to, tr, ts, tt, tw, ty, ug, uk, 
        // ur, uz, ve, vi, vo, wa, wo, xh, yi, yo, za, zh, zu]
        

    • Locale.filter(List priorityList, Collection locales)

      • priorityList

        • 用户的语言优先级列表,其中每个语言标记根据优先级降序排序
      • locales

        • 用于匹配的 Locale 实例列表
      • 根据 RFC 4647 标准中定义的过滤机制筛选出匹配的 Locale 实例列表

      • 其底层调用了 filter(priorityList, locales, FilteringMode.AUTOSELECT_FILTERING) 方法

        String ranges = "zh-CN;q=0.2, ja-JP;q=0.4, en-US;q=0.6";
        List<Locale.LanguageRange> priorityList = Locale.LanguageRange.parse(ranges);
        List<Locale> locales = Arrays.asList(new Locale("zh", "CN"), new Locale("en", "US"));
        List<Locale> filter = Locale.filter(priorityList, locales);
        System.out.println(filter); // [en_US, zh_CN]
        
    • Locale.filter(List priorityList, Collection locales, FilteringMode mode)

      • priorityList

        • 用户的语言优先级列表,其中每个语言标记根据优先级降序排序
      • locales

        • 用于匹配的 Locale 实例列表
      • mode

        • 过滤模式

          名称 作用
          AUTOSELECT_FILTERING 基于给定 Locale 列表的自动过滤模式
          EXTENDED_FILTERING 扩展过滤模式
          IGNORE_EXTENDED_RANGES 指定过滤模式,将忽略给定 Locale 列表中包含的扩展语言范围
          MAP_EXTENDED_RANGES 指定过滤模式,如果给定的 Locale 列表中包含扩展语言范围, 则将其映射到基本语言范围
          REJECT_EXTENDED_RANGES 指定过滤模式,如果给定的 Locale 列表中包含扩展语言范围, 则拒绝该列表,并抛出异常
      • 根据 RFC 4647 标准中定义的过滤机制筛选出匹配的 Locale 实例列表

        String ranges = "zh-CN;q=0.2, ja-JP;q=0.4, en-US;q=0.6";
        List<Locale.LanguageRange> priorityList = Locale.LanguageRange.parse(ranges);
        List<Locale> locales = Arrays.asList(new Locale("zh", "CN"), new Locale("en", "US"));
        List<Locale> filter = Locale.filter(priorityList, locales, Locale.FilteringMode.AUTOSELECT_FILTERING);
        System.out.println(filter); // [en_US, zh_CN]
        

    • Locale.filterTags(List priorityList, Collection tags)

      • priorityList

        • 用户的语言优先级列表,其中每个语言标记根据优先级降序排序
      • tags

        • 用于匹配的语言标记列表
      • 根据 RFC 4647 标准中定义的过滤机制筛选出匹配的语言标记列表

      • 其底层调用了 filterTags(priorityList, tags, FilteringMode.AUTOSELECT_FILTERING) 方法

        String ranges = "zh-CN;q=0.2, ja-JP;q=0.4, en-US;q=0.6";
        List<Locale.LanguageRange> priorityList = Locale.LanguageRange.parse(ranges);
        List<String> tags = Arrays.asList("zh-CN", "en-US");
        List<String> filterTags = Locale.filterTags(priorityList, tags);
        System.out.println(filterTags); // [en-us, zh-cn]
        
    • Locale.filterTags(List priorityList, Collection tags, FilteringMode mode)

      • priorityList

        • 用户的语言优先级列表,其中每个语言标记根据优先级降序排序
      • tags

        • 用于匹配的语言标记列表
      • mode

        • 过滤模式
      • 根据 RFC 4647 标准中定义的过滤机制筛选出匹配的语言标记列表

        String ranges = "zh-CN;q=0.2, ja-JP;q=0.4, en-US;q=0.6";
        List<Locale.LanguageRange> priorityList = Locale.LanguageRange.parse(ranges);
        List<String> tags = Arrays.asList("zh-CN", "en-US");
        List<String> filterTags = Locale.filterTags(priorityList, tags, Locale.FilteringMode.AUTOSELECT_FILTERING);
        System.out.println(filterTags); // [en-us, zh-cn]
        

    • Locale.lookup(List priorityList, Collection locales)

      • priorityList

        • 用户的语言优先级列表,其中每个语言标记根据优先级降序排序
      • locales

        • 用于匹配的 Locale 实例列表
      • 根据 RFC 4647 标准中定义的查找机制返回最佳匹配的 Locale 实例

        String ranges = "zh-CN;q=0.2, ja-JP;q=0.4, en-US;q=0.6";
        List<Locale.LanguageRange> priorityList = Locale.LanguageRange.parse(ranges);
        List<Locale> locales = Arrays.asList(new Locale("zh", "CN"), new Locale("en", "US"));
        Locale lookup = Locale.lookup(priorityList, locales);
        System.out.println(lookup); // en_US
        

    • Locale.lookupTag(List priorityList, Collection tags)

      • priorityList

        • 用户的语言优先级列表,其中每个语言标记根据优先级降序排序
      • tags

        • 用于匹配的语言标记列表
      • 根据 RFC 4647 标准中定义的查找机制返回最佳匹配的语言标记

        String ranges = "zh-CN;q=0.2, ja-JP;q=0.4, en-US;q=0.6";
        List<Locale.LanguageRange> priorityList = Locale.LanguageRange.parse(ranges);
        List<String> tags = Arrays.asList("zh-CN", "en-US");
        String tag = Locale.lookupTag(priorityList, tags);
        System.out.println(tag); // en-us
        

    • Locale.forLanguageTag(String languageTag)

      • languageTag

        • 语言标记
      • 根据 IETF BCP 47 标准获取指定语言标记代表的 Locale

        Locale locale = Locale.forLanguageTag("zh-CN-x-lvariant-yue");
        System.out.println(locale); // zh_CN_yue
        

三、参考资料



Class – 13 – ThreadPoolExecutor类常用方法解析

一、ThreadPoolExecutor 类定义

  • ThreadPoolExecutor 类位于 java.util.concurrent 包中,主要用于创建线程池

  • ThreadPoolExecutor 类提供四个构造函数来实例化 ThreadPoolExecutor 对象

    ThreadPoolExecutor(int corePoolSize,
                       int maximumPoolSize,
                       long keepAliveTime,
                       TimeUnit unit,
                       BlockingQueue<Runnable> workQueue)
    
    ThreadPoolExecutor(int corePoolSize,
                       int maximumPoolSize,
                       long keepAliveTime,
                       TimeUnit unit,
                       BlockingQueue<Runnable> workQueue,
                       ThreadFactory threadFactory)
    
    ThreadPoolExecutor(int corePoolSize,
                       int maximumPoolSize,
                       long keepAliveTime,
                       TimeUnit unit,
                       BlockingQueue<Runnable> workQueue,
                       RejectedExecutionHandler handler)
    
    ThreadPoolExecutor(int corePoolSize,
                       int maximumPoolSize,
                       long keepAliveTime,
                       TimeUnit unit,
                       BlockingQueue<Runnable> workQueue,
                       ThreadFactory threadFactory,
                       RejectedExecutionHandler handler)
    
    • 由源码可知,前面三个构造函数内部都是调用第四个构造函数来实现的

    • 构造函数七个参数含义如下

      参数名 含义
      corePoolSize 核心线程数
      maximumPoolSize 最大线程数
      keepAliveTime 非核心线程的最大存活时间
      unit keepAliveTime 参数的时间单位
      workQueue 工作队列
      threadFactory 线程创建工厂
      handler 线程拒绝策略
  • ThreadPoolExecutor 类包含四个线程拒绝策略

    拒绝策略 含义
    AbortPolicy 直接丢弃任务,抛出异常 (默认策略)
    CallerRunsPolicy 将任务分配给调用线程来执行
    DiscardPolicy 直接丢弃任务,不抛出异常
    DiscardOldestPolicy 丢弃队列中最早的任务,不抛出异常

二、ThreadPoolExecutor 类常用方法

创建一个线程池,用于下面例子调用

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10, 
    TimeUnit.SECONDS, new LinkedBlockingQueue<>(10),  
    Executors.defaultThreadFactory(),  new ThreadPoolExecutor.AbortPolicy());

  • getPoolSize()

    • 获取线程池中当前的线程数

      executor.execute(() -> System.out.println("Hello World"));
      System.out.println(executor.getPoolSize()); // 1
      executor.shutdown();
      

  • getLargestPoolSize()

    • 获取线程池中同时存在的最大线程数

    • largestPoolSize <= maximunPoolSize

      executor.execute(() -> System.out.println("Hello World"));
      System.out.println(executor.getLargestPoolSize()); // 1
      executor.shutdown();
      

  • getCorePoolSize()

    • 获取核心线程数

      System.out.println(executor.getCorePoolSize()); // 5
      

  • setCorePoolSize(int corePoolSize)

    • 设置核心线程数

      executor.setCorePoolSize(10);
      System.out.println(executor.getCorePoolSize()); // 10
      

  • getMaximumPoolSize()

    • 获取最大线程数

      System.out.println(executor.getMaximumPoolSize()); // 10
      

  • setMaximumPoolSize(int maximumPoolSize)

    • 设置最大线程数

      executor.setMaximumPoolSize(20);
      System.out.println(executor.getMaximumPoolSize()); // 20
      

  • getKeepAliveTime(TimeUnit unit)

    • 获取线程最大存活时间 (该线程指的是非核心线程)

      System.out.println(executor.getKeepAliveTime(TimeUnit.SECONDS)); // 10
      

  • setKeepAliveTime(long time, TimeUnit unit)

    • 设置线程最大存活时间 (该线程指的是非核心线程)

      executor.setKeepAliveTime(20, TimeUnit.SECONDS);
      System.out.println(executor.getKeepAliveTime(TimeUnit.SECONDS)); // 20
      

  • getQueue()

    • 获取工作队列

    • 当线程数大于核心线程数且小于最大线程数时,提交的新任务会放入到队列中

      • 此种情况,当前线程数为 5,小于等于核心线程数,因此不会有任务放入到队列中

        IntStream.range(0, 5).forEach(i -> 
            executor.execute(() -> System.out.println("Hello World")));
        System.out.println(executor.getQueue());
        executor.shutdown();
        // Hello World
        // Hello World
        // Hello World
        // Hello World
        // Hello World
        // []
        
      • 此种情况,当前线程数为 6,大于核心线程数,因此会有任务放入到队列中

        IntStream.range(0, 6).forEach(i -> 
            executor.execute(() -> System.out.println("Hello World")));
        System.out.println(executor.getQueue());
        executor.shutdown();
        // Hello World
        // Hello World
        // Hello World
        // Hello World
        // Hello World
        // Hello World
        // [clazz.ThreadPoolExecutorTest$$Lambda$2/1023892928@4dd8dc3]
        

  • getThreadFactory()

    • 获取线程创建工厂

      System.out.println(executor.getThreadFactory()); 
      // java.util.concurrent.Executors$DefaultThreadFactory@3d075dc0
      

  • setThreadFactory(ThreadFactory threadFactory)

    • 设置线程创建工厂

      executor.setThreadFactory(Executors.defaultThreadFactory());
      System.out.println(executor.getThreadFactory()); 
      // java.util.concurrent.Executors$DefaultThreadFactory@682a0b20
      

  • getRejectedExecutionHandler()

    • 获取线程拒绝策略

      System.out.println(executor.getRejectedExecutionHandler()); 
      // java.util.concurrent.ThreadPoolExecutor$AbortPolicy@214c265e
      

  • setRejectedExecutionHandler(RejectedExecutionHandler handler)

    • 设置线程拒绝策略

      executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
      System.out.println(executor.getRejectedExecutionHandler()); 
      // java.util.concurrent.ThreadPoolExecutor$DiscardPolicy@682a0b20
      

  • getActiveCount()

    • 获取正在执行任务的大致线程数

      executor.execute(() -> System.out.println("Hello World"));
      System.out.println(executor.getActiveCount()); // 1
      executor.shutdown();
      

  • getTaskCount()

    • 获取已安排执行的大致任务总数

    • 因为任务和线程的状态可能在计算期间动态改变,所以获取到的只是近似值

      executor.execute(() -> System.out.println("Hello World"));
      System.out.println(executor.getTaskCount()); // 1
      executor.shutdown();
      123
      
      

  • getCompletedTaskCount()

    • 获取已完成执行的大致任务总数

    • 因为任务和线程的状态可能在计算期间动态改变,所以获取到的只是近似值

      executor.execute(() -> System.out.println("Hello World"));
      System.out.println(executor.getCompletedTaskCount()); // 1
      executor.shutdown();
      

  • execute(Runnable command)

    • 执行给定的 Runnable 任务

      executor.execute(() -> System.out.println("Hello World")); // Hello World
      executor.shutdown();
      

  • submit(Runnable task)

    • 提交给定的 Runnable 任务进行执行,在任务执行完成后,返回相应的 Future

    • Future 的 get() 方法会在任务执行完成后返回 null

      Future<?> submit1 = executor.submit(() -> System.out.println("Hello World"));
      System.out.println(submit1.get()); // null
      executor.shutdown();
      
  • submit(Callable task)

    • 提交给定的 Callable 任务进行执行,在任务执行完成后,返回相应的 Future

    • Future 的 get() 方法会在任务执行完成后返回任务结果

      Future<Object> submit2 = executor.submit(() -> "Hello World");
      System.out.println(submit2.get()); // Hello World
      executor.shutdown();
      
  • submit(Runnable task, T result)

    • 提交给定的 Runnable 任务进行执行,在任务执行完成后,返回相应的 Future

    • Future 的 get() 方法会在任务执行完成后返回给定的任务结果

      Future<String> submit = executor.submit(() -> System.out.println("Hello World"), "result");
      System.out.println(submit.get()); // result
      executor.shutdown();
      

  • invokeAll(Collection tasks)

    • 执行给定的 Callable 任务列表,在所有任务执行完成后,返回相应的 Future 列表

    • Future 的 get() 方法会在任务执行完成后返回给定的任务结果

      Callable<String> task1 = () -> "Hello World1";
      Callable<String> task2 = () -> "Hello World2";
      List<Callable<String>> callableList = Arrays.asList(task1, task2);
      List<Future<String>> futureList = executor.invokeAll(callableList);
      for (Future<String> future : futureList) {
              
              
          System.out.println(future.get());
      }
      executor.shutdown();
      
      // Hello World1
      // Hello World2
      
  • invokeAll(Collection tasks, long timeout, TimeUnit unit)

    • 执行给定的 Callable 任务列表,在所有任务执行完成后,返回相应的 Future 列表

    • 针对所有任务,进行了超时时间控制,如果超时,会取消所有没有未完成的任务,并抛出 CancellationException 异常

      Callable<String> task1 = () -> "Hello World1";
      Callable<String> task2 = () -> {
              
              
          TimeUnit.SECONDS.sleep(2);
          return "Hello World2";
      };
      List<Callable<String>> callableList = Arrays.asList(task1, task2);
      List<Future<String>> futureList = executor.invokeAll(callableList, 1, TimeUnit.SECONDS);
      for (Future<String> future : futureList) {
              
              
          System.out.println(future.get());
      }
      executor.shutdown();
      
      // Hello World1
      // Exception in thread "main" java.util.concurrent.CancellationException
      // 	at java.util.concurrent.FutureTask.report(FutureTask.java:121)
      // 	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
      // 	at clazz.ThreadPoolExecutorTest.main(ThreadPoolExecutorTest.java:55)
      

  • invokeAny(Collection tasks)

    • 执行给定的任务列表,在有一个任务成功执行完成后,就会返回相应的任务结果,其余任务会被取消

      Callable<String> task1 = () -> "Hello World1";
      Callable<String> task2 = () -> "Hello World2";
      List<Callable<String>> callableList = Arrays.asList(task1, task2);
      String result = executor.invokeAny(callableList);
      System.out.println(result); // Hello World1
      executor.shutdown();
      
  • invokeAny(Collection tasks, long timeout, TimeUnit unit)

    • 执行给定的任务列表,在有一个任务成功执行完成后,就会返回相应的任务结果

    • 针对所有任务,进行了超时时间控制,如果超时,会取消超时任务,直到有任务成功执行为止

    • 如果所有任务都超时,则会抛出 TimeoutException 异常

      Callable<String> task1 = () -> {
              
              
          TimeUnit.SECONDS.sleep(2);
          return "Hello World1";
      };
      Callable<String> task2 = () -> "Hello World2";
      List<Callable<String>> callableList = Arrays.asList(task1, task2);
      String result = executor.invokeAny(callableList, 1, TimeUnit.SECONDS);
      System.out.println(result); // Hello World2
      executor.shutdown();
      
      Callable<String> task1 = () -> {
              
              
      TimeUnit.SECONDS.sleep(2);
      return "Hello World1";
      };
      Callable<String> task2 = () -> {
              
              
      TimeUnit.SECONDS.sleep(2);
      return "Hello World2";
      };
      List<Callable<String>> callableList = Arrays.asList(task1, task2);
      String result = executor.invokeAny(callableList, 1, TimeUnit.SECONDS);
      System.out.println(result);
      executor.shutdown();
      
      // Exception in thread "main" java.util.concurrent.TimeoutException
      // 	at java.util.concurrent.AbstractExecutorService.doInvokeAny(AbstractExecutorService.java:184)
      // 	at java.util.concurrent.AbstractExecutorService.invokeAny(AbstractExecutorService.java:225)
      // 	at clazz.ThreadPoolExecutorTest.main(ThreadPoolExecutorTest.java:75)
      

  • isShutdown()

    • 如果线程池已关闭,则返回 true;否则返回 false

      executor.execute(() -> System.out.println("Hello World"));
      executor.shutdown();
      System.out.println(executor.isShutdown()); // true
      

  • isTerminated()

    • 如果在线程池关闭后,所有任务都已完成,则返回 true;否则返回 false

    • 此外,除非先调用 shutdown() 方法 或 shutdownDown() 方法,否则 isTerminated() 永远为 false

      • 此种情况,执行 execute() 方法的线程晚于主线程执行完毕,因此 isTerminated() 方法返回 false

        executor.execute(() -> System.out.println("Hello World"));
        executor.shutdown();
        System.out.println(executor.isTerminated()); // false
        
      • 此种情况,让主线程休眠 100 ms,使执行 execute() 方法的线程先执行完毕,因此 isTerminated() 方法返回 true

        executor.execute(() -> System.out.println("Hello World"));
        executor.shutdown();
        TimeUnit.MILLISECONDS.sleep(100);
        System.out.println(executor.isTerminated()); // true
        

  • isTerminating()

    • 如果线程池在执行了 shutdown() 方法或 shutdownNow() 方法后,尚有任务未执行完成,则返回 true;否则返回 false

      • 此种情况,执行 execute() 方法的线程晚于主线程执行完毕,因此 isTerminating() 方法返回 true

        executor.execute(() -> System.out.println("Hello World"));
        executor.shutdown();
        System.out.println(executor.isTerminating()); // true
        
      • 此种情况,让主线程休眠 100 ms,使执行 execute() 方法的线程先执行完毕,因此 isTerminating() 方法返回 false

        executor.execute(() -> System.out.println("Hello World"));
        executor.shutdown();
        TimeUnit.MILLISECONDS.sleep(100);
        System.out.println(executor.isTerminating()); // false
        

  • shutdown()
    • 关闭线程池
    • 正在执行的任务会继续执行,尚未执行的任务不再处理

  • shutdownNow()
    • 立刻关闭线程池
    • 中止所有正在执行的任务,尚未执行的任务不再处理

  • prestartCoreThread()

    • 启动一个核心线程,使其等待执行任务,返回 true

    • 此方法会覆盖在执行新任务时,启动核心线程的默认策略

    • 如果所有核心线程均已启动,则调用此方法会返回 false

      System.out.println(executor.prestartCoreThread()); // ture
      System.out.println(executor.getPoolSize()); // 1
      executor.shutdown();
      
      IntStream.range(0, 5).forEach(i -> executor.execute(() -> System.out.println("Hello World")));
      System.out.println(executor.prestartCoreThread()); // false
      System.out.println(executor.getPoolSize()); // 5
      executor.shutdown();
      

  • prestartAllCoreThreads()

    • 启动所有核心线程,使其等待执行任务

    • 此方法会覆盖在执行新任务时,启动核心线程的默认策略

      System.out.println(executor.prestartAllCoreThreads()); // 5
      System.out.println(executor.getPoolSize()); // 5
      executor.shutdown();
      

  • allowCoreThreadTimeOut(boolean value)

    • 设置是否允许核心线程超时

      executor.prestartAllCoreThreads();
      executor.allowCoreThreadTimeOut(true);
      System.out.println(executor.getPoolSize()); // 5
      TimeUnit.SECONDS.sleep(15);
      System.out.println(executor.getPoolSize()); // 0
      

  • allowsCoreThreadTimeOut()

    • 获取核心线程是否可以超时的标识

      executor.allowCoreThreadTimeOut(true);
      System.out.println(executor.allowsCoreThreadTimeOut()); // true
      
      executor.allowCoreThreadTimeOut(false);
      System.out.println(executor.allowsCoreThreadTimeOut()); // false
      
      

  • awaitTermination(long timeout, TimeUnit unit)

    • 设置超时时间,当线程池关闭后,阻塞主线程直到所有任务都执行完毕,或者超时

      • 此种情况,任务执行完毕时间小于超时时间,即所有线程都已执行完毕,返回 true

        executor.execute(() -> {
                  
                  
            try {
                  
                  
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                  
                  
                e.printStackTrace();
            }
            System.out.println("Hello World");
        });
        executor.shutdown();
        System.out.println(executor.awaitTermination(3, TimeUnit.SECONDS)); // true
        
      • 此种情况,任务执行完毕时间大于超时时间,即尚有线程未执行完毕,返回 false

        executor.execute(() -> {
                  
                  
            try {
                  
                  
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                  
                  
                e.printStackTrace();
            }
            System.out.println("Hello World");
        });
        executor.shutdown();
        System.out.println(executor.awaitTermination(3, TimeUnit.SECONDS)); // false
        

猜你喜欢

转载自blog.csdn.net/qq_43842093/article/details/131349291