0
点赞
收藏
分享

微信扫一扫

Java笔记11 常用类

扬帆远航_df7c 2022-03-12 阅读 53

11.1 包装类

11.1.1 包装类的分类

针对八种基本类型相应的引用类型——包装类

有了类的特点,就可以调用类中的方法

基本数据类型 包装类
boolean Boolean
char Character
byte Byte
short Short
int Integer
long Long
float Float
double Double

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

11.1.2 包装类和基本数据的转换

  1. jdk5之前用手动装箱和拆箱的方式

    1. 手动装箱:

      1. 包装类型 包装类型对象 = new 包装类型(基本类型变量);

      2. 或者:包装类型 包装类型对象 = 包装类型.valueOf(基本类型变量);

      3. int n1 = 100;
        Integer integer = new Integer(n1);
        Integer integer1 = Integer.valueOf(n1);
        
    2. 手动拆箱:

      1. 基本类型 基本类型变量名 = 包装类型对象.xxxValue();
      2. 如:int i = integer.intValue();
  2. jdk5及以后采用自动装箱和拆箱的方式(直接用=)

    1. 自动装箱:
      1. Integer integer2 = n2; //底层使用的是 Integer.valueOf(n2)
    2. 自动拆箱:
      1. int n3 = integer2; //底层仍然使用的是 intValue()方法

11.1.3 练习

下面两段代码输出结果相同吗?

  1. Object obj1 = true ? new Integer(1) : new Double(2.0);
    System.out.println(obj1);	//1.0
    //三元运算符是一个整体,前边是Integer,后边是Double
    //Double精度更高,自动类型提升
    
  2. Object obj2;
    if (true) {
        obj2 = new Integer(1);
    } else {
        obj2 = new Double(2.0);
    }
    System.out.println(obj2);	//1
    

11.1.4 包装类型和String类型的相互转换

以Integer为例:

public class WrapperString {
    public static void main(String[] args) {
        //包装类(Integer) =》 String
        Integer i = 100;    //自动装箱
        //方式1
        String str1 = i + "";
        //方式2
        String str2 = i.toString();
        //方式3
        String str3 = String.valueOf(i);

        //String =》 包装类(Integer)
        String str4 = "12345";
        //方式1
        Integer i2 = Integer.parseInt(str4);    //parseInt()返回int,然后自动装箱
        //方式2
        Integer i3 = new Integer(str4); //构造器,本质还是调用parseInt()
    }
}

11.1.5 Integer类和Character类的常用方法

public class WrapperMethod {
    public static void main(String[] args) {
        //Integer
        System.out.println(Integer.MIN_VALUE);//返回最小值
        System.out.println(Integer.MAX_VALUE);//返回最大值

        //Character
        System.out.println(Character.isDigit('a'));//判断是不是数字
        System.out.println(Character.isLetter('a'));//判断是不是字母
        System.out.println(Character.isUpperCase('a'));//判断是不是大写
        System.out.println(Character.isLowerCase('a'));//判断是不是小写
        System.out.println(Character.isWhitespace('a'));//判断是不是空格
        System.out.println(Character.toUpperCase('a'));//转成大写
        System.out.println(Character.toLowerCase('a'));//转成小写
    }
}

11.1.6 Integer面试题

//输出结果为?
public class IntegerExer {
    public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j);

        Integer m = 1;
        Integer n = 1;
        System.out.println(m == n);

        Integer x = 128;
        Integer y = 128;
        System.out.println(x == y);
        
        Integer a = 127;
        int b = 127;
        System.out.println(a == b);
    }
}
  1. i 和 j 为 new 出来的不同 Integer 对象,通过 = 比较结果为 false

  2. m 和 n 采用自动装箱,底层是调用 valueOf() 方法,查看源码

    1. public static Integer valueOf(int i) {
              if (i >= IntegerCache.low && i <= IntegerCache.high)
                  return IntegerCache.cache[i + (-IntegerCache.low)];
              return new Integer(i);
          }
      //IntegerCache.low = -128
      //IntegerCache.high = 127
      
    2. 可以看到,但在范围-128~127之间时,直接返回一个Integer对象,没有new,因此m和n指向的是同一个对象,因此 = 比较的结果为 true

  3. x 和 y由于超出了-128~127的范围,所以指向的是两个new的Integer对象,因此 = 比较的结果为 false

  4. a 和 b 比较,由于 b 是基本数据类型,判断的是值是否相等,因此输出true

11.2 String类

11.2.1 介绍

  1. String对象用于保存字符串,也就是一串字符序列
  2. 字符串常量对象是用双引号括起来的字符序列。例如:“你好”、“12.97”、"boy"等
  3. 字符串的字符使用Unicode编码,一个字符(不管是字母还是汉字)占两个字节
  4. String类常用的构造器:
    1. String s1 = new String();
    2. String s2 = new String(String original);
    3. String s3 = new String(char[] a);
    4. String s1 = new String(char[] a, int startIndex, int count);

在这里插入图片描述

串行化 可以在网络传输

11.2.2 创建String对象的两种方式

  1. 直接赋值String s = "hello";
    1. 先从常量池查看是否有"hello"数据空间,如果有,直接指向;如果没有,则重新创建,然后指向。s最终指向的是常量池的空间地址
  2. 调用构造器String s2 = new String("hello");
    1. 先在堆中创建空间,里边维护了value属性,指向常量池中的hello空间。如果常量池中没有"hello",重新创建,如果有,直接通过value指向。s2最终指向的是堆中的空间地址
    2. value是final类型的,指向的地址不可改变,但其地址存放的内容可以改变

在这里插入图片描述

11.2.3 练习

  1. String a = "abc";	//常量池中找"abc",没有则创建
    String b = "abc";	//常量池中找"abc",前边语句执行过一定有,因此和a指向同一个
    System.out.println(a.equals(b));	//true
    System.out.println(a == b);			//true
    
  2. String a = new String("abc");
    String b = new String("abc");
    System.out.println(a.equals(b));	//true
    System.out.println(a == b);			//false,a和b为指向value的地址,不相同,两个value指向常量池中的同一个"abc"
    
  3. String a = "abc";
    String b = new String("abc");
    System.out.println(a.equals(b));	//true
    System.out.println(a == b);			//false
    System.out.println(a == b.intern());	//true
    System.out.println(b == b.intern());	//false
    //调用intern()方法时,如果池中已经包含一个等于此String对象的字符串
    //(通过equals(Object)方法确定),则返回池中的字符串
    //否则,将String对象添加到池中,并返回该String对象的引用
    //intern()方法最终返回的是常量池的地址
    

11.2.4 字符串的特性

  1. String是一个final类,代表不可改变的字符序列
  2. 字符串是不可变的,一个字符串对象一旦被分配,其内容是不可变的

11.2.5 面试题

  1. //以下代码创建了几个对象
    String s1 = "hello";
    s1 = "haha";
    //创建了两个对象
    

在这里插入图片描述

  1. //以下代码创建了几个对象
    String a = "hello" + "abc";
    //创建了一个对象,编译器会优化为String a = "helloabc"
    
  2. //以下代码创建了几个对象
    String a = "hello";
    String b = "abc";
    String c = a + b;
    //共三个String对象
    //String c = a + b底层逻辑为:
    //StringBuilder sb = new StringBuilder();
    //sb.append(a); sb.append(b);将a和b的值追加到sb
    //String c = sb.toString(); 将sb转换为String对象返回给c
    //toString()使用的是new,所以c指向堆
    //String a = "hello" + "abc";常量相加,看的是池
    //String c = a + b;变量相加,是在堆中
    

    在这里插入图片描述

  3. String s1 = "hello";
    String s2 = "abc";
    String s3 = "helloabc";
    String s4 = (S1 + S2).intern();
    System.out.println(s3 == s4);	//true
    System.out.println(s3.equals(s4));	//true
    
  4. //!!!输出什么?
    public class StringExer {
        String str = new String("hsp");
        final char[] ch = {'j','a','v','a'};
        public void change(String str, char ch[]) {
            str = "java";
            ch[0] = 'h';
        }
    
        public static void main(String[] args) {
            StringExer stringExer = new StringExer();
            stringExer.change(stringExer.str,stringExer.ch);
            System.out.print(stringExer.str + " ");//hsp
            System.out.println(stringExer.ch);	//hava
        }
    }
    

    在这里插入图片描述

    11.2.6 String类的常用方法

    11.2.6.1 说明

    String类是保存字符串常量的,每次更新都要重新开辟空间,效率较低,因此Java设计者还提供了StringBuilder和StringBuffer来增强String的功能,并提高效率

    11.2.6.2 常用方法

    • equals:区分大小写,判断内容是否相等

    • equalsIgnoreCase:忽略大小写的判断内容是否相等

    • length:获取字符的个数,字符串的长度

    • indexOf:获取字符在字符串中第一次出现的索引,找不到则返回-1

    • lastIndexOf:获取字符在字符串中最后一次出现的索引,索引从零开始,找不到则返回-1

    • subString:截取指定范围的子串,startIndex~endIndex-1

      • String name = "hello,张三";
        System.out.println(name.substring(6));//截取索引6后面的字符
        
      • System.out.println(name.substring(2,5));//llo
        
    • trim:去前后空格

    • charAt:获取某索引处的字符,注意不能使用Str[index]这种方式

    • toUpperCase:转换为大写

    • toLowerCase:转换为小写

    • connat:拼接字符串

    • replace:替换字符串中的字符

      • s1.replace()方法执行后返回的结果才是替换过的,s1无变化
    • split:分割字符串,对于某些分割字符串我们需要转义字符\,如:|\”等

      • Sreing road = "E:\\aaa\\bbb";
        String split = road.split("\\\\");
        
    • compareTo:比较两个字符串的大小

      • public int compareTo(String anotherString) {
                int len1 = value.length;
                int len2 = anotherString.value.length;
                int lim = Math.min(len1, len2);
                char v1[] = value;
                char v2[] = anotherString.value;
        
                int k = 0;
                while (k < lim) {
                    char c1 = v1[k];
                    char c2 = v2[k];
                    if (c1 != c2) {
                        return c1 - c2;
                    }
                    k++;
                }
                return len1 - len2;
            }
        

        从第一个字符开始比较,若不相同返回Unicode值差值,若都相同则返回长度差值

    • toCharArray:转换为字符串数组

    • format:格式化字符串

      • 占位符:%s字符串、%c字符、%d整型、%.2f浮点型

      • %.2f 表示使用小数来替换,替换后,只会保留小数点两位, 并且进行四舍五入的处理

      • String name = "john";
        int age = 10;
        double score = 56.857;
        char gender = '男';
        String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 性别是%c.希望大家喜欢我!";
        String info2 = String.format(formatStr, name, age, score, gender);
        System.out.println(info2);
        //我的姓名是john 年龄是10,成绩是56.86 性别是男.希望大家喜欢我!
        

11.3 StringBuffer类

11.3.1 介绍

  • StringBuffer代表可变的字符序列,可以对字符串内容进行增删

  • 很多方法和String相同,但StringBuffer是可变长度的

  • StringBuffer是一个容器

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
  1. StringBuffer 的直接父类 是 AbstractStringBuilder
  2. StringBuffer 实现了 Serializable, 即 StringBuffer 的对象可以串行化
  3. 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final,该 value 数组存放 字符串内容,引出存放在堆中的
  4. StringBuffer 是一个 final 类,不能被继承
  5. 因为 StringBuffer 字符内容是存在 char[] value, 所有在变化(增加/删除) ,不用每次都更换地址(即不是每次创建新对象), 所以效率高于 String

11.3.2 与String的区别

  1. String保存的是字符常量,里边的值不能更改,每次String类的更新实际上就是更改地址,效率较低
  2. StringBuffer保存的是字符串变量,里边的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率较高

11.3.3 String与StringBuffer相互转换

public class StringAndStringBuffer {
    public static void main(String[] args) {
        //String —> StringBuffer
        String str = "hello tom";
        //方式 1 使用构造器
        //注意: 返回的才是 StringBuffer 对象,对 str 本身没有影响
        StringBuffer stringBuffer = new StringBuffer(str);
        //方式 2 使用的是 append 方法
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1 = stringBuffer1.append(str);
        
        //StringBuffer -> String
        StringBuffer stringBuffer3 = new StringBuffer("韩顺平教育");
        //方式 1 使用 StringBuffer 提供的 toString 方法
        String s = stringBuffer3.toString();
        //方式 2: 使用构造器来搞定
        String s1 = new String(stringBuffer3);
    }
} 

11.3.4 StringBuffer常用方法

public class StringBufferMethod {
    public static void main(String[] args) {
        StringBuffer s = new StringBuffer("hello");
        
        //增
        s.append(',');// "hello,"
        s.append("张三丰");//"hello,张三丰"
        s.append("赵敏").append(100).append(true).append(10.5);//"hello,张三丰赵敏100true10.5"
        System.out.println(s);//"hello,张三丰赵敏100true10.5"
        
        //删
        /*
        * 删除索引为>=start && <end 处的字符
        * 解读: 删除 11~14 的字符 [11, 14)
        */
        s.delete(11, 14);
        System.out.println(s);//"hello,张三丰赵敏true10.5"
        
        //改
        //老韩解读,使用 周芷若 替换 索引 9-11 的字符 [9,11)
        s.replace(9, 11, "周芷若");
        System.out.println(s);//"hello,张三丰周芷若 true10.5"
        //查找指定的子串在字符串第一次出现的索引,如果找不到返回-1
        int indexOf = s.indexOf("张三丰");
        System.out.println(indexOf);//6
        
        //插
        //老韩解读,在索引为 9 的位置插入 "赵敏",原来索引为 9 的内容自动后移
        s.insert(9, "赵敏");
        System.out.println(s);//"hello,张三丰赵敏周芷若 true10.5"
        
        //长度
        System.out.println(s.length());//22
        System.out.println(s);
    }
}

11.3.5 练习

  1. public class StringBufferExercise01 {
        public static void main(String[] args) {
            String str = null;// ok
            StringBuffer sb = new StringBuffer(); //ok
            sb.append(str);//需要看源码 , 底层调用的是 AbstractStringBuilder 的 appendNull,将空对象转换为"null"
            System.out.println(sb.length());//4
            System.out.println(sb);//null
            //下面的构造器,会抛出 NullpointerException
            StringBuffer sb1 = new StringBuffer(str);//看底层源码 super(str.length() + 16);
            System.out.println(sb1);
        }
    }
    

11.4 StringBuilder类

11.4.1 介绍

  1. 一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(不是线程安全的)。该类被设计用作StringBuffer的一个简易替换,用作字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快
  2. 在StringBuilder上的主要操作是append方法和insert方法,可重载这些方法,以接收任意类型的数据

11.4.2 常用方法

StringBuilder和StringBuffer的方法是一样的

11.4.3 String、StringBuffer 和 StringBuilder 的比较

  1. StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样

  2. String:不可变字符序列,效率低,但是复用率高

  3. StringBuffer:可变字符序列,效率较高(增删),线程安全

  4. StringBuilder:可变字符序列,效率最高,线程不安全

  5. String使用说明:

    1. String s = "a";	//创建了一个字符串
      s += "b";	//实际上原来的"a"字符串已经被丢弃了,现在又产生了一个新的字符串s+"b"(也就是"ab")
      //如果多次执行这些改变字符串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。
      //如果这样的操作放在循环中,会极大影响程序的性能
      //结论:如果我们对String做大量修改,不要使用String
      

11.4.4 String、StringBuffer 和 StringBuilder 的选

  1. 如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
  2. 如果字符串存在大量的修改操作,并存在单线程的情况,使用StringBuilder
  3. 如果字符串存在大量的修改操作,并存在多线程的情况,使用StringBuffer
  4. 如果我们的字符串很少修改,被多个对象引用,使用String,比如配置信息等

11.5 Math类

11.5.1 介绍

Math类包含用于执行基本数学运算的方法,比如初等指数、对数、平方根和三角函数

11.5.2 方法(均为静态)

有很多,看文档,举例:

Modifier and Type Method and Description
static double abs(double a)返回值为 double绝对值。
static float abs(float a)返回 float值的绝对值。
static int abs(int a)返回值为 int绝对值。
static long abs(long a)返回值为 long绝对值。
static double acos(double a)返回值的反余弦值;返回的角度在0.0到pi的范围内。
static int addExact(int x, int y)返回其参数的总和,如果结果溢出int,则抛出 int
static long addExact(long x, long y)返回其参数的总和,如果结果溢出long,则抛出 long
static double asin(double a)返回值的正弦值;返回角度在pi / 2到pi / 2的范围内。
static double atan(double a)返回值的反正切值;返回角度在pi / 2到pi / 2的范围内。
static double atan2(double y, double x)返回从直角坐标(转换角度 thetaxy )为极坐标 (R,θ-)。
static double cbrt(double a)返回 double值的多维数据集根。
static double ceil(double a)返回大于或等于参数的最小(最接近负无穷大) double值,等于一个数学整数。

11.5.3 示例

public class MathMethod {
    public static void main(String[] args) {
        //Math 常用的方法(静态方法)
        //1.abs 绝对值
        int abs = Math.abs(-9);
        System.out.println(abs);//9
        //2.pow 求幂
        double pow = Math.pow(2, 4);//2 的 4 次方
        System.out.println(pow);//16
        //3.ceil 向上取整,返回>=该参数的最小整数(转成 double);
        double ceil = Math.ceil(3.9);
        System.out.println(ceil);//4.0
        //4.floor 向下取整,返回<=该参数的最大整数(转成 double)
        double floor = Math.floor(4.001);
        System.out.println(floor);//4.0
        //5.round 四舍五入 Math.floor(该参数+0.5)
        long round = Math.round(5.51);
        System.out.println(round);//6
        //6.sqrt 求开方
        double sqrt = Math.sqrt(9.0);
        System.out.println(sqrt);//3.0
        //7.random 求随机数
        // random 返回的是 0 <= x < 1 之间的一个随机小数
        // 思考:请写出获取 a-b 之间的一个随机整数,a,b 均为整数 ,比如 a = 2, b=7
        // 即返回一个数 x, 2 <= x <= 7
        // Math.random() * (b-a) 返回的就是 0 <= 数 <= b-a
        // (1) (int)(a) <= x <= (int)(a + Math.random() * (b-a +1) )
        // (2) 使用具体的数给小伙伴介绍 a = 2,b = 7
        // (int)(a + Math.random() * (b-a +1) ) = (int)( 2 + Math.random()*6)
        // Math.random()*6 返回的是 0 <= x < 6 小数
        // 2 + Math.random()*6 返回的就是 2<= x < 8 小数
        // (int)(2 + Math.random()*6) = 2 <= x <= 7
        // (3) 公式就是 (int)(a + Math.random() * (b-a +1) )
        for(int i = 0; i < 100; i++) {
        System.out.println((int)(2 + Math.random() * (7 - 2 + 1)));
        }
        //max , min 返回最大值和最小值
        int min = Math.min(1, 9);
        int max = Math.max(45, 90);
        System.out.println("min=" + min);
        System.out.println("max=" + max);
    }
}

11.6 Arrays类

11.6.1 常见方法

Arrays包含了一系列静态方法,用于管理和操作数组

  1. toString:返回数组的字符串形式
  2. sort:排序(自然排序和定制排序)
  3. binarySearch:通过二分搜索法进行查找,要求必须排好序
  4. copyOf:复制指定的数组
  5. fill:数组元素填充
  6. equals:比较两个数组元素是否完全一致
  7. asList:将数组转换为list

11.6.2 示例

  1. //toString
    Integer[] integers = {1, 20, 90};
    System.out.println(Arrays.toString(integers));//[1, 20, 90]
    
  2. //sort
    Integer arr[] = {1, -1, 7, 0, 89};
    //默认排序
    Arrays.sort(arr);
    //定制排序,通过传入接口Comparator
    Arrays.sort(arr, new Comparator() {
        @Override
            public int compare(Object o1, Object o2) {
            Integer i1 = (Integer) o1;
            Integer i2 = (Integer) o2;
            return i2 - i1;
        }
    });
    
    1. 调用 定制排序 时,传入两个参数

      1. 排序的数组 arr
      2. 实现了 Comparator 接口的匿名内部类 , 要求实现 compare 方法
    2. Arrays.sort(arr, new Comparator());会调用TimSort类的private static void binarySort(T[] a, int lo, int hi, int start, Comparator<?super T> c)()

    3. 执行到 binarySort 方法的代码, 会根据动态绑定机制 c.compare()执行我们传入的匿名内部类的 compare ()

      1. while (left < right) {
            int mid = (left + right) >>> 1;
            if (c.compare(pivot, a[mid]) < 0)
            right = mid;
            else
            left = mid + 1;
        }
        
    4. ) public int compare(Object o1, Object o2) 返回的值>0 还是 <0会影响整个排序结果, 这就充分体现了 接口编程+动态绑定+匿名内部类的综合使用,将来的底层框架和源码的使用方式,会非常常见

  3. //结合冒泡 + 定制排序
    public class ArraysSortCustom {
        public static void main(String[] args) {
            int[] arr = {12,2,-3,0,89,45};
            bubble(arr, new Comparator() {
                @Override
                public int compare(Object o1, Object o2) {
                    Integer i1 = (Integer) o1;
                    Integer i2 = (Integer) o2;
    //                return i1 - i2;   //递增
                    return i2 -i1;  //递减
                }
            });
            System.out.println(Arrays.toString(arr));
        }
        public static void bubble(int[] arr, Comparator c) {
            int temp = 0;
            for (int i = 0; i < arr.length - 1; i++) {
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    //数组排序由 c.compare(arr[j], arr[j + 1])返回的值决定
                    if(c.compare(arr[j], arr[j+1]) > 0) {
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
        }
    }
    
  4. //binarySearch,必须排好序
    Integer[] arr = {1, 2, 90, 123, 567};
    int index = Arrays.binarySearch(arr, 567);
    System.out.println("index=" + index);
    
  5. //copyOf
    Integer[] newArr = Arrays.copyOf(arr, arr.length);
    //1. 从 arr 数组中,拷贝 arr.length 个元素到 newArr 数组中
    //2. 如果拷贝的长度 > arr.length 就在新数组的后面 增加 null
    //3. 如果拷贝长度 < 0 就抛出异常 NegativeArraySizeException
    //4. 该方法的底层使用的是 System.arraycopy()
    
  6. //fill
    Integer[] num = new Integer[]{9,3,2};
    Arrays.fill(num, 99);	
    //使用 99 去填充 num 数组,可以理解成是替换原理的元素
    System.out.println(Arrays.toString(num));	//[99, 99, 99]
    
  7. //equals 比较两个数组元素内容是否完全一致
    Integer[] arr2 = {1, 2, 90, 123};
    boolean equals = Arrays.equals(arr, arr2);
    
  8. //asList 将一组值,转换成 list
    List asList = Arrays.asList(2,3,4,5,6,1);
    //1. asList 方法,会将 (2,3,4,5,6,1)数据转成一个 List 集合
    //2. 返回的 asList 编译类型 List(接口)
    //3. asList 运行类型 java.util.Arrays#ArrayList, 是 Arrays 类的
    // 静态内部类 private static class ArrayList<E> extends AbstractList<E>
    // implements RandomAccess, java.io.Serializable
    

11.6.3 练习

在这里插入图片描述

public class ArrayExercise {
    public static void main(String[] args) {
        Book[] books = new Book[4];
        books[0] = new Book("红楼梦",100);
        books[1] = new Book("西游记前传",90);
        books[2] = new Book("三国演义",5);
        books[3] = new Book("水浒",300);
        //按价格排序
        sortBooks(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book b1 = (Book) o1;
                Book b2 = (Book) o2;
                return (int)(b1.getPrice() - b2.getPrice());
            }
        });
        printBooks(books);
        //按书名长度排序
        sortBooks(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book b1 = (Book) o1;
                Book b2 = (Book) o2;
                return (int)(b1.getName().length() - b2.getName().length());
            }
        });
        printBooks(books);
    }

    public static Book[] sortBooks(Book[] books, Comparator c) {
        Book temp = null;
        for (int i = 0; i < books.length - 1; i++) {
            for (int j = 0; j < books.length - 1 - i; j++) {
                if(c.compare(books[j], books[j+1]) > 0) {
                    temp = books[j];
                    books[j] = books[j+1];
                    books[j+1] = temp;
                }
            }
        }
        return books;
    }
    public static void printBooks(Book[] books){
        for (Book book : books) {
            System.out.println(book);
        }
        System.out.println("===========================");
    }
}

class Book {
    private String name;
    private double price;

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "书名:" + name + ", 价格:" + price + "元";
    }
}

11.7 System类

11.7.1 常用方法

  1. exit:退出当前程序
  2. arraycopy:复制数组元素,比较适合底层调用,一般使用Array.copyOf完成复制数组
    1. 语法:System.arraycopy(src, srcPos, dest, destPos, length);
  3. currentTimeMillens:返回当前时间距离1970-01-01的毫秒数
  4. gc:运行垃圾回收机制 System.gc()

11.7.2 示例

//exit
System.exit(0);//exit(0) 表示程序退出,0表示一个状态,正常的状态

//arraycopy
int[] src = {1, 2, 3};
int dest = new int[3];
System.arraycopy(src, 0, dest, 0, 3);

//currentTimeMillens
System.out.println(System.currentTimeMillis());

11.8 BigInteger类和BigDecimal类

11.8.1 介绍

  1. BigInteger适合保存比较大的整数
  2. BigDecimal适合保存精度更高的浮点数

11.8.2 常用方法

在对 BigInteger 和 BigDecimal 进行加减乘除的时候,需要使用对应的方法,不能直接进行 + - * /

  1. add:加
  2. subtract:减
  3. multiply:乘
  4. divide:除

11.8.3 示例

  1. //BigInteger
    BigInteger bigInteger = new BigInteger("23788888899999999999999999999");
    BigInteger bigInteger2 = new BigInteger("10099999999999999999999999999999999999999999999999999999999999999999999999999999999");
    System.out.println(bigInteger);
    //加
    BigInteger add = bigInteger.add(bigInteger2);
    System.out.println(add);
    //减
    BigInteger subtract = bigInteger.subtract(bigInteger2);
    System.out.println(subtract);
    //乘
    BigInteger multiply = bigInteger.multiply(bigInteger2);
    System.out.println(multiply);
    //除
    BigInteger divide = bigInteger.divide(bigInteger2);
    System.out.println(divide);
    
  2. //BigDecimal 
    BigDecimal bigDecimal = new BigDecimal("1999.111111111199999999922222228888");
    BigDecimal bigDecimal2 = new BigDecimal("3");
    System.out.println(bigDecimal);
    System.out.println(bigDecimal.add(bigDecimal2));
    System.out.println(bigDecimal.subtract(bigDecimal2));
    System.out.println(bigDecimal.multiply(bigDecimal2));
    //System.out.println(bigDecimal.divide(bigDecimal2));//可能因为结果是无限循环小数,抛出异常 ArithmeticException
    //解决方法:在调用 divide 方法时,指定精度即可. BigDecimal.ROUND_CEILING
    //指定后,如果有无限循环小数,就会保留 分子 的精度
    System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));
    

11.9 日期类

11.9.1 第一代日期类

  1. Date:精确到毫秒,代表特定的瞬间,很多方法已经弃用
  2. SimpleDateFormat:格式化和解析日期的类,它允许进行格式化(日期->文本)、解析(文本->日期)和规范化
字母 日期或时间元素 表示 示例
G Era designator Text AD
y Year Year 1996; 96
Y Week year Year 2009; 09
M Month in year (context sensitive) Month July; Jul; 07
L Month in year (standalone form) Month July; Jul; 07
w Week in year Number 27
W Week in month Number 2
D Day in year Number 189
d Day in month Number 10
F Day of week in month Number 2
E Day name in week Text Tuesday; Tue
u Day number of week (1 = Monday, …, 7 = Sunday) Number 1
a Am/pm marker Text PM
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
h Hour in am/pm (1-12) Number 12
m Minute in hour Number 30
s Second in minute Number 55
S Millisecond Number 978
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800
X Time zone ISO 8601 time zone -08; -0800; -08:00

示例:

public class Date01 {
    public static void main(String[] args) throws ParseException {
        //1. 获取当前系统时间
        //2. 这里的 Date 类是在 java.util 包
        //3. 默认输出的日期格式是国外的方式, 因此通常需要对格式进行转换
        Date d1 = new Date(); //获取当前系统时间
        System.out.println("当前日期=" + d1);
        Date d2 = new Date(9234567); //通过指定毫秒数得到时间
        System.out.println("d2=" + d2); //获取某个时间对应的毫秒数
        
        //1. 创建 SimpleDateFormat 对象,可以指定相应的格式
        //2. 这里的格式使用的字母是规定好,不能乱写
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 hh:mm:ss E");
        String format = sdf.format(d1); // format:将日期转换成指定格式的字符串
        System.out.println("当前日期=" + format);
        
        //1. 可以把一个格式化的 String 转成对应的 Date
        //2. 得到 Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换
        //3. 在把 String -> Date , 使用的 sdf 格式需要和你给的 String 的格式一样,否则会抛出转换异常
        String s = "1996 年 01 月 01 日 10:20:30 星期一";
        Date parse = sdf.parse(s);
        System.out.println("parse=" + sdf.format(parse));
    }
}

11.9.2 第二代日期类

  1. 第二代日期类,主要就是Calender类(日历)
  2. Calendar类是一个抽象类,它为特定瞬间与一组如YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。

示例:

public class Calendar_ {
    public static void main(String[] args) {
        
        //1. Calendar 是一个抽象类, 并且构造器是 private
        //2. 可以通过 getInstance() 来获取实例
        //3. 提供大量的方法和字段提供给程序员
        //4. Calendar 没有提供对应的格式化的类,因此需要程序员自己组合来输出(灵活)
        //5. 如果我们需要按照 24 小时进制来获取时间, Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY
        Calendar c = Calendar.getInstance(); //创建日历类对象//比较简单,自由
        System.out.println("c=" + c);
        //2.获取日历对象的某个日历字段
        System.out.println("年:" + c.get(Calendar.YEAR));
        // 这里为什么要 + 1, 因为 Calendar 返回月时候,是按照 0 开始编号
        System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
        System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
        System.out.println("小时:" + c.get(Calendar.HOUR));
        System.out.println("分钟:" + c.get(Calendar.MINUTE));
        System.out.println("秒:" + c.get(Calendar.SECOND));
        //Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
        System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" +
        c.get(Calendar.DAY_OF_MONTH) +
        " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND) );
    }
}

11.9.3 第三代日期类

11.9.3.1 前两代不足

Date类的大部分方法在jdk1.1引入Calendar类后被弃用了,Calendar也存在的问题:

  1. 可变性:像日期和时间这样的类应该是不可变的
  2. 偏移性:Date中的年份是从1900开始,月份是从0开始
  3. 格式化:格式化只对Date有用,Calendar不行
  4. 它们不是线程安全的
  5. 不能处理闰秒(每隔两天,多出1秒)

11.9.3.2 LocalDate、LocalTime、LocalDateTime

JDK8加入了LocalDate(日期/年月日)、LocalTime(时间/时分秒)、LocalDateTime(日期时间/年月日时分秒)

  1. LocalDate只包含日期,可以获取日期字段
  2. LocalTime只包含时间,可以获得时间字段
  3. LocalDateTime包含日期+时间,可以获取日期和时间字段

11.9.3.3 DateTimeFormatter格式化日期类

类似SimpleDateFormat

语法:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(时间对象);

11.9.3.4 示例

public class LocalDate_ {
    public static void main(String[] args) {
        //第三代日期
        //1. 使用 now() 返回表示当前日期时间的 对象
        LocalDateTime ldt = LocalDateTime.now(); //LocalDate.now();//LocalTime.now()
        System.out.println(ldt);
        //2. 使用 DateTimeFormatter 对象来进行格式化
        // 创建 DateTimeFormatter 对象
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = dateTimeFormatter.format(ldt);
        System.out.println("格式化的日期=" + format);
        System.out.println("年=" + ldt.getYear());
        System.out.println("月=" + ldt.getMonth());
        System.out.println("月=" + ldt.getMonthValue());
        System.out.println("日=" + ldt.getDayOfMonth());
        System.out.println("时=" + ldt.getHour());
        System.out.println("分=" + ldt.getMinute());
        System.out.println("秒=" + ldt.getSecond());
        LocalDate now = LocalDate.now(); //可以获取年月日
        LocalTime now2 = LocalTime.now();//获取到时分秒
        //提供 plus 和 minus 方法可以对当前时间进行加或者减
        //看看 890 天后,是什么时候 把 年月日-时分秒
        LocalDateTime localDateTime = ldt.plusDays(890);
        System.out.println("890 天后=" + dateTimeFormatter.format(localDateTime));
        //看看在 3456 分钟前是什么时候,把 年月日-时分秒输出
        LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
        System.out.println("3456 分钟前 日期=" + dateTimeFormatter.format(localDateTime2));
    }
}

11.9.3.5 Instant 时间戳

类似于Date

提供了一系列和Date类转换的方法

  1. Instant -> Date :

    1. Date date = Date.from(instant);
      
  2. Date ->Instant :

    1. Instant instant = date.toInstant();
      

示例:

public class Instant_ {
    public static void main(String[] args) {
        //1.通过 静态方法 now() 获取表示当前时间戳的对象
        Instant now = Instant.now();
        System.out.println(now);
        //2. 通过 from 可以把 Instant 转成 Date
        Date date = Date.from(now);
        //3. 通过 date 的 toInstant() 可以把 date 转成 Instant 对象
        Instant instant = date.toInstant();
    }
}

11.10 练习

  1. /**
     * 将字符串中指定部分进行反转,比如将"abcdef"反转为"aedcbf"
     * 编写方法public static String reverse(String str, int start, int end)完成
     */
    public class Exercise9_01 {
        public static void main(String[] args) {
            String str = "abcdef";
            try {
                System.out.println(reverse(str, 1, 4));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        public static String reverse(String str, int start, int end) {
            if (str == null || str.length() == 0 || start >=end || start < 0 || end >= str.length()) {
                throw new RuntimeException("参数不正确");
            }
            StringBuffer sb = new StringBuffer(str);
            char temp = ' ';
            while(start < end) {
                temp = sb.charAt(start);
                sb.setCharAt(start, sb.charAt(end));
                sb.setCharAt(end, temp);
                start++;
                end--;
            }
            return sb.toString();
        }
    }
    
  2. /**
     * 输入用户名、密码、邮箱,如果信息录入成功,则提示注册成功,否则生成异常对象
     * 要求:
     * 1.用户名长度为2、3或4
     * 密码长度为6,要求全是数字
     * 邮箱中包含@和.并且@在.前面
     */
    public class Exercise9_02 {
        public static void main(String[] args) {
            String name = "tom";
            String pwd = "123456";
            String email = "tom@163.com";
            try {
                userRegister(name, pwd, email);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        public static void userRegister(String name, String pwd, String email) {
            if (name == null || pwd == null || email == null ||
                    name.length() == 0 || pwd.length() == 0 ||
                	email.length() == 0) {
                throw new RuntimeException("参数不能为空");
            }
            //判断用户名长度是否为2、3或4
            int nameLen = name.length();
            if (!(nameLen >= 2 && nameLen <= 4)) {
                throw new RuntimeException("用户名长度为2、3或4");
            }
            //判断密码长度是否为6,是否全是数字
            if (!(pwd.length() == 6 && isDigital(pwd))) {
                throw new RuntimeException("密码长度为6,要求全是数字");
            }
            //判断是否邮箱中包含@和.并且@在.前面
            int atPos = email.indexOf('@');
            int pointPos = email.indexOf('.');
            if (!(atPos > 0 && pointPos > atPos)) {
                throw new RuntimeException("邮箱中包含@和.并且@在.前面");
            }
            //前边通过则注册成功
            System.out.println("注册成功!");
            System.out.println("欢迎您," + name);
        }
    
        //判断字符串是否为数字
        public static boolean isDigital(String str) {
            char[] chars = str.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                if (chars[i] < '0' || chars[i] > '9') {
                    return false;
                }
            }
            return true;
        }
    }
    
  3. /**
     * 编写Java程序,输入形式为,William Jefferson Clinton,
     * 以Clinton,William .J的形式打印出来
     * 其中.J是中间单词的首字母大写
     */
    public class Exercise9_03 {
        public static void main(String[] args) {
            String name = "William Jefferson Clinton";
            try {
                System.out.println(reverse(name));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        public static String reverse(String name) {
            if (name == null || name.length() == 0) {
                throw new RuntimeException("姓名不能为空");
            }
            String[] names = name.split(" ");
            if (names.length != 3) {
                throw new RuntimeException("输入格式不正确");
            }
            return String.format("%s,%s .%s",names[2],names[0],names[1].toUpperCase().charAt(0));
        }
    }
    
  4. /**
     * 输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字
     */
    public class Exercise9_04 {
        public static void main(String[] args) {
            String str = "Ab86dDc3";
            try {
                count(str);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        public static void count(String str) {
            if (str == null || str.length() == 0) {
                throw new RuntimeException("字符串不能为空");
            }
            int upperCaseCount = 0;
            int lowerCaseCount = 0;
            int digitCount = 0;
            char[] chars = str.toCharArray();
            for (char aChar : chars) {
                if (Character.isUpperCase(aChar)) {
                    upperCaseCount++;
                } else if (Character.isLowerCase(aChar)) {
                    lowerCaseCount++;
                } else if (Character.isDigit(aChar)) {
                    digitCount++;
                }
            }
            System.out.println("字符串:"+str+"有"+
                    upperCaseCount+"个大写字母,"+
                    lowerCaseCount+ "个小写字母,"+
                    digitCount+"个数字");
        }
    }
    
  5. 在这里插入图片描述

举报

相关推荐

0 条评论