hualonghongyan 发表于 2021-5-8 09:58

Java常用类笔记

# 一、前言

这篇技术博客是JavaSE教程做的笔记总结,方便大家的学习同时也方便自己。

# 二、String类

## 1.理解String的不可变性

String:字符串,使用""引起来表示

1. String声明为final的,不能被继承
2. String实现了Serializable接口:表示字符串是**支持序列化**的
实现了Comparable接口:表示String可以比较大小
3. String在内部定义了final char[] value用于存储字符串数据
4. String:**代表不可变的字符序列**。简称:不可变性。(只要对字符串内容进行任何修改,都必须重新造!)

```
体现:
   1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
   2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能在原有的value上进行赋值
   3.当调用String的replace()修改指定字符或字符串时,也需要重新指定内存区域赋值
```

5. 通过字面量的方式(区别于new)给一个字符串赋值,此时的**字符串值声明在字符串常量池**中
6. 字符串常量池中是**不会存储相同内容**的字符串的。

图解如下:

https://bbs.leyuz.net/uploads/remote/202102/6c9f996a73f2471de70359ccc71b0159.png

附加:JVM中字**符串常量池存放位置**说明

```
JDK1.6:字符串常量池存储在方法区(永久区)
JDK1.7:字符串常量池存储在堆空间
JDK1.8:字符串常量池存储在方法区(元空间)
```

## 2.String不同实例化方式对比

String共有**两种**实例化的方式:

1. 通过字面量定义的方式
2. 通过new + 构造器方式

```
/** * 面试题:String s = new String("abc");方式创建对象,在内存中创建了几个对象? *       两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc" */
public class StringTest {
    @test    public void test1(){
      //此时的s1和s2数据声明在方法区中的字符串常量池中
      String s1 = "abc";
      String s2 = "abc";

      //new + 构造器方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间后对应的地址值
      String s3 = new String("abc");
      String s4 = new String("abc");

      System.out.println(s1 == s2); //true 因为字符串常量存储在方法区的常量池中,是唯一的(共享)
      System.out.println(s1 == s3); //false s1指向常量池中的地址,s3指向堆空间地址
      System.out.println(s1 == s4); //false s1指向常量池中的地址,s4指向对空间地址
      System.out.println(s3 == s4); //false s3和s4都指向堆空间地址,但是地址值不同
    }
}
```

总结:字符串分两种实例化方式,通过**字面量**实例化就存储在**方法区的常量池**中,通过**new方式**就存储在堆空间中。常量池中的常量是**唯一且不可修改**的,如果想使用新的常量,只能在池中创建新的!

https://bbs.leyuz.net/uploads/remote/202102/cdab706213ee4407b7e06e5117de98f2.png

## 3.String不同拼接操作的对比

**结论**:

- 1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
- 2.只要其中有一个是变量,结果就在堆中
- 3.如果拼接的结果调用intern()方法,返回值就在常量池中

```
public class StringTest {
    @Test    public void test1(){
      String s1 = "javaEE";
      String s2 = "hadoop";

      String s3 = "javaEEhadoop";
      String s4 = "javaEE" + "hadoop";
      String s5 = s1 + "hadoop";
      String s6 = "javaEE" + s2;
      String s7 = s1 + s2;

      System.out.println(s3 == s4); //true 常量和常量拼接,地址依旧在常量池,所以指向同一个地址
      System.out.println(s3 == s5); //false 常量和变量拼接,地址就在堆空间中,所以没指向同一个地址
      System.out.println(s3 == s6); //false 同理
      System.out.println(s5 == s6); //false 同理
      System.out.println(s3 == s7); //false 同理
      System.out.println(s5 == s7); //false 同理
      System.out.println(s6 == s7); //false 同理

      String s8 = s5.intern(); //返回值得到的s8使用的常量池中已经存在的"JavaEEhadoop"
      System.out.println(s3 == s8); //true
    }

@Test    public void test1(){
      String s1 = "javaEEhadoop";
      String s2 = "javaEE";
      String s3 = s2 + "hadoop";
      System.out.println(s1 == s3); //false

      final String s4 = "javaEE"; //s4是常量
      String s5 = s4 + "hadoop";
      System.out.println(s1 == s5); //true 原因:看结论1
    }
}
```

## 4.String常用方法

1. **int length()**:返回字符串的长度: return value.length
2. **char charAt(int index)**: 返回某索引处的字符return value
3. **boolean isEmpty()**:判断是否是空字符串:return value.length == 0
4. **String toLowerCase()**:使用默认语言环境,将 String 中的所有字符转换为小写
5. **String toUpperCase()**:使用默认语言环境,将 String 中的所有字符转换为大写
6. **String trim()**:返回字符串的副本,忽略前导空白和尾部空白
7. **boolean equals(Object obj)**:比较字符串的内容是否相同
8. **boolean equalsIgnoreCase(String anotherString)**:与equals方法类似,忽略大小写
9. **String concat(String str)**:将指定字符串连接到此字符串的结尾。 等价于用“+”
10. **int compareTo(String anotherString)**:比较两个字符串的大小
11. **String substring(int beginIndex)**:返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
12. **String substring(int beginIndex, int endIndex)** :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
13. **boolean endsWith(String suffix)**:测试此字符串是否以指定的后缀结束
14. **boolean startsWith(String prefix)**:测试此字符串是否以指定的前缀开始
15. **boolean startsWith(String prefix, int toffset)**:测试此字符串从指定索引开始的子字符串是否以指定前缀开始
16. **boolean contains(CharSequence s)**:当且仅当此字符串包含指定的 char 值序列时,返回 true
17. **int indexOf(String str)**:返回指定子字符串在此字符串中第一次出现处的索引
18. **int indexOf(String str, int fromIndex)**:返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
19. **int lastIndexOf(String str)**:返回指定子字符串在此字符串中最右边出现处的索引
20. **int lastIndexOf(String str, int fromIndex)**:返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
注:indexOf和lastIndexOf方法如果未找到都是返回-1
21. **String replace(char oldChar, char newChar)**:返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
22. **String replace(CharSequence target, CharSequence replacement)**:使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
23. **String replaceAll(String regex, String replacement)** : 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
24. **String replaceFirst(String regex, String replacement)** : 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
25. **boolean matches(String regex)**:告知此字符串是否匹配给定的正则表达式。
26. **String[] split(String regex)**:根据给定正则表达式的匹配拆分此字符串。
27. **String[] split(String regex, int limit)**:根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

**代码演示**:

```
import org.junit.Test;


public class StringTest {
    @Test    public void test1(){
      //length()
      String s1 = "HelloWorld";
      System.out.println(s1.length()); //10

      //charAt()
      System.out.println(s1.charAt(0)); //H
      System.out.println(s1.charAt(9)); //d

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

      //toLowerCase()
      String s2 = s1.toLowerCase();
      System.out.println(s2); //helloworld

      //toUpperCase()
      String s3 = s1.toUpperCase();
      System.out.println(s3); //HELLOWORLD

      //trim()
      String s4 = "   hello world   ";
      String s5 = s4.trim();
      System.out.println("---" + s4 + "---"); //---   hello world   ---
      System.out.println("---" + s5 + "---"); //---hello world---
    }

    @Test    public void test2(){
      //equalsIgnoreCase()
      String s1 = "HelloWorld";
      String s2 = "helloworld";
      System.out.println(s1.equals(s2)); //false
      System.out.println(s1.equalsIgnoreCase(s2)); //true

      //concat()
      String s3 = "abc";
      String s4 = s3.concat("def");
      System.out.println(s4); //abcdef

      //compareTo()
      String s5 = "abc";
      String s6 = new String("abe");
      System.out.println(s5.compareTo(s6)); //涉及到字符串排序

      //substring()
      String s7 = "北京天安门广场";
      System.out.println(s7.substring(2)); //天安门广场

      //endIndex()
      System.out.println(s7.substring(2, 5)); //天安门
    }

    @Test    public void test3(){
      //endsWith()
      String str1 = "helloworld";
      boolean b1 = str1.endsWith("ld");
      System.out.println(b1); //true

      //startsWith()
      boolean b2 = str1.startsWith("He");
      System.out.println(b2); //false
      boolean b3 = str1.startsWith("ll",2);
      System.out.println(b3); //true

      //contains()
      String str2 = "wo";
      System.out.println(str1.contains(str2)); //true

      //indexOf()
      System.out.println(str1.indexOf("lo")); //3
      System.out.println(str1.indexOf("lol")); //-1
      System.out.println(str1.indexOf("lo",5)); //-1

      //lastIndexOf()
      String str3 = "hellorworld";
      System.out.println(str3.lastIndexOf("or")); //7
      System.out.println(str3.lastIndexOf("or",6)); //4

      //什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?
      //1.存在唯一的的一个str   2.不存在str
    }

    @Test    public void test4(){
      //replace()
      String str1 = "北京尚硅谷教育北京";
      String str2 = str1.replace('北', '东');
      String str3 = str1.replace("北京", "上海");
      System.out.println(str1); //北京尚硅谷教育北京
      System.out.println(str2); //东京尚硅谷教育东京
      System.out.println(str3); //上海尚硅谷教育上海
    }
}
```

## 5.String类与其他结构之间的转换

```
/** * 涉及到String类与其他结构之间的转换 */
public class StringTest {
    @Test    public void test1(){
      //String--->基本数据类型、包装类
      String str1 = "123";
      int num = Integer.parseInt(str1); //123

      //基本数据类型、包装类--->String
      String str2 = String.valueOf(num); //"123"
      String str3 = num + "";
    }

    @Test    public void test2(){
      /*      String与char[]之间的转换         */


      //String--->char[]:调用String的toCharArray()
      String str1 = "abc123";
      char[] charArray = str1.toCharArray();
      for (int i = 0; i < charArray.length; i++) {
            System.out.println(charArray);
      }

      //char[]--->String:调用String的构造器
      char[] arr = new char[]{'h','e','l','l','o'};
      String str2 = new String(arr);
      System.out.println(str2); //hello
    }

    @Test    public void test3() throws UnsupportedEncodingException {
      /*      String与byte[]之间转换      编码:字符串--->字节(看得懂--->看不懂)      解码:编码的逆过程,字节--->字符串(看不懂的二进制数据--->看得懂)                说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码         */

      //编码:String--->byte[]:调用
      String str1 = "abc123中国";
      byte[] bytes = str1.getBytes(); //使用默认的字符集(utf-8)进行编码
      //
      System.out.println(Arrays.toString(bytes));

      byte[] gbks = str1.getBytes("gbk"); //使用gbk字符集进行编码
      //
      System.out.println(Arrays.toString(gbks));


      //解码:byte[]--->String:调用String构造器
      String str2 = new String(bytes); //使用默认的字符集,进行解码
      System.out.println(str2); //abc123中国

      String str3 = new String(gbks);
      System.out.println(str3); //出现乱码,原因:编码集和解码集不一致!

      String str4 = new String(gbks, "gbk");
      System.out.println(str4); //没有出现乱码,原因:编码集和解码集一致!
    }
}
```

# 三、StringBuffer类和StringBuilder类

## 1.StringBuffer分析(StringBuilder同理)

StringBuffer类不同于String,其对象**必须使用构造器**生成。

1. StringBuffer():初始容量为16的字符串缓冲区
2. StringBuffer(int size):构造指定容量的字符串缓冲区
3. StringBuffer(String capacity):将内容初始化为指定字符串内容

```
String、StringBuffer、StringBuilder三者异同?
    String:不可变的字符序列;底层结构使用char[]存储
    StringBuffer:可变的字符序列,线程安全的,效率低;底层结构使用char[]存储
    StringBuilder:可变的字符序列,jdk5.0新增,线程不安全的,效率高;底层结构使用char[]存储


String str = new String(); //char[] value = new char;
    String str1 = new String("abc"); //char[] value = new char[]{'a','b','c'};

    StringBuffer sb1 = new StringBuffer(); //char[] value = new char; 底层创建了一个长度是16的数组
    sb1.append('a'); //value = 'a';
    sb1.append('b'); //value = 'b';

    StringBuffer sb2 = new StringBuffer("abc"); //char[] value = new char["abc".length() + 16];

    问题1:System.out.println(sb2.length()); //3
    问题2:扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层数组
          默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组中

    指导意义:在开发中,建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
```

**注意**:String、StringBuffer、StringBuilder三者之间如何转换?

```
String-->StringBuffer、StringBuilder:
1.调用StringBuffer、StringBuilder构造器
StringBuffer、StringBuilder-->String:
1.调用String构造器
2.StringBuffer、StringBuilder的toString()
```

**理解:关于StringBuffer和StringBuilder这两个类,它们之间除了类名不同,唯一的区别就是:是否同步(synchronized)**

## 2.StringBuffer常用方法(StringBuilder同理)

String类中定了许多方法,StringBuffer中也有。但是StringBuffer还有一些独有的方法,我们来了解了解:

1. **StringBuffer append(xxx)**:提供了很多的append()方法,用于进行字符串拼接
2. **StringBuffer delete(int start,int end)**:删除指定位置的内容
3. **StringBuffer replace(int start, int end, String str)**:把[start,end)位置替换为str
4. **StringBuffer insert(int offset, xxx)**:在指定位置插入xxx
5. **StringBuffer reverse()** :把当前字符序列逆转
6. **public int indexOf(String str)**
7. **public String substring(int start,int end)**:返回一个从start开始到end索引结束的左闭右开区间的子字符串1
8. **public int length()**
9. **public char charAt(int n)**
10. **public void setCharAt(int n ,char ch)**

**代码展示**:

```
public class StringTest {

    @Test    public void test2(){
      //append()
      StringBuffer s1 = new StringBuffer("abc");
      s1.append(1);
      s1.append('1');
      System.out.println(s1); //abc11

      //delete()
      //s1.delete(2,4); //ab1

      //replace()
      //s1.replace(2,4,"hello"); //abhello1

      //insert()
      //s1.insert(2,false); //abfalsec11

      //reverse()
      //s1.reverse(); //11cba

      //sustring()
      //String s2 = s1.substring(1, 3); //bc
    }
}
```

总结:

```
增:append(xxx)
删:delete(int start,int end)
改:setCharAt(int n ,char ch)
查:charAt(int n)
插:insert(int offset, xxx)
长度:length()
遍历:for() + charAt(int n)/toString()
```

## 3.效率对比

接下来我们探讨一下:String、StringBuffer、StringBuilder三者之间的效率对比

代码展示:

```
public class StringTest {
    @Test    public void test2(){
      long startTime = 0L;
      long endTime = 0L;
      String text = "";
      StringBuffer buffer = new StringBuffer("");
      StringBuilder builder = new StringBuilder("");

      //开始对比
      //StringBuffer时间
      startTime = System.currentTimeMillis();
      for (int i = 0; i < 20000; i++) {
            buffer.append(String.valueOf(i));
      }
      endTime = System.currentTimeMillis();
      System.out.println("StringBuffer的执行时间:" + (endTime - startTime));

      //StringBuilder测试时间
      startTime = System.currentTimeMillis();
      for (int i = 0; i < 20000; i++) {
            builder.append(String.valueOf(i));
      }
      endTime = System.currentTimeMillis();
      System.out.println("StringBuilder的执行时间:" + (endTime - startTime));

      //String测试时间
      startTime = System.currentTimeMillis();
      for (int i = 0; i < 20000; i++) {
            text = text + i;
      }
      endTime = System.currentTimeMillis();
      System.out.println("String的执行时间:" + (endTime - startTime));
    }
}
```

运行结果如下:

https://bbs.leyuz.net/uploads/remote/202102/50715cd2b19f28ef71094e4f27e93d7f.png

**总结**:
效率由高到低排名为:**StringBuilder > StringBuffer > String**

# 四、JDK8之前日期和时间API

## 1.System.currentTimeMillis()

代码展示:

```
public class StringTest {

    //1.System类中的currentTimeMillis()
    @Test    public void test1() {
      //返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
      //称为:时间戳
      long time = System.currentTimeMillis();
      System.out.println(time);
    }
```

## 2.Date类

```
    /*    java.util.Date类            |---java.sql.Date类    1.两个构造器的使用      >构造器一:Date():创建一个对应当前时间Date对象      >构造器二:创建指定毫秒数的Date对象    2.两个方法的使用      >toString():显示当前的年、月、日、时、分、秒      >getTime():获取当前Date对象对应的毫秒数。(时间戳)    3.java.sql.Date对应着数据库中的日期类型的变量      >如何实例化      >如何将java.util.Date转换为java.sql.Date对象   */

    @Test    public void test2(){
      //构造器一:Date():创建一个对应当前时间Date对象
      Date date1 = new Date();
      System.out.println(date1); //Tue Feb 09 14:10:37 CST 2021
      System.out.println(date1.getTime()); //1612851112558

      //构造器二:创建指定毫秒数的Date对象
      Date date2 = new Date(1612851112558L);
      System.out.println(date2);

      //创建java.sql.Date对象
      java.sql.Date date3 = new java.sql.Date(321312213L);
      System.out.println(date3.toString()); //1970-01-05

      //如何将java.util.Date转换为java.sql.Date对象
      //情况一:
      Date date4 = new java.sql.Date(123231312313L);
      java.sql.Date date5 = (java.sql.Date) date4;
      //情况二:
      Date date6 = new Date();
      java.sql.Date date7 = new java.sql.Date(date6.getTime());
    }
}
```

## 3.SimpleDateFormat类

Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。

```
格式化:
1. SimpleDateFormat() :默认的模式和语言环境创建对象
2. public SimpleDateFormat(String pattern):该构造器可以用参数pattern指定的格式创建一个对象3. public String format(Date date):方法格式化时间对象date解析:1. public Date parse(String source):从给定字符串的开始解析文本,以生成一个日期。
```

代码展示:

```
/** * JDK 8之前的日期时间的API测试 * 1.System类中currentTimeMillis(); * 2.java.util.Date和子类java.sql.Date * 3.SimpleDateFormat * 4.Calendar */
public class DateTimeTest {
    /*    SimpleDateFormat的使用:对日期Date类的格式化和解析    1.两个操作:      1.格式化:日期对象--->字符串      2.解析:格式化逆过程,字符串--->日期对象    2.SimpleDateFormat的实例化   */

    @Test    public void testSimpleDateFormat() throws ParseException {
      //实例化SimpleDateFormat:使用默认构造器
      SimpleDateFormat sdf = new SimpleDateFormat();

      //格式化:日期--->字符串
      Date date = new Date();
      String format = sdf.format(date);
      System.out.println(format);

      //解析:字符串--->日期
      String str = "21-07-07 上午12:00";
      Date date1 = sdf.parse(str);
      System.out.println(date1);


      //按照指定的方式格式化和解析:调用带参的构造器(我们主要使用这种方式!)
      SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
      //格式化
      String format1 = sdf1.format(date);
      System.out.println(format1); //2021-02-10 01:54:58
      //解析:要求字符串必须符合SimpleDateFormat识别的格式(通过构造器参数体现)
      //否则,抛异常
      Date date2 = sdf1.parse("2021-02-10 01:54:58");
      System.out.println(date2); //Wed Feb 10 01:54:58 CST 2021
    }
}
```

## 4.Calendar类

Calendar是一个**抽象基类**,主用用于完成日期字段之间相互操作的功能。

```
获取Calendar实例的方法:
1. 使用Calendar.getInstance()方法
2. 调用它的子类GregorianCalendar的构造器。
```

代码展示:

```
/** * JDK 8之前的日期时间的API测试 * 1.System类中currentTimeMillis(); * 2.java.util.Date和子类java.sql.Date * 3.SimpleDateFormat * 4.Calendar */
public class DateTimeTest {
    /*   Calendar日历类(抽象类)的使用   */

    @Test    public void testCalendar(){
      //1.实例化
      //方式一:创建其子类(GregorianCalendar)的对象
      //方式二:调用其静态方法getInstance()
      Calendar calendar = Calendar.getInstance();
      System.out.println(calendar.getClass());//class java.util.GregorianCalendar

      //2.常用方法
      //get()
      int days = calendar.get(Calendar.DAY_OF_MONTH);
      System.out.println(days);
      System.out.println(calendar.get(Calendar.DAY_OF_YEAR));

      //set()
      //Calendar可变性
      calendar.set(Calendar.DAY_OF_MONTH,22);
      days = calendar.get(Calendar.DAY_OF_MONTH);
      System.out.println(days);

      //add()
      calendar.add(Calendar.DAY_OF_MONTH,3);
      days = calendar.get(Calendar.DAY_OF_MONTH);
      System.out.println(days);

      //getTime():日历类--->Date
      Date date = calendar.getTime();
      System.out.println(date);

      //setTime():Date--->日历类
      Date date1 = new Date();
      calendar.setTime(date1);
      days = calendar.get(Calendar.DAY_OF_MONTH);
      System.out.println(days);
    }
}
```

**注意**:

1. 获取月份时:一月是0,二月是1,以此类推,12月是11
2. 获取星期时:周日是1,周二是2 , 。。。。周六是7

# 五、JDK8中新日期和时间API

**为何引进新的API?**
JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们有许多**缺点**:

```
可变性:像日期和时间这样的类应该是不可变的。
偏移性:Date中的年份是从1900开始的,而月份都从0开始。
格式化:格式化只对Date有用,Calendar则不行。
此外,它们也不是线程安全的;不能处理闰秒等。
```

**总结**:对日期和时间的操作一直是Java程序员最痛苦的地方之一。

正因如此,我们才需要引进新的API,Java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。

## 1. LocalDate、LocalTime、LocalDateTime

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

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

代码展示:

```
public class DateTimeTest {
    /*   LocalDate、LocalTime、LocalDateTime的使用   说明:      1.LocalDateTime相较于LocalDate、LocalTime,使用频率更高      2.类似于Calendar类   */

    @Test    public void test1(){
      //now():获取当前的日期、时间、日期 + 时间
      LocalDate localDate = LocalDate.now();
      LocalTime localTime = LocalTime.now();
      LocalDateTime localDateTime = LocalDateTime.now();

      System.out.println(localDate);
      System.out.println(localTime);
      System.out.println(localDateTime);

      //of():设置指定的年、月、日、时、分、秒。没有偏移量
      LocalDateTime localDateTime1 = localDateTime.of(2020, 10, 6, 13, 23, 43);
      System.out.println(localDateTime1); //2020-10-06T13:23:43

      //getXxx():获取相关的属性
      System.out.println(localDateTime.getDayOfMonth());
      System.out.println(localDateTime.getDayOfWeek());
      System.out.println(localDateTime.getMonth());
      System.out.println(localDateTime.getMonthValue());
      System.out.println(localDateTime.getMinute());

      //体现不可变性
      //withXxx():设置相关的属性
      LocalDate localDate1 = localDate.withDayOfMonth(22);
      System.out.println(localDate);
      System.out.println(localDate1);

      LocalDateTime localDateTime2 = localDateTime.withHour(4);
      System.out.println(localDateTime);
      System.out.println(localDateTime2);


      //不可变性
      LocalDateTime localDateTime3 = localDateTime.plusMonths(3);
      System.out.println(localDateTime);
      System.out.println(localDateTime3);

      LocalDateTime localDateTime4 = localDateTime.minusDays(6);
      System.out.println(localDateTime);
      System.out.println(localDateTime4);
    }
}
```

## 2.Instant类

Instant:时间线上的一个**瞬时点**。 这可能被用来记录应用程序中的事件时间戳。

代码展示:

```
public class DateTimeTest {
    /*    Instant的使用    类似于java.util.Date类   */

    @Test    public void test1(){
      //now():获取本初子午线对应的标准时间
      Instant instant = Instant.now();
      System.out.println(instant); //2021-02-10T23:35:44.312Z

      //添加时间的偏移量
      OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
      System.out.println(offsetDateTime); //2021-02-11T07:35:44.312+08:00

      //toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数 --->Date类的getTime()
      long milli = instant.toEpochMilli();
      System.out.println(milli);

      //ofEpochMilli():通过给定的毫秒数,获取Instant实例 --->Date(long millis)
      Instant instant1 = Instant.ofEpochMilli(321321312312L);
      System.out.println(instant1);
    }
}
```

## 3.DateTimeFormatter类

代码展示:

```
public class DateTimeTest {
    /*    DateTimeFormatter:格式化或解析日期、时间    类似于SimpleDateFormat   */

    @Test    public void test1(){
      //实例化方式
      //方式一:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
      DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
      //格式化:日期--->字符串
      LocalDateTime localDateTime = LocalDateTime.now();
      String str1 = formatter.format(localDateTime);
      System.out.println(localDateTime);
      System.out.println(str1);
      //解析:字符串--->日期
      TemporalAccessor parse = formatter.parse("2021-02-11T07:52:55.315");
      System.out.println(parse);

      //方式二:
      //本地化相关的格式。如:ofLocalizedDateTime()
      //FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
      DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
      //格式化
      String str2 = formatter1.format(localDateTime);
      System.out.println(str2);//2019年2月18日 下午03时47分16秒


      //本地化相关的格式。如:ofLocalizedDate()
      //FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDate
      DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
      //格式化
      String str3 = formatter2.format(LocalDate.now());
      System.out.println(str3);//2019-2-18


      //重点:方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
      DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
      //格式化
      String str4 = formatter3.format(LocalDateTime.now());
      System.out.println(str4);

      //解析
      TemporalAccessor accessor = formatter3.parse("2019-02-18 03:52:09");
      System.out.println(accessor);

    }
}
```

# 六、Java比较器

在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。

Java实现对象排序的方式有**两种**:

1. 自然排序:java.lang.Comparable
2. 定制排序:java.util.Comparator

## 1.自然排序:Comparable接口

Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。

实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。

实现Comparable接口的对象列表(和数组)可以通过 **Collections.sort 或Arrays.sort**进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

代码展示:

```
/** * 一、说明:java中的对象,正常情况下,只能进行比较:== 或 != 。不能使用> 或 < *         但是在开发场景中,我们需要对多个对象进行排序,言外之意,需要比较对象的大小 *         如何实现?使用两个接口中任何一个:Comparable 或 Comparator * * 二、Comparable接口的使用 * */
public class CompareTest {
    /*    Comparable接口的使用举例:自然排序    1.像String、包装类等实现了Comparable接口,重写了compareTo(),给出了比较两个对象大小的方式    2.像String、包装类重写compareTo()方法以后,进行了从小到大的排列    3.重写compareTo()的规则:      如果当前对象this大于形参对象obj,则返回正整数,      如果当前对象this小于形参对象obj,则返回负整数,      如果当前对象this等于形参对象obj,则返回零。    4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,    重写compareTo(obj)方法,在compareTo(obj)方法中指明如何排序   */
    @Test    public void test1(){
      String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
      Arrays.sort(arr);
      System.out.println(Arrays.toString(arr));
    }


    @Test    public void test2(){
      Goods[] arr = new Goods;
      arr = new Goods("lenovoMouse",34);
      arr = new Goods("dellMouse",43);
      arr = new Goods("xiaomiMouse",12);
      arr = new Goods("huaweiMouse",65);
      arr = new Goods("microsoftmouse",43);

      Arrays.sort(arr);
      System.out.println(Arrays.toString(arr));
    }
}

=================================================================
/** * 商品类 */
public class Goods implements Comparable {
    private String name;
    private double price;

    //构造器、getter、setter、toString()方法略

    //指明商品比较大小的方式:按照价格从低到高排序,
    //再按照商品名称从低到高排序
    @Override    public int compareTo(Object o) {
      if (o instanceof Goods){
            Goods goods = (Goods) o;
            //方式一:
            if (this.price > goods.price){
                return 1;
            }else if (this.price < goods.price){
                return -1;
            }else {
                //return 0;
                return this.name.compareTo(goods.name);
            }

            //方式二
            //return Double.compare(this.price,goods.price);
      }
      throw new RuntimeException("传入的数据类型不一致!");
    }
}
```

## 2.定制排序:Comparator接口

当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序

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

代码展示:

```
/** * 一、说明:java中的对象,正常情况下,只能进行比较:== 或 != 。不能使用> 或 < *         但是在开发场景中,我们需要对多个对象进行排序,言外之意,需要比较对象的大小 *         如何实现?使用两个接口中任何一个:Comparable 或 Comparator * * 二、Comparable接口与Comparator接口使用对比: * Comparable接口的方式一旦指定,保证该接口实现类的对象在任何位置都可以比较大小 * Comparator接口属于临时性的比较 */
public class CompareTest {
    /*    Comparator接口的使用:定制排序    1.背景:当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,    或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序    2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小:    如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表o1小于o2。   */

    @Test    public void test(){
      String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
      Arrays.sort(arr, new Comparator(){

            //按照字符串从大到小的顺序排列
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof String && o2 instanceof String){
                  String s1 = (String) o1;
                  String s2 = (String) o2;
                  return -s1.compareTo(s2);
                }
                //return 0;
                throw new RuntimeException("输入数据类型不一致");
            }
      });
      System.out.println(Arrays.toString(arr));
    }

    @Test    public void test1(){
      Goods[] arr = new Goods;
      arr = new Goods("lenovoMouse",34);
      arr = new Goods("dellMouse",43);
      arr = new Goods("xiaomiMouse",12);
      arr = new Goods("huaweiMouse",65);
      arr = new Goods("huaweiMouse",224);
      arr = new Goods("microsoftmouse",43);

      Arrays.sort(arr, new Comparator() {
            //指明商品比较大小的方式:按照产品名称从低到高排序,再按照价格从高到低排序
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Goods && o2 instanceof Goods){
                  Goods g1 = (Goods) o1;
                  Goods g2 = (Goods) o2;
                  if (g1.getName().equals(g2.getName())){
                        return -Double.compare(g1.getPrice(),g2.getPrice());
                  }else {
                        return g1.getName().compareTo(g2.getName());
                  }
                }
                throw new RuntimeException("输入数据类型不一致");
            }
      });

      System.out.println(Arrays.toString(arr));
    }
}
```

# 七、System类

System类代表**系统**,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。

由于该类的**构造器是private**的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便的进行调用。

System类内部包含in、out和err**三个成员变量**,分别代表标准输入流
(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。

成员方法:

```
1. native long currentTimeMillis()
2. void exit(int status)
3. void gc()
4. String getProperty(String key)
```

代码展示:

```
public class SystemTest {
    @Test    public void test(){
      String javaVersion = System.getProperty("java.version");
      System.out.println("java的version:" + javaVersion);

      String javaHome = System.getProperty("java.home");
      System.out.println("java的home:" + javaHome);

      String osName = System.getProperty("os.name");
      System.out.println("os的name:" + osName);

      String osVersion = System.getProperty("os.version");
      System.out.println("os的version:" + osVersion);

      String userName = System.getProperty("user.name");
      System.out.println("user的name:" + userName);

      String userHome = System.getProperty("user.home");
      System.out.println("user的home:" + userHome);

      String userDir = System.getProperty("user.dir");
      System.out.println("user的dir:" + userDir);
    }
}
```

输出结果如下:

https://bbs.leyuz.net/uploads/remote/202102/00f968bce7fa67b35a7cceb7bbb56815.png

# 八、Math类

java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型。

```
abs 绝对值
acos,asin,atan,cos,sin,tan 三角函数
sqrt 平方根
pow(double a,doble b) a的b次幂
log 自然对数
exp e为底指数
max(double a,double b)
min(double a,double b)
random() 返回0.0到1.0的随机数
long round(double a) double型数据a转换为long型(四舍五入)
toDegrees(double angrad) 弧度—>角度
toRadians(double angdeg) 角度—>弧度
```

# 九、BigInteger类

大于基本数据类型的**整数**,如果要表示再大的整数,不管是基本数据类型还是他们的包装类都**无能为力**,更不用说进行运算了。

java.math包的**BigInteger可以表示不可变的任意精度的整数**。BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。

**构造器**:
**BigInteger(String val)**:根据字符串构建BigInteger对象

常用方法:

1. **public BigInteger abs()**:返回此 BigInteger 的绝对值的 BigInteger
2. **BigInteger add(BigInteger val)** :返回其值为 (this + val) 的 BigInteger
3. **BigInteger subtract(BigInteger val)** :返回其值为 (this - val) 的 BigInteger
4. **BigInteger multiply(BigInteger val)** :返回其值为 (this * val) 的 BigInteger
5. **BigInteger divide(BigInteger val)** :返回其值为 (this / val) 的 BigInteger。整数相除只保留整数部分。
6. **BigInteger remainder(BigInteger val)** :返回其值为 (this % val) 的 BigInteger。
7. **BigInteger[] divideAndRemainder(BigInteger val)**:返回包含 (this / val) 后跟(this % val) 的两个 BigInteger 的数组。
8. **BigInteger pow(int exponent)** :返回其值为 (thisexponent) 的 BigInteger。

# 十、BigDecimal类

一般的**Float类和Double类**可以用来做科学计算或工程计算,但在商业计算中,**要求数字精度比较高,故用到java.math.BigDecimal类**。

BigDecimal类支持不可变的、任意精度的有符号十进制定点数。

构造器:
public BigDecimal(double val)
public BigDecimal(String val)

常用方法:

1. **public BigDecimal add(BigDecimal augend)**
2. **public BigDecimal subtract(BigDecimal subtrahend)**
3. **public BigDecimal multiply(BigDecimal multiplicand)**
4. **public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)**

代码展示:

```
public class SystemTest {
    @Test    public void test(){
      BigInteger bi = new BigInteger("12421312312333241123");
      BigDecimal bd = new BigDecimal("12435.351");
      BigDecimal bd2 = new BigDecimal("11");
      System.out.println(bi);
      // System.out.println(bd.divide(bd2)); //报错
      System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));
      System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP));
    }
}
```

hualonghongyan 发表于 2021-5-8 10:41

这帖子,大家是不是看不到呀~

凉米饭 发表于 2021-5-8 10:44

可以看到的 。已经收藏

加奈绘 发表于 2021-5-8 10:54

收藏了,谢谢分享

hualonghongyan 发表于 2021-5-8 11:02

凉米饭 发表于 2021-5-8 10:44
可以看到的 。已经收藏

谢谢的,哈哈,我以为大家看不到

forever1003 发表于 2021-5-8 12:03

感谢分享,先收藏,

Mango_943 发表于 2021-5-8 14:09

不错 ,写得挺好的

asenna 发表于 2021-5-9 10:45

感谢分享

IntDoubleFloat 发表于 2021-5-9 12:36

感谢分享,记录一下

铁牛妹妹爱发呆 发表于 2021-5-9 18:39

感谢楼主总结分享,已收藏
页: [1] 2
查看完整版本: Java常用类笔记