• Java常用类


    Java常用类

    目录

    概述

    总结:https://www.bilibili.com/video/BV1mE411x7Wt?p=157

    day01笔记

    1、String类。
    1.1、对String在内存存储方面的理解:
    第一:字符串一旦创建不可变。
    第二:双引号括起来的字符串存储在字符串常量池中。
    第三:字符串的比较必须使用equals方法。
    第四:String已经重写了toString()和equals()方法。

    ​ 1.2、String的构造方法。
    ​ String s = "abc";
    ​ String s = new String("abc");
    ​ String s = new String(byte数组);
    ​ String s = new String(byte数组, 起始下标, 长度);
    ​ String s = new String(char数组);
    ​ String s = new String(char数组, 起始下标, 长度);

    ​ 1.3、String类常用的21个方法。

    2、StringBuffer/StringBuilder
    2.1、StringBuffer/StringBuilder可以看做可变长度字符串。
    2.2、StringBuffer/StringBuilder初始化容量16.
    2.3、StringBuffer/StringBuilder是完成字符串拼接操作的,方法名:append
    2.4、StringBuffer是线程安全的。StringBuilder是非线程安全的。
    2.5、频繁进行字符串拼接不建议使用“+”

    3、八种基本数据类型对应的包装类
    3.1、包装类存在有什么用?
    方便编程。
    3.2、八种包装类的类名是什么?
    Byte
    Short
    Integer
    Long
    Float
    Double
    Boolean
    Character
    3.3、所有数字的父类Number
    3.4、照葫芦画瓢:学习Integer,其它的模仿Integer。
    3.5、什么是装箱?什么是拆箱?


    day02笔记

    1、八种基本数据类型对应的包装类。
    1.1、什么是自动装箱和自动拆箱,代码怎么写?
    Integer x = 100; // x里面并不是保存100,保存的是100这个对象的内存地址。
    Integer y = 100;
    System.out.println(x == y); // true

    ​ Integer x = 128;
    ​ Integer y = 128;
    ​ System.out.println(x == y); // false

    ​ 1.2、Integer类常用方法。
    ​ Integer.valueOf()
    ​ Integer.parseInt("123")
    ​ Integer.parseInt("中文") : NumberFormatException

    1.3、Integer String int三种类型互相转换。

    2、日期类
    2.1、获取系统当前时间
    Date d = new Date();
    2.2、日期格式化:Date --> String
    yyyy-MM-dd HH:mm:ss SSS
    SimpleDateFormat sdf = new SimpleDate("yyyy-MM-dd HH:mm:ss SSS");
    String s = sdf.format(new Date());
    2.3、String --> Date
    SimpleDateFormat sdf = new SimpleDate("yyyy-MM-dd HH:mm:ss");
    Date d = sdf.parse("2008-08-08 08:08:08");
    2.4、获取毫秒数
    long begin = System.currentTimeMillis();
    Date d = new Date(begin - 1000 * 60 * 60 * 24);

    3、数字类
    3.1、DecimalFormat数字格式化
    ###,###.## 表示加入千分位,保留两个小数。
    ###,###.0000 表示加入千分位,保留4个小数,不够补0
    3.2、BigDecimal
    财务软件中通常使用BigDecimal

    4、随机数
    4.1、怎么产生int类型随机数。
    Random r = new Random();
    int i = r.nextInt();
    4.2、怎么产生某个范围之内的int类型随机数。
    Random r = new Random();
    int i = r.nextInt(101); // 产生[0-100]的随机数。

    5、枚举
    5.1、枚举是一种引用数据类型。
    5.2、枚举编译之后也是class文件。
    5.3、枚举类型怎么定义?
    enum 枚举类型名{
    枚举值,枚举值2,枚举值3
    }
    5.4、当一个方法执行结果超过两种情况,并且是一枚一枚可以列举出来
    的时候,建议返回值类型设计为枚举类型。

    6、异常处理机制
    6.1、java中异常的作用是:增强程序健壮性。
    6.2、java中异常以类和对象的形式存在。


    一、String类

    StringTest01——String类型概述以及存储位置

    1. String表示字符串类型,属于引用数据类型,不属于基本数据类型。

    2. 在java中随便使用双引号括起来的都是String对象。例如:"abc","def","hello world!",这是3个String对象。

    3. java中规定,双引号括起来的字符串,是不可变的,也就是说"abc"自出生到最终死亡,不可变,不能变成"abcd",也不能变成"ab"。

    4. 在JDK当中双引号括起来的字符串,例如:"abc" "def"都是直接存储在“方法区”的“字符串常量池”当中的。

      为什么SUN公司把字符串存储在一个“字符串常量池”当中呢。因为字符串在实际的开发中使用太频繁。为了执行效率,
      所以把字符串放到了方法区的字符串常量池当中。

    package com.example.javase.string;
    public class StringTest01 {
        public static void main(String[] args) {
            // 这两行代码表示底层创建了3个字符串对象,都在字符串常量池当中。
            String s1 = "abcdef";
            String s2 = "abcdef" + "xy";
    
            // 分析:这是使用new的方式创建的字符串对象。这个代码中的"xy"是从哪里来的?
            // 凡是双引号括起来的都在字符串常量池中有一份。
            // new对象的时候一定在堆内存当中开辟空间。
            String s3 = new String("xy");
    
            // i变量中保存的是100这个值。
            int i = 100;
            // s变量中保存的是字符串对象的内存地址。
            // s引用中保存的不是"abc",是0x1111
            // 而0x1111是"abc"字符串对象在“字符串常量池”当中的内存地址。
            String s = "abc";
        }
    }
    

    这个示例对应的内存图:

    1. 首先在java虚拟机的方法区会存放字节码文件、代码片段、静态变量和字符串常量池

    2. 当程序执行时,main方法栈帧会被压入栈中,然后执行:

      • String s1 = "abcdef",会在方法区创建 "abcdef" 常量,然后s1存放这个常量的内存地址。

      • String s2 = "abcdef" + "xy","abcdef" 常量在方法区已经存在了,还需要创建一个 "xy" 常量,然后通过字符串拼接成"abcdefxy" 放入方法区。

      • String s3 = new String("xy"),在堆内存开辟出一块空间,存放String对象,s3存放的是String对象的内存地址,String对象存放的是字符串常量池中的 "xy"的内存地址。

        由于"xy"在字符串常量池中已经存在一份了,所以不会被再次创建。

    day25-String的内存图

    ​ String类型的引用中同样也是保存了对象的内存地址:

    day25-String类型的引用中同样也是保存了对象的内存地址

    ​ Spring的面试题:

    day25-String相关面试题

    StringTest02——”==“与equals

    1. 使用==比较两个对象时,比较的是两个对象的内存首地址。

    2. 使用equals方法比较两个对象:

      如果不重写equals方法的话,使用的是Object类的equals方法,使用的==比较对象的首地址。

      如果重写了equals方法,比较的是内容。

    3. 所以在对字符串对象进行比较时:

      如果比较是不是同一个对象,使用==.

      如果比较的是两个字符串对象的内容,使用equals

    4. String类已经重写了equals方法,表示比较的内容。

    5. 使用equals比较时,需要注意的是:

      建议使用:"testString".equals(s2)这种形式。

      不推荐使用:(s2).equals"testString",因为可能会出现空指针异常。

    package com.bjpowernode.javase.string;
    
    public class StringTest02 {
        public static void main(String[] args) {
            String s1 = "hello";
            // "hello"是存储在方法区的字符串常量池当中
            // 所以这个"hello"不会新建。(因为这个对象已经存在了!)
            String s2 = "hello";
            // 分析结果是true还是false?
            // == 双等号比较的是不是变量中保存的内存地址?是的。
            System.out.println(s1 == s2); // true
    
            String x = new String("xyz");
            String y = new String("xyz");
            // 分析结果是true还是false?
            // == 双等号比较的是不是变量中保存的内存地址?是的。
            System.out.println(x == y); //false
    
            // 通过这个案例的学习,我们知道了,字符串对象之间的比较不能使用“==”
            // "=="不保险。应该调用String类的equals方法。
            // String类已经重写了equals方法,以下的equals方法调用的是String重写之后的equals方法。
            System.out.println(x.equals(y)); // true
    
            String k = new String("testString");
            //String k = null;
            // "testString"这个字符串可以后面加"."呢?
            // 因为"testString"是一个String字符串对象。只要是对象都能调用方法。
            System.out.println("testString".equals(k)); // 建议使用这种方式,因为这个可以避免空指针异常。
            System.out.println(k.equals("testString")); // 存在空指针异常的风险。不建议这样写。
        }
    }
    

    StringTest03——分析以下程序,一共创建了几个对象?

    String s1 = new String("hello")
    String s2 = new String("hello")

    分析:一个创建了3个对象,"hello" 对象被放入了方法区的字符串常量池中,new的两个String对象放在了堆中。

    package com.bjpowernode.javase.string;
    /*
    分析以下程序,一共创建了几个对象
     */
    public class StringTest03 {
        public static void main(String[] args) {
            /*
            一共3个对象:
                方法区字符串常量池中有1个:"hello"
                堆内存当中有两个String对象。
                一共3个。
             */
            String s1 = new String("hello");
            String s2 = new String("hello");
        }
    }
    

    StringTest04——关于String类中常用的构造方法

    • 第一个:String s = new String("");
    • 第二个:String s = ""; 最常用。
    • 第三个:String s = new String(char数组);
    • 第四个:String s = new String(char数组,起始下标,长度);
    • 第五个:String s = new String(byte数组);
    • 第六个:String s = new String(byte数组,起始下标,长度)
    package com.bjpowernode.javase.string;
    
    /**
     * 关于String类中的构造方法。
     *  第一个:String s = new String("");
     *  第二个:String s = ""; 最常用
     *  第三个:String s = new String(char数组);
     *  第四个:String s = new String(char数组,起始下标,长度);
     *  第五个:String s = new String(byte数组);
     *  第六个:String s = new String(byte数组,起始下标,长度)
     */
    public class StringTest04 {
        public static void main(String[] args) {
    
            // 创建字符串对象最常用的一种方式
            String s1 =  "hello world!";
            // s1这个变量中保存的是一个内存地址。
            // 按说以下应该输出一个地址。
            // 但是输出一个字符串,说明String类已经重写了toString()方法。
            System.out.println(s1);//hello world!
            System.out.println(s1.toString()); //hello world!
    
            // 这里只掌握常用的构造方法。
            byte[] bytes = {97, 98, 99}; // 97是a,98是b,99是c
            String s2 = new String(bytes);
    
            // 前面说过:输出一个引用的时候,会自动调用toString()方法,默认Object的话,会自动输出对象的内存地址。
            // 通过输出结果我们得出一个结论:String类已经重写了toString()方法。
            // 输出字符串对象的话,输出的不是对象的内存地址,而是字符串本身。
            System.out.println(s2.toString()); //abc
            System.out.println(s2); //abc
    
            // String(字节数组,数组元素下标的起始位置,长度)
            // 将byte数组中的一部分转换成字符串。
            String s3 = new String(bytes, 1, 2);
            System.out.println(s3); // bc
    
            // 将char数组全部转换成字符串
            char[] chars = {'我','是','中','国','人'};
            String s4 = new String(chars);
            System.out.println(s4);
            // 将char数组的一部分转换成字符串
            String s5 = new String(chars, 2, 3);
            System.out.println(s5);
    
            String s6 = new String("helloworld!");
            System.out.println(s6); //helloworld!
        }
    }
    

    StringTest05——String类当中常用方法【重点】

    1. char charAt(int index):返回字符串中指定位置的字符。

    2. int compareTo(String anotherString):比较两个字符串的大小。(-1,0,1)

    3. boolean contains(CharSequence s):判断当前字符串是否包含某个字符序列(字符串)。

    4. boolean endsWith(String suffix):判断当前字符串是否以某个子字符串结尾。

    5. boolean equals(Object anObject): 比较两个字符串必须使用equals方法。

      equal() 和 compareTo() 方法的区别?

      equals只能看出相等不相等。

      compareTo方法可以看出是否相等,并且同时还可以看出谁大谁小,如"abd"就比"abc"大。

    6. boolean equalsIgnoreCase(String anotherString):判断两个字符串是否相等(忽略大小写)。

    7. byte[] getBytes():将字符串对象转换成字节数组。

    8. int indexOf(String str):返回某个子字符串在当前字符串中第一次出现处的索引(下标)。

    9. boolean isEmpty():判断某个字符串是否为“空字符串”。底层源代码调用的是该字符串的length()方法。

    10. int length():返回字符串的长度。

      面试题:判断数组长度和判断字符串长度不一样?

      判断数组长度是length属性,判断字符串长度是length()方法。

    11. int lastIndexOf(String str):返回某个子字符串在当前字符串中最后一次出现的索引(下标)。

    12. String replace(CharSequence target, CharSequence replacement):简单来说,就是用一个字符串来替换当前字符串中的某个(子)字符串,返回一个新的字符串。

    13. String[] split(String regex):将当前字符串按照某个字符(字符串)进行拆分,返回一个拆分后的数组。

    14. boolean startsWith(String prefix):判断当前字符串是否以指定字符串开头。

    15. String substring(int beginIndex) :返回当前字符串的字串,从起始下标处到字符串末尾。

    16. String substring(int beginIndex, int endIndex):返回当前字符串的字串,从起始下标处到结束下标【前闭后开】

      前闭后开的意思就是:包括起始下标,不包括结束下标。

    17. char[] toCharArray():将当前字符串转换成char数组。

    18. String toLowerCase():转换为小写。

    19. String toUpperCase():转化为大写。

    20. String trim():去除字符串前后空格。

      String s = " Hello World ";

      去除前后空格:String s="Hello World";

      只是字串前后的空格,字符串中间的空格不会被去除。

    21. String.valueOf():将指定类型的非字符串转换为字符串。

      如:int、boolean、float...等基本数据类型。

      也可以是一个对象 String.valueOf(new Person());

      注意:如果Person对象没有重写toString方法?

      返回的字符串是该对象的内存地址:com.example.javase.string.Person@10f87f48

      重写toString()之后返回的是一个重写之后的字符串:我是VIP客户。

      扩展:println()方法的源代码是如何实现的?

      System.out.println()这个方法在输出任何数据的时候都是先转换成字符串,再输出。

      public void print(int i) {
       write(String.valueOf(i));
      }
      public void print(long l) {
           write(String.valueOf(l));
       }
      public void print(Object obj) {
           write(String.valueOf(obj));
       }
      
    package com.bjpowernode.javase.string;
    
    public class StringTest05 {
        public static void main(String[] args) {
    
            // String类当中常用方法。
            //1(掌握).char charAt(int index)
            char c = "中国人".charAt(1); // "中国人"是一个字符串String对象。只要是对象就能“点.”
            System.out.println(c); // 国
    
            // 2(了解).int compareTo(String anotherString)
            // 字符串之间比较大小不能直接使用 > < ,需要使用compareTo方法。
            int result = "abc".compareTo("abc");
            System.out.println(result); //0(等于0) 前后一致  10 - 10 = 0
    
            int result2 = "abcd".compareTo("abce");
            System.out.println(result2); //-1(小于0) 前小后大 8 - 9 = -1
    
            int result3 = "abce".compareTo("abcd");
            System.out.println(result3); // 1(大于0) 前大后小 9 - 8 = 1
    
            // 拿着字符串第一个字母和后面字符串的第一个字母比较。能分胜负就不再比较了。
            System.out.println("xyz".compareTo("yxz")); // -1
    
            // 3(掌握).boolean contains(CharSequence s)
            // 判断前面的字符串中是否包含后面的子字符串。
            System.out.println("HelloWorld.java".contains(".java")); // true
            System.out.println("http://www.baidu.com".contains("https://")); // false
    
            // 4(掌握). boolean endsWith(String suffix)
            // 判断当前字符串是否以某个子字符串结尾。
            System.out.println("test.txt".endsWith(".java")); // false
            System.out.println("test.txt".endsWith(".txt")); // true
            System.out.println("fdsajklfhdkjlsahfjkdsahjklfdss".endsWith("ss")); // true
    
            // 5(掌握).boolean equals(Object anObject)
            // 比较两个字符串必须使用equals方法,不能使用“==”
            // equals方法有没有调用compareTo方法? 老版本可以看一下。JDK13中并没有调用compareTo()方法。
            // equals只能看出相等不相等。
            // compareTo方法可以看出是否相等,并且同时还可以看出谁大谁小。
            System.out.println("abc".equals("abc")); // true
    
            // 6(掌握).boolean equalsIgnoreCase(String anotherString)
            // 判断两个字符串是否相等,并且同时忽略大小写。
            System.out.println("ABc".equalsIgnoreCase("abC")); // true
    
            // 7(掌握).byte[] getBytes()
            // 将字符串对象转换成字节数组
            byte[] bytes = "abcdef".getBytes();
            for(int i = 0; i < bytes.length; i++){
                System.out.println(bytes[i]);
            }
    
            // 8(掌握).int indexOf(String str)
            // 判断某个子字符串在当前字符串中第一次出现处的索引(下标)。
            System.out.println("oraclejavac++.netc#phppythonjavaoraclec++".indexOf("java")); // 6
    
            // 9(掌握).boolean isEmpty()
            // 判断某个字符串是否为“空字符串”。底层源代码调用的应该是字符串的length()方法。
            //String s = "";
            String s = "a";
            System.out.println(s.isEmpty());
    
            // 10(掌握). int length()
            // 面试题:判断数组长度和判断字符串长度不一样
            // 判断数组长度是length属性,判断字符串长度是length()方法。
            System.out.println("abc".length()); // 3
    
            System.out.println("".length()); // 0
    
            // 11(掌握).int lastIndexOf(String str)
            // 判断某个子字符串在当前字符串中最后一次出现的索引(下标)
            System.out.println("oraclejavac++javac#phpjavapython".lastIndexOf("java")); //22
    
            // 12(掌握). String replace(CharSequence target, CharSequence replacement)
            // 替换。
            // String的父接口就是:CharSequence
            String newString = "http://www.baidu.com".replace("http://", "https://");
            System.out.println(newString); //https://www.baidu.com
            // 把以下字符串中的“=”替换成“:”
            String newString2 = "name=zhangsan&password=123&age=20".replace("=", ":");
            System.out.println(newString2); //name:zhangsan&password:123&age:20
    
            // 13(掌握).String[] split(String regex)
            // 拆分字符串
            String[] ymd = "1980-10-11".split("-"); //"1980-10-11"以"-"分隔符进行拆分。
            for(int i = 0; i < ymd.length; i++){
                System.out.println(ymd[i]);
            }
            String param = "name=zhangsan&password=123&age=20";
            String[] params = param.split("&");
            for(int i = 0; i <params.length; i++){
                System.out.println(params[i]);
                // 可以继续向下拆分,可以通过“=”拆分。
            }
    
            // 14(掌握)、boolean startsWith(String prefix)
            // 判断某个字符串是否以某个子字符串开始。
            System.out.println("http://www.baidu.com".startsWith("http")); // true
            System.out.println("http://www.baidu.com".startsWith("https")); // false
    
            // 15(掌握)、 String substring(int beginIndex) 参数是起始下标。
            // 截取字符串
            System.out.println("http://www.baidu.com".substring(7)); //www.baidu.com
    
            // 16(掌握)、String substring(int beginIndex, int endIndex)
            // beginIndex起始位置(包括)
            // endIndex结束位置(不包括)
            System.out.println("http://www.baidu.com".substring(7, 10)); //www
    
            // 17(掌握)、char[] toCharArray()
            // 将字符串转换成char数组
            char[] chars = "我是中国人".toCharArray();
            for(int i = 0; i < chars.length; i++){
                System.out.println(chars[i]);
            }
    
            // 18(掌握)、String toLowerCase()
            // 转换为小写。
            System.out.println("ABCDefKXyz".toLowerCase());
    
            // 19(掌握)、String toUpperCase();
            System.out.println("ABCDefKXyz".toUpperCase());
    
            // 20(掌握). String trim();
            // 去除字符串前后空白
            System.out.println("           hello      world             ".trim());
    
            // 21(掌握). String中只有一个方法是静态的,不需要new对象
            // 这个方法叫做valueOf
            // 作用:将“非字符串”转换成“字符串”
            //String s1 = String.valueOf(true);
            //String s1 = String.valueOf(100);
            //String s1 = String.valueOf(3.14);
    
            // 这个静态的valueOf()方法,参数是一个对象的时候,会自动调用该对象的toString()方法吗?
            String s1 = String.valueOf(new Customer());
            //System.out.println(s1); // 没有重写toString()方法之前是对象内存地址 com.bjpowernode.javase.string.Customer@10f87f48
            System.out.println(s1); //我是一个VIP客户!!!!
    
            // 我们是不是可以研究一下println()方法的源代码了?
            System.out.println(100);
            System.out.println(3.14);
            System.out.println(true);
    
            Object obj = new Object();
            // 通过源代码可以看出:为什么输出一个引用的时候,会调用toString()方法!!!!
            // 本质上System.out.println()这个方法在输出任何数据的时候都是先转换成字符串,再输出。
            System.out.println(obj);
    
            System.out.println(new Customer());
        }
    }
    
    class Customer {
        // 重写toString()方法
    
        @Override
        public String toString() {
            return "我是一个VIP客户!!!!";
        }
    }
    

    二、StringBuffer、StringBuilder类

    StringBufferTest01——String字符串拼接存在的问题

    思考:我们在实际的开发中,如果需要进行字符串的频繁拼接,会有什么问题?

    因为java中的字符串是不可变的,每一次拼接都会产生新字符串,这样会占用大量的方法区内存。造成内存空间的浪费。

    String s = "abc";

    s += "hello";

    就以上两行代码,就导致在方法区字符串常量池当中创建了3个对象:

    "abc"

    "hello"

    "abchello"

    这些对象在字符串常量池中是不会被垃圾回收器释放的,因此是非常占用内存的。

    public class StringBufferTest01 {
        public static void main(String[] args) {
            String s = "";
            // 这样做会给java的方法区字符串常量池带来很大的压力。
            for(int i = 0; i < 100; i++){
                //s += i;
                s = s + i;
                System.out.println(s);
            }
        }
    }
    

    StringBufferTest02——引入StringBuffer

    1、因此如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的:

    java.lang.StringBuffer

    java.lang.StringBuilder

    2、StringBuffer的底层实现?

    • StringBuffer的底层使用的是char[] value数组,往StringBuffer中存放字符串,实际上是放到了数组中了。
    • 默认的无参构造的初始化容量为16。
    • append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。

    3、StringBuffer与String底层实现的区别?

    String使用的是private final char value[];

    StringBuffer使用的是char value[]

    因此StringBuffer是可变的。

    为什么StringBuffer是可变的?

    image-20200913164953482

    4、如何优化StringBuffer的性能?

    在创建StringBuffer的时候尽可能给定一个初始化容量。

    最好减少底层数组的扩容次数。预估计一下,给一个大一些初始化容量。

    关键点:给一个合适的初始化容量。可以提高程序的执行效率。

    public class StringBufferTest02 {
        public static void main(String[] args) {
    
            // 创建一个初始化容量为16个byte[] 数组。(字符串缓冲区对象)
            StringBuffer stringBuffer = new StringBuffer();
    
            // 拼接字符串,以后拼接字符串统一调用 append()方法。
            // append是追加的意思。
            stringBuffer.append("a");
            stringBuffer.append("b");
            stringBuffer.append("d");
            stringBuffer.append(3.14);
            stringBuffer.append(true);
            // append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。
            stringBuffer.append(100L);
    
            System.out.println(stringBuffer.toString());
    
            // 指定初始化容量的StringBuffer对象(字符串缓冲区对象)
            StringBuffer sb = new StringBuffer(100);
            sb.append("hello");
            sb.append("world");
            sb.append("hello");
            sb.append("kitty");
    
            System.out.println(sb);
        }
    }
    

    StringBufferTest04——String为什么是不可变的&&StringBuilder/StringBuffer为什么是可变的?

    1、面试题:String为什么是不可变的?
    在源代码中,String类中有一个byte[]数组,这个byte[]数组采用了final修饰,因为数组一旦创建长度不可变。并且被final修饰的引用一旦指向某个对象之后,不可再指向其它对象,所以String是不可变的!
    "abc" 无法变成 "abcd"

    2、StringBuilder/StringBuffer为什么是可变的呢?
    在源代码中,tringBuffer/StringBuilder内部实际上是一个byte[]数组,这个byte[]数组没有被final修饰,StringBuffer/StringBuilder的初始化容量是16,当存满之后会进行扩容,底层调用了数组拷贝的方法
    System.arraycopy()...是这样扩容的。所以StringBuilder/StringBuffer适合于使用字符串的频繁拼接操作。

    package com.bjpowernode.javase.stringbuffer;
    
    public class StringBufferTest04 {
        public static void main(String[] args) {
            // 字符串不可变是什么意思?
            // 是说双引号里面的字符串对象一旦创建不可变。
            String s = "abc"; //"abc"放到了字符串常量池当中。"abc"不可变。
    
            // s变量是可以指向其它对象的。
            // 字符串不可变不是说以上变量s不可变。说的是"abc"这个对象不可变。
            s = "xyz";//"xyz"放到了字符串常量池当中。"xyz"不可变。
    
        }
    }
    

    StringBuilderTest01——StringBuffer和StringBuilder的区别?

    StringBuffer和StringBuilder的区别?
    StringBuffer中的方法都有:synchronized关键字修饰。表示StringBuffer在多线程环境下运行是安全的。
    StringBuilder中的方法都没有:synchronized关键字修饰,表示StringBuilder在多线程环境下运行是不安全的。

    public class StringBuilderTest01 {
        public static void main(String[] args) {
    
            // 使用StringBuilder也是可以完成字符串的拼接。
            StringBuilder sb = new StringBuilder();
            sb.append(100);
            sb.append(true);
            sb.append("hello");
            sb.append("kitty");
            System.out.println(sb);
        }
    }
    

    三、基础类型对应的 8 个包装类

    IntegerTest01——为什么要再提供8种包装类呢?

    1、java中为8种基本数据类型又对应准备了8种包装类型。8种包装类属于引用数据类型,父类是Object。
    2、思考:为什么要再提供8种包装类呢?

    因为8种基本数据类型不够用。比如说调用public static void doSome(Object obj){},想要传入一个100进去,但是基本数据类型属于Object,无法传入。
    所以SUN又提供对应的8种包装类型。

    package com.bjpowernode.javase.integer;
    /*
    1、java中为8种基本数据类型又对应准备了8种包装类型。8种包装类属于引用数据类型,父类是Object。
    2、思考:为什么要再提供8种包装类呢?
        因为8种基本数据类型不够用。
        所以SUN又提供对应的8种包装类型。
     */
    public class IntegerTest01 {
    
        //入口
        public static void main(String[] args) {
    
            // 有没有这种需求:调用doSome()方法的时候需要传一个数字进去。
            // 但是数字属于基本数据类型,而doSome()方法参数的类型是Object。
            // 可见doSome()方法无法接收基本数据类型的数字。那怎么办呢?可以传一个数字对应的包装类进去。
    
            // 把100这个数字经过构造方法包装成对象。
            MyInt myInt = new MyInt(100);
            // doSome()方法虽然不能直接传100,但是可以传一个100对应的包装类型。
            doSome(myInt);
        }
    
        public static void doSome(Object obj){
            //System.out.println(obj);
            System.out.println(obj.toString());
        }
    }
    

    IntegerTest02——8种基本数据类型对应的包装类型名

    1、8种基本数据类型对应的包装类型名是什么?

    基本数据类型              包装类型
    -------------------------------------
    byte                    java.lang.Byte(父类Number)
    short                   java.lang.Short(父类Number)
    int                     java.lang.Integer(父类Number)
    long                    java.lang.Long(父类Number)
    float                   java.lang.Float(父类Number)
    double                  java.lang.Double(父类Number)
    boolean                 java.lang.Boolean(父类Object)
    char                    java.lang.Character(父类Object)
    

    2、以上八种包装类中,重点以java.lang.Integer为代表进行学习,其它的类型照葫芦画瓢就行。

    3、八种包装类中其中6个都是数字对应的包装类,他们的父类都是Number,可以先研究一下Number的公共的方法:
    Number是一个抽象类,无法实例化对象。
    Number类中有这样的方法:

    • byte byteValue() :以 byte 形式返回指定的数值。
    • abstract double doubleValue():以 double 形式返回指定的数值。
    • abstract float floatValue():以 float 形式返回指定的数值。
    • abstract int intValue():以 int 形式返回指定的数值。
    • abstract long longValue():以 long 形式返回指定的数值。
    • short shortValue():以 short 形式返回指定的数值。

    这些方法其实所有的数字包装类的子类都有,这些方法是负责拆箱的。

    4、什么是拆箱和装箱?

    装箱:基本数据类型 -(转换为)->引用数据类型

    拆箱:将引用数据类型--(转换为)-> 基本数据类型

    public class IntegerTest02 {
        public static void main(String[] args) {
    
            // 123这个基本数据类型,进行构造方法的包装达到了:基本数据类型向引用数据类型的转换。
            // 基本数据类型 -(转换为)->引用数据类型(装箱)
            Integer i = new Integer(123);
    
            // 将引用数据类型--(转换为)-> 基本数据类型
            float f = i.floatValue();
            System.out.println(f); //123.0
    
            // 将引用数据类型--(转换为)-> 基本数据类型(拆箱)
            int retValue = i.intValue();
            System.out.println(retValue); //123
        }
    }
    

    IntegerTest03——Integer类的构造方法

    Integer类的构造方法:

    1. Integer(int):将int基本类型转化为包装类型。
    2. Integer(String):将String字符串转化为Integer包装类型。
    package com.bjpowernode.javase.integer;
    
    /*
    关于Integer类的构造方法,有两个:
        Integer(int)
        Integer(String)
     */
    public class IntegerTest03 {
        public static void main(String[] args) {
    
            // Java9之后不建议使用这个构造方法了。出现横线表示已过时。
            // 将数字100转换成Integer包装类型(int --> Integer)
            Integer x = new Integer(100);
            System.out.println(x);
    
            // 将String类型的数字,转换成Integer包装类型。(String --> Integer)
            Integer y = new Integer("123");
            System.out.println(y);
    
            // double -->Double
            Double d = new Double(1.23);
            System.out.println(d);
    
            // String --> Double
            Double e = new Double("3.14");
            System.out.println(e);
        }
    }
    

    IntegerTest04——获得对应包装类型的最大值、最小值

    ByteShortIntegerLongDoubleFloat都可以通过这种方式获得最大值和最小值。

    package com.bjpowernode.javase.integer;
    
    public class IntegerTest04 {
        public static void main(String[] args) {
            // 通过访问包装类的常量,来获取最大值和最小值
            System.out.println("int的最大值:" + Integer.MAX_VALUE);	//2147483647
            System.out.println("int的最小值:" + Integer.MIN_VALUE);	//-2147483648
            System.out.println("byte的最大值:" + Byte.MAX_VALUE);	//127
            System.out.println("byte的最小值:" + Byte.MIN_VALUE);	//-128
        }
    }
    

    IntegerTest05——自动装箱和自动拆箱

    自动装箱:基本数据类型自动转换成包装类。

    Integer z = 1000; // 等同于:Integer z = new Integer(1000);

    z保存的是1000的地址。

    自动拆箱:包装类自动转换成基本数据类型。

    好处:方便编程。

    public class IntegerTest05 {
        public static void main(String[] args) {
    
            // 900是基本数据类型
            // x是包装类型
            // 基本数据类型 --(自动转换)--> 包装类型:自动装箱
            Integer x = 900;
            System.out.println(x);
    
            // x是包装类型
            // y是基本数据类型
            // 包装类型 --(自动转换)--> 基本数据类型:自动拆箱
            int y = x;
            System.out.println(y);
    
            // z是一个引用,z是一个变量,z还是保存了一个对象的内存地址。
            Integer z = 1000; // 等同于:Integer z = new Integer(1000);
            // 分析为什么这个没有报错呢?
            // +两边要求是基本数据类型的数字,z是包装类,不属于基本数据类型,这里会进行自动拆箱。将z转换成基本数据类型
            // 在java5之前你这样写肯定编译器报错。
            System.out.println(z + 1);
    
            Integer a = 1000; // Integer a = new Integer(1000); a是个引用,保存内存地址指向对象。
            Integer b = 1000; // Integer b = new Integer(1000); b是个引用,保存内存地址指向对象。
            // == 比较的是对象的内存地址,a和b两个引用中保存的对象内存地址不同。
            // == 这个运算符不会触发自动拆箱机制。(只有+ - * /等运算的时候才会。)
            System.out.println(a == b); //false
        }
    }
    
    

    IntegerTest06——Integer非常重要的面试题

    Java中为了提高程序的执行效率,将[-128到127]之间所有的包装对象提前创建好,放到了一个方法区的“整数型常量池”当中了,目的是只要用这个区间的数据不需要再new了,直接从整数型常量池当中取出来。

    原理:x变量中保存的对象的内存地址和y变量中保存的对象的内存地址是一样的。

    day26-Integer的内存结构

    package com.bjpowernode.javase.integer;
    
    /*
    这个题目是Integer非常重要的面试题。
     */
    public class IntegerTest06 {
        public static void main(String[] args) {
    
            Integer a = 128;
            Integer b = 128;
            System.out.println(a == b); //false
    
            /*
            java中为了提高程序的执行效率,将[-128到127]之间所有的包装对象提前创建好,
            放到了一个方法区的“整数型常量池”当中了,目的是只要用这个区间的数据不需要
            再new了,直接从整数型常量池当中取出来。
    
            原理:x变量中保存的对象的内存地址和y变量中保存的对象的内存地址是一样的。
             */
            Integer x = 127;
            Integer y = 127;
            // == 永远判断的都是两个对象的内存地址是否相同。
            System.out.println(x == y); //true
        }
    }
    

    IntegerTest07——Integer类当中有一些常用的方法

    1. Integer x = new Integer(1000):将int型的数据转化为包装类型,(手动装箱).

    2. int y = x.intValue():将Integer类型转化为int型(手动拆箱).

    3. double doubleValue(): 以 double 类型返回该 Integer 的值。

    4. float floatValue():以 float 类型返回该 Integer 的值。

    5. long longValue(): 以 long 类型返回该 Integer 的值。

    6. short shortValue(): 以 short类型返回该 Integer 的值。

    7. static int parseInt(String s):将String类型转化为Int类型。

      静态方法:Integer.parseInt(String s)

      注意s需要是数字字符串,如“123”,否则会报异常:NumberFormatException

    8. static String toBinaryString(int i):将十进制 i 转化为2进制字符串。

    9. static String toHexString(int i):将十进制 i 转化为16进制字符串。

    10. static String toOctalString(int i):将十进制 i 转化为8进制字符串。

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

    12. static Integer valueOf(String s):返回一个表示指定的 int 值的 Integer 实例。

    package com.bjpowernode.javase.integer;
    
    import jdk.swing.interop.SwingInterOpUtils;
    
    /*
    总结一下之前所学的经典异常?
        空指针异常:NullPointerException
        类型转换异常:ClassCastException
        数组下标越界异常:ArrayIndexOutOfBoundsException
        数字格式化异常:NumberFormatException
    
    Integer类当中有哪些常用的方法呢?
     */
    public class IntegerTest07 {
        public static void main(String[] args) {
    
            // 手动装箱
            Integer x = new Integer(1000);
    
            // 手动拆箱。
            int y = x.intValue();
            System.out.println(y);
    
            Integer a = new Integer("123");
    
            // 编译的时候没问题,一切符合java语法,运行时会不会出问题呢?
            // 不是一个“数字”可以包装成Integer吗?不能。运行时出现异常。
            // java.lang.NumberFormatException
            //Integer a = new Integer("中文");
    
            // 重点方法
            // static int parseInt(String s)
            // 静态方法,传参String,返回int
            //网页上文本框中输入的100实际上是"100"字符串。后台数据库中要求存储100数字,此时java程序需要将"100"转换成100数字。
            int retValue = Integer.parseInt("123"); // String -转换-> int
            //int retValue = Integer.parseInt("中文"); // NumberFormatException
            System.out.println(retValue + 100);
    
            // 照葫芦画瓢
            double retValue2 = Double.parseDouble("3.14");
            System.out.println(retValue2 + 1); //4.140000000000001(精度问题)
    
            float retValue3 = Float.parseFloat("1.0");
            System.out.println(retValue3 + 1); //2.0
    
            // -----------------------------------以下内容作为了解,不需要掌握---------------------------------------
            // static String toBinaryString(int i)
            // 静态的:将十进制转换成二进制字符串。
            String binaryString = Integer.toBinaryString(3);
            System.out.println(binaryString); //"11" 二进制字符串
    
            // static String toHexString(int i)
            // 静态的:将十进制转换成十六进制字符串。
            String hexString = Integer.toHexString(16);
            System.out.println(hexString); // "10"
    
            // 十六进制:1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a
            hexString = Integer.toHexString(17);
            System.out.println(hexString); // "11"
    
            //static String toOctalString(int i)
            // 静态的:将十进制转换成八进制字符串。
            String octalString = Integer.toOctalString(8);
            System.out.println(octalString); // "10"
    
            System.out.println(new Object()); //java.lang.Object@6e8cf4c6
    
            // valueOf方法作为了解
            //static Integer valueOf(int i)
            // 静态的:int-->Integer
            Integer i1 = Integer.valueOf(100);
            System.out.println(i1);
    
            // static Integer valueOf(String s)
            // 静态的:String-->Integer
            Integer i2 = Integer.valueOf("100");
            System.out.println(i2);
        }
    }
    

    IntegerTest08——String-int-Integer之间互相转换

    String-int-Integer之间互相转换图:

    day26-String Integer int三种类型的互相转换

    package com.bjpowernode.javase.integer;
    
    /**
     * String int Integer之间互相转换
     */
    public class IntegerTest08 {
        public static void main(String[] args) {
    
            // String --> int
            int i1 = Integer.parseInt("100"); // i1是100数字
            System.out.println(i1 + 1); // 101
    
            // int --> String
            String s2 = i1 + ""; // "100"字符串
            System.out.println(s2 + 1); // "1001"
    
            // int --> Integer
            // 自动装箱
            Integer x = 1000;
    
            // Integer --> int
            // 自动拆箱
            int y = x;
    
            // String --> Integer
            Integer k = Integer.valueOf("123");
    
            // Integer --> String
            String e = String.valueOf(k);
        }
    }
    

    四、日期相关类

    DateTest01——Date与SimpleDateFormat的用法

    1、Date所在包:java.util.Date

    2、SimpleDateFormat所在包:java.text.SimpleDateFormat

    3、使用Date如何获得当前系统的时间【无参构造】?

    Date nowTime = new Date();
    Date data = new Date(long date)	//使用给定毫秒时间值构造一个 Date 对象。
    

    输出的格式是:Sun Sep 13 22:07:38 CST 2020

    4、String类型的日期如何转化为Date类型?

    String day = "2017-09-09 22:09:57 653";
    SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
    Date date1 = sdf1.parse(day);
    System.out.println(date1);  //Sat Sep 09 22:09:57 CST 2017
    

    5、Date类型如何转化为String类型的日期?

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
    String formatDate = sdf.format(date);
    System.out.println(formatDate); //2020-09-13 22:09:57 653
    

    6、SimpleDateFormat格式化日期参数的书写规则

    yyyy 年(年是4位)
    MM 月(月是2位)
    dd 日
    HH 时
    mm 分
    ss 秒
    SSS 毫秒(毫秒3位,最高999。1000毫秒代表1秒)

    public class DateTest01 {
        public static void main(String[] args) throws Exception {
    
            // 获取系统当前时间(精确到毫秒的系统当前时间)
            // 直接调用无参数构造方法就行。
            Date nowTime = new Date();
    
            // java.util.Date类的toString()方法已经被重写了。
            // 输出的应该不是一个对象的内存地址,应该是一个日期字符串。
            //System.out.println(nowTime); //Thu Mar 05 10:51:06 CST 2020
    
            // 日期可以格式化吗?
            // 将日期类型Date,按照指定的格式进行转换:Date --转换成具有一定格式的日期字符串-->String
            // SimpleDateFormat是java.text包下的。专门负责日期格式化的。
            /*
            yyyy 年(年是4位)
            MM 月(月是2位)
            dd 日
            HH 时
            mm 分
            ss 秒
            SSS 毫秒(毫秒3位,最高999。1000毫秒代表1秒)
            注意:在日期格式中,除了y M d H m s S这些字符不能随便写之外,剩下的符号格式自己随意组织。
             */
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            //SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
            //SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
    
            String nowTimeStr = sdf.format(nowTime);
            System.out.println(nowTimeStr);
    
            // 假设现在有一个日期字符串String,怎么转换成Date类型?
            // String --> Date
            String time = "2008-08-08 08:08:08 888";
            //SimpleDateFormat sdf2 = new SimpleDateFormat("格式不能随便写,要和日期字符串格式相同");
            // 注意:字符串的日期格式和SimpleDateFormat对象指定的日期格式要一致。不然会出现异常:java.text.ParseException
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            Date dateTime = sdf2.parse(time);
            System.out.println(dateTime); //Fri Aug 08 08:08:08 CST 2008
    
        }
    }
    

    DateTest02——System.currentTimeMillis()的用法

    1、用法

    long nowTimeMillis = System.currentTimeMillis():获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数。

    2、使用场景

    统计一个方法执行消耗的时间。

    //方法执行前
    long begin = System.currentTimeMillis();
    print();
    //方法执行后
    long end = System.currentTimeMillis();
    

    3、System类的相关属性和方法

    • System.out 【out是System类的静态变量。】
    • System.out.println() println()方法不是System类的,是PrintStream类的方法。】
    • System.gc() 建议启动垃圾回收器
    • System.currentTimeMillis() 获取自1970年1月1日到系统当前时间的总毫秒数。
    • System.exit(0) 退出JVM
    /*
    获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数。
    1秒 = 1000毫秒
     */
    public class DateTest02 {
        public static void main(String[] args) {
            // 获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数。
            long nowTimeMillis = System.currentTimeMillis();
            System.out.println(nowTimeMillis); //1583377912981
    
            // 统计一个方法耗时
            // 在调用目标方法之前记录一个毫秒数
            long begin = System.currentTimeMillis();
            print();
            // 在执行完目标方法之后记录一个毫秒数
            long end = System.currentTimeMillis();
            System.out.println("耗费时长"+(end - begin)+"毫秒");
        }
    
        // 需求:统计一个方法执行所耗费的时长
        public static void print(){
            for(int i = 0; i < 1000000000; i++){
                System.out.println("i = " + i);
            }
        }
    }
    
    

    DateTest03——获得几天前(几月前)的日期

    //获得一天前的Date对象

    Date time2 = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24);

    //格式化Date对象

    String strTime2 = sdf.format(time2);//2020-03-04 11:44:14 829

    package com.bjpowernode.javase.date;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class DateTest03 {
        public static void main(String[] args) {
    
            // 这个时间是什么时间?
            // 1970-01-01 00:00:00 001
            Date time = new Date(1); // 注意:参数是一个毫秒
    
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime = sdf.format(time);
            // 北京是东8区。差8个小时。
            System.out.println(strTime); // 1970-01-01 08:00:00 001
    
            // 获取昨天的此时的时间。
            Date time2 = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24);
            String strTime2 = sdf.format(time2);
            System.out.println(strTime2); //2020-03-04 11:44:14 829
    
            // 获取“去年的今天”的时间
        }
    }
    

    五、数字相关类

    BigDecimalTest01——高精度BigDecimal

    1、BigDecimal是什么?

    BigDecimal 属于大数据,精度极高。不属于基本数据类型,属于java对象(引用数据类型)
    这是SUN提供的一个类。专门用在财务软件当中。

    2、高精度BigDecimal使用场景

    BigDecimal用于财务数据。

    double则不能使用于财务数据中,原因是精度不够。

    import java.math.BigDecimal;
    
    public class BigDecimalTest01 {
        public static void main(String[] args) {
    
            // 这个100不是普通的100,是精度极高的100
            BigDecimal v1 = new BigDecimal(100);
            // 精度极高的200
            BigDecimal v2 = new BigDecimal(200);
            // 求和
            // v1 + v2; // 这样不行,v1和v2都是引用,不能直接使用+求和。
            BigDecimal v3 = v1.add(v2); // 调用方法求和。
            System.out.println(v3); //300
    
            BigDecimal v4 = v2.divide(v1);
            System.out.println(v4); // 2
        }
    }
    

    DecimalFormatTest01——数字的格式化

    DecimalFormat位于java.text.DecimalFormat包下。

    数字格式有哪些?

    # 代表任意数字
    , 代表千分位
    .代表小数点
    0 代表不够时补0

    ###,###.## 表示:加入千分位,保留2个小数。

    ###,###.0000 表示保留4个小数位,不够补上0。

    package com.bjpowernode.javase.number;
    
    import java.text.DecimalFormat;
    
    /*
    关于数字的格式化。(了解)
     */
    public class DecimalFormatTest01 {
        public static void main(String[] args) {
            // java.text.DecimalFormat专门负责数字格式化的。
            //DecimalFormat df = new DecimalFormat("数字格式");
    
            /*
            数字格式有哪些?
                # 代表任意数字
                , 代表千分位
                . 代表小数点
                0 代表不够时补0
    
                ###,###.##
                    表示:加入千分位,保留2个小数。
             */
            DecimalFormat df = new DecimalFormat("###,###.##");
            //String s = df.format(1234.56);
            String s = df.format(1234.561232);
            System.out.println(s); // "1,234.56"
    
            DecimalFormat df2 = new DecimalFormat("###,###.0000"); //保留4个小数位,不够补上0
            String s2 = df2.format(1234.56);
            System.out.println(s2); // "1,234.5600"
        }
    }
    

    六、Random类

    RandomTest01——生成随机数

    1、Random类常用方法

    • int nextInt():伪随机地生成并返回一个 int 值,有2的32次方的可能值。
    • int nextInt(int n):在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
    import java.util.Random;
    
    /**
     * 随机数
     */
    public class RandomTest01 {
        public static void main(String[] args) {
            // 创建随机数对象
            Random random = new Random();
    
            // 随机产生一个int类型取值范围内的数字。
            int num1 = random.nextInt();
    
            System.out.println(num1);
    
            // 产生[0~100]之间的随机数。不能产生101。
            // nextInt翻译为:下一个int类型的数据是101,表示只能取到100.
            int num2 = random.nextInt(101); //不包括101
            System.out.println(num2);
        }
    }
    

    RandomTest02——生成5个不重复的随机数[0-100],重复的话重新生成。

    package com.bjpowernode.javase.random;
    
    import java.util.Arrays;
    import java.util.Random;
    
    /*
    编写程序,生成5个不重复的随机数[0-100]。重复的话重新生成。
    最终生成的5个随机数放到数组中,要求数组中这5个随机数不重复。
     */
    public class RandomTest02 {
        public static void main(String[] args) {
    
            // 创建Random对象
            Random random = new Random();
    
            // 准备一个长度为5的一维数组。
            int[] arr = new int[5]; // 默认值都是0
            for(int i = 0; i < arr.length; i++){
                arr[i] = -1;
            }
    
            // 循环,生成随机数
            int index = 0;
            while(index < arr.length){
                // 生成随机数
                //int num = random.nextInt(101);
                //int num = random.nextInt(6); // 只能生成[0-5]的随机数!
                int num = random.nextInt(4); // 只能生成[0-3]的随机数!永远都有重复的,永远都凑不够5个。
                System.out.println("生成的随机数:" + num);
                // 判断arr数组中有没有这个num
                // 如果没有这个num,就放进去。
                if(!contains(arr, num)){
                    arr[index++] = num;
                }
            }
    
            // 遍历以上的数组
            for(int i = 0; i < arr.length; i++){
                System.out.println(arr[i]);
            }
        }
    
        /**
         * 单独编写一个方法,这个方法专门用来判断数组中是否包含某个元素
         * @param arr 数组
         * @param key 元素
         * @return true表示包含,false表示不包含。
         */
        public static boolean contains(int[] arr, int key){
            /*
            // 这个方案bug。(排序出问题了。)
            // 对数组进行升序
            //Arrays.sort(arr);
            // 进行二分法查找
            // 二分法查找的结果 >= 0说明,这个元素找到了,找到了表示存在!
            //return Arrays.binarySearch(arr, key) >= 0;
             */
    
            for(int i = 0; i < arr.length; i++){
                if(arr[i] == key){
                    // 条件成立了表示包含,返回true
                    return true;
                }
            }
            // 这个就表示不包含!
            return false;
        }
    }
    

    七、Enum枚举类型

    EnumTest01——引入枚举类型?

    现有一方法如下:

    public static int divide(int a, int b){
        try {
            int c = a / b;
            // 程序执行到此处表示以上代码没有发生异常。表示执行成功!
            return 1;
        } catch (Exception e){
            // 程序执行到此处表示以上程序出现了异常!
            // 表示执行失败!
            return 0;
        }
    }
    

    该方法返回值类型为int,拿到返回值之后需要判断返回值是0或者1,如果是0,则计算失败,1则表示计算成功!

    System.out.println(retValue == 1 ? "计算成功" : "计算失败");

    这个方法有个缺陷就是:如果返回值写错了,写成了10,但是编译器是不会报错的。

    改进:返回值声明为Boolean型。

    System.out.println(success ? "计算成功" : "计算失败");

    思考:以上的这个方法设计没毛病,挺好,返回true和false表示两种情况,
    但是在以后的开发中,有可能遇到一个方法的执行结果可能包括三种情况,
    四种情况,五种情况不等,但是每一个都是可以数清楚的,一枚一枚都是可以
    列举出来的。这个布尔类型就无法满足需求了。此时需要使用java语言中的
    枚举类型。

    public class EnumTest01 {
        public static void main(String[] args) {
    
            //System.out.println(10 / 0); //java.lang.ArithmeticException: / by zero
            /*
            int retValue = divide(10, 2);
            System.out.println(retValue == 1 ? "计算成功" : "计算失败"); // 1
    
            int retValue2 = divide(10, 0);
            System.out.println(retValue2 == 0 ? "计算失败" : "计算成功"); // 0
             */
    
            boolean success = divide(10, 0);
            System.out.println(success ? "计算成功" : "计算失败");
        }
    
        /**
         * 需求(这是设计者说的!):以下程序,计算两个int类型数据的商,计算成功返回1,计算失败返回0
         * @param a int类型的数据
         * @param b int类型的数据
         * @return 返回1表示成功,返回0表示失败!
         */
        /*
        public static int divide(int a, int b){
            try {
                int c = a / b;
                // 程序执行到此处表示以上代码没有发生异常。表示执行成功!
                return 1;
            } catch (Exception e){
                // 程序执行到此处表示以上程序出现了异常!
                // 表示执行失败!
                return 0;
            }
        }
         */
    
        // 设计缺陷?在这个方法的返回值类型上。返回一个int不恰当。
        // 既然最后的结果只是成功和失败,最好使用布尔类型。因为布尔类型true和false正好可以表示两种不同的状态。
        /*
        public static int divide(int a, int b){
            try {
                int c = a / b;
                // 返回10已经偏离了需求,实际上已经出错了,但是编译器没有检查出来。
                // 我们一直想追求的是:所有的错误尽可能让编译器找出来,所有的错误越早发现越好!
                return 10;
            } catch (Exception e){
                return 0;
            }
        }
        */
    
        // 这种设计不错。
        public static boolean divide(int a, int b){
            try {
                int c = a / b;
                return true;
            } catch (Exception e){
                return false;
            }
        }
    }
    

    EnumTest02——采用枚举的方式改造程序

    1、什么是枚举类型 ?

    枚举是一种引用数据类型

    2、枚举类型怎么定义,语法是什么?

    enum 枚举类型名{
    枚举值1,枚举值2
    }

    3、结果只有两种情况的,建议使用布尔类型。

    4、结果超过两种并且还是可以一枚一枚列举出来的,建议使用枚举类型。

    例如:颜色、四季、星期等都可以使用枚举类型 .

    5、枚举编译之后也是生成class文件。

    6、枚举中的每一个值可以看做是常量。

    public class EnumTest02 {
        public static void main(String[] args) {
            Result r = divide(10, 2);
            System.out.println(r == Result.SUCCESS ? "计算成功" : "计算失败");
        }
        /**
         * 计算两个int类型数据的商。
         * @param a int数据
         * @param b int数据
         * @return Result.SUCCESS表示成功,Result.FAIL表示失败!
         */
        public static Result divide(int a, int b){
            try {
                int c = a / b;
                return Result.SUCCESS;
            } catch (Exception e){
                return Result.FAIL;
            }
        }
    }
    
    // 枚举:一枚一枚可以列举出来的,才建议使用枚举类型。
    // 枚举编译之后也是生成class文件。
    // 枚举也是一种引用数据类型。
    // 枚举中的每一个值可以看做是常量。
    enum Result{
        // SUCCESS 是枚举Result类型中的一个值
        // FAIL 是枚举Result类型中的一个值
        // 枚举中的每一个值,可以看做是“常量”
        SUCCESS, FAIL
    }
    
  • 相关阅读:
    新经资讯项目业务逻辑梳理
    HTTP状态保持的原理
    CSRF的原理和防范措施
    装饰器路由具体实现梳理
    Flask中异常捕获
    正则匹配路由
    (搬运以学习)flask 上下文的实现
    flask之请求钩子
    如何在linux中创建虚拟环境
    面包屑导航
  • 原文地址:https://www.cnblogs.com/nieaojie625/p/13663816.html
Copyright © 2020-2023  润新知