常用类 13章

35 篇文章 0 订阅

第十三章

常用类

13.1 包装类
13.1.1、包装类(wrapper)的分类:

①针对八种基本数据类型相应的引用类型
②有了类的特点,就可以调用类中的方法
在这里插入图片描述
查看每一个的类的父类,从中就可以知道哪些类可以被调用:
在这里插入图片描述

在这里插入图片描述

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

1、在jdk5之前用的是手动的装箱和拆箱的方式,装箱就是:基本类型 -> 包装类型,反之就是拆箱

2、在jadk5(包含jdk5)以后,就是用自动的装箱和拆箱方式了但是底层源码还是调用手动的 valueOf() 方法

我们通过 int 和 Integer 的转换为案例来演示:

public class WrapperType {
    public static void main(String[] args) {
        int n1 = 50;
        //jdk5前 手动装箱:
        Integer integer1 = new Integer(n1);//相当于就是创建一个Integer类对象,然后传入int型的变量参数
        Integer integer2 = Integer.valueOf(n1);//使用valueOf()方法去装箱
        //jdk5前 手动拆箱:
        int n2 = integer2.intValue();//使用intValue()方法去拆箱,如果拆箱别的,就是 类对象名.数据类型Value
        //jdk5后 自动装箱
        Integer integer3 = n1;//其实底层调用的还是手动装箱的valueOf()方法
        //jdk5后 自动拆箱
        int n3 = integer3;//其实底层调用的还是手动的 intValue()方法,
    }
}

对于其他的类型,都可以去自己类比尝试去转换试试,注意,byte是字节哦,也就是说是一个字节数组对象哈

测试:
A01:判断下列代码是否正确
Double d = 100d;
Float f = 1.5;

       //课堂测试A01:在main中
        Double d = 100d;//true,因为这里自动的调用了手动装箱中的Double.valueOf(100d)方法,换句话就是100d已经是一个对象了
        Float f = 1.5f;//false,因为1.5是一个基本数据类型,并没有被转换成类对象,所以会报错,如果是 1.5f 则就是对的

A02:判断下列代码输出是否一致:

//课堂测试A02:在main中
        Object obj1 = true ? new Integer(1) : new Double(2.0);
        //这里是一个三元运算符,因为Integer和Double都是Object的子类,
        // 但是呢,Integer在三元运算符中的前一位判断中,那么最后对象是建立的Integer对象,注意提高优先级
        System.out.println(obj1);//输出Integer对象:1.0,不是 1,原因在下面注意地方
        
        Object obj2;//定义一个Object类
        if (true){//如果正确,那么创建Integer对象
            obj2 = new Integer(1);
        }else {//如果错误,那么创建Double对象
            obj2 = new Double(2.0);
        }
        System.out.println(obj2);//Integer对象:1,不会提高优先级

注意:在做三元运算符的时候,要把整个三元运算符看作一个整体, 如果两个的精度不一致,会提高精度,无论输出是谁,但是精度必须是两者中最高的,
精度:double > float > long > int >char

13.1.3 包装类和String数据的转换

以 Integer 和 String 作为案例:

public class WrapperString {
    public static void main(String[] args) {
        //1、包装类(Integer -> String)
        Integer i = 10;
        //方法一:
        String str1 = i +" ";
        //这里至少基于i的数字去加上一个空格去组成“1“,然后去赋值给一个str1对象,对于i的数据类型是没有改变的
        //方法二:
        String s = i.toString();//因为包装类基本上都有toString方法,所以可以直接调用
        //方法三:
        String s1 = String.valueOf(i);//使用valueOf方法

        //2、String -> 包装类(Integer)
        String str2 = "123";//注意是必须能够转换的
        //方法一:
        Integer integer1 = Integer.parseInt(str2);//使用了自动装箱
        //方法二:
        Integer integer2 = Integer.valueOf(str2);//使用valueOf方法
        //方法三:
        Integer integer = new Integer(str2);//直接new一个Integer对象,通过构造器去转换
    }
}
13.1.4 Integer和Character类的常用方法

1、Integer:
在这里插入图片描述
2、String:
在这里插入图片描述
可以通过以下方法去查看不同类的方法,这些方法都是可以直接 lei类型 . 方法名用的,要用啥就去查就行

步骤一:
在这里插入图片描述

步骤二:
在这里插入图片描述
在这里插入图片描述

方法图:
在这里插入图片描述

13.1.5 Integer 经典面试题

阅读以下代码,看看输出什么

public class IntegerExercise01 {
    public static void main(String[] args) {
        method();
    }
    public static void method(){
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j);//false,两个对象,肯定不同,所有false

        Integer m = 1;//装箱,使用了 Integer.valueOf(1)
        Integer n = 1;//装箱,使用了 Integer.valueOf(1)  1在-128~127之间,所以没问题
        System.out.println(m == n);//ture,所以相同的,不能直接自己去判断,要进入底层源码去查看是否一致

        /*查看Integer.valueOf( )方法的底层源码:
           //这是源码方法上面提示中的代码,显示了i的取值范围
            This method will always cache values in the range -128 to 127,
        public static Integer valueOf(int i) {//功能方法
            if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)
            //判断 i 的值是否在 最小值(low:-128)、最大值(high:127)之间,如果在那么就是传入数组返回
                return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
            return new Integer(i);
             //如果不在最小值(low:-128)、最大值(high:127)之间,那么就是返回一个Integer对象
        }*/

        Integer x = 128;//128 不在最小值(low:-128)、最大值(high:127)之间,所以是返回的对象
        Integer y = 128;//128 不在最小值(low:-128)、最大值(high:127)之间,所以是返回的对象
        System.out.println(x == y);//false,因为是两个对象,所以不相等,

        Integer i1 = 127;
        int i2 = 127;//基本数据类型
        // 注意:只要有基本数据类型,不管其他的是什么类型,都是判断值是否相等
        System.out.println(i1 == i2);
    }
输出:
false
true
false
true

13.2 String类 !!!
13.2.1String类的理解和创建对象

1、String对象用于保存字符串,也就是一组字符序列
实现接口: 继承Object类
在这里插入图片描述

2、字符串常量对象是用双引号括起的字符序列,例如 ”123“,”小王“
在这里插入图片描述

3、字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)都是占两个字节

4、String类常用的构造器:
在这里插入图片描述
所有构造器可以在diagram图里点击这个可查看:
在这里插入图片描述
在这里插入图片描述
5、String类实现了Serializble接口,说明String可以串行化,也就是可以在网络中传输
在这里插入图片描述
6、String类实现了Comparable接口,说明String对象可以比较大小
在这里插入图片描述
7、String 是 final 类,是不能被其他类继承的
在这里插入图片描述
8、String 有属性:private final char value[ ];用于存放字符串内容,相当于一个字符串数组,注意:因为 value 是 final 类型的,所以不能修改(是不能修改value的地址,可以修改地址里面的值
在这里插入图片描述
在这里插入图片描述

13.2.2 String对象的创建方法

方式一:直接赋值
String s = ” hsp “;

分析:
先在常量池中去查看是否有 ”hsp“ 的数据空间,如果有 s 直接指向常量池中数据的地址,如果没有,就在常量池中去创建一个数据空间,然后再指向,总之就是:直接赋值的 s 最终指向是指向常量池的

方式二:调用构造器
String s2 = new String( ” hsp “ )

分析:
先在堆中创建空间,空间里面有维护 final修饰的 value属性,value属性指向常量池中的数据空间,如果没有数据空间,那么就创建一个,如果有,就通过value去指向常量池中的数据空间地址,然后 S2 对象再去指向value属性的堆地址,

两种方法的内存分布图:
在这里插入图片描述

13.2.3 String练习题

A01:分析下列代码的输出:
在这里插入图片描述

public class String02 {
    public static void main(String[] args) {
        String a ="123";
        String b ="123";
        System.out.println(a.equals(b));//TRUE,equals是判断d,b数组里面的字符串是否相等
        System.out.println(a == b);//TRUE,
        /*过程:
        1、因为直接赋值,所以 a 对象先去找常量池中有没有”123“,
        2、显然一开始a没有找到”123“,那就再常量池中去创建了一个”123“的数据空间,设地址:0x11
        3、常量池中有了”123“后,a就直接去指向”123“的地址(0x11)了,所以a的地址:0x11
        4、然后创建一个b字符串,b也去常量池中找是否有”123“数据空间
        5、显然找到了,因为之前a创建了,所以b就直接去指向”123“的数据空间,地址:0x11*/
    }
}
输出:
true
true

A02:
分析下列代码的输出:

public class StringExercise03 {
    public static void main(String[] args) {
        String a = "123";// a指向常量池的”123“
        String b = new String("123");// b指向堆中对象
        System.out.println(a.equals(b));//true,比较数值
        System.out.println(a == b);//false,比较对象,两者的对象地址所指向不同
        System.out.println(a == b.intern());//true,
        // intern()方法:返回字符串对象的规范表示,详细解释见下面解析:
        System.out.println(b == b.intern());//false,b是一个对象,b.intern是直接指向常量池
    }
}
输出:
true
false
true
false

解析:
intern()方法API的解释:当调用intern方法时,如果池已经包含与equals(Object)方法确定的相当于此String对象的字符串,则返回来自常量池的字符串。 否则,此String对象将添加到常量池中,并返回对此String对象的引用。
通俗理解:只要String对象调用了 intern ( ) 方法,那么这个对象就是指向常量池的

A03:
分析下列代码的输出:

public class StringExercise04 {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "123";
        Person person2 = new Person();
        person2.name = "123";
        System.out.println(person1.name.equals(person2.name));
        System.out.println(person1.name == person2.name);
        System.out.println(person1.name == "123");
    }
}
class Person{
    public static String name;
}
输出:
true
true
true

简易内存分布图:
在这里插入图片描述

13.2.4 字符串特性

1、 String是一个final类,代表不可变的字符序列
2、字符串是不可变的,一个字符串对象一旦被分配,其内容是不可以变的,要是修改字符串的值,那就重新建一个对象去指向就行

案例1:
分析下面代码,创建了多少个对象(由内存布局图可以看出来,一共创建了两个对象)
在这里插入图片描述

案例2:
分析下面代码,创建了多少个对象
在这里插入图片描述
案例3:
在这里插入图片描述
小结:c = a + b,底层是,先创建个StringBuilder sb = new StringBuilder()对象,然后 sb对象去调用sb.append(a)方法,再去调用sb.append(b)方法,append( )方法是在原来的字符串基础上去追加,sb是在堆中
重要规则:String c = “a” + “b”;该对象是常量相加,是指向常量池,而, String c = a + b;是对象相加,指向堆

案例4:
分下下列代码输出:

public class StringExercise06 {
    public static void main(String[] args) {
        String s1 = "hello";//s1指向池中 "hello"
        String s2 = "abc";//s2指向池中 "abc"
        String s3 = "helloabc";//s3指向池中"hellosbc"
        String s4 = (s1 + s2).intern();//s4指向 是池中"hellozbc"
        System.out.println(s3 == s4);//true  因为都指向池中
        System.out.println(s3.equals(s4));//true  因为字符串内容相等
    }
}
输出:
true
true

A04:
分析下列代码的输出

public class Test1 {
    String str = new String("hello");
    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){
        Test1 ex = new Test1();
        ex.change(ex.str, ex.ch);
        System.out.print(ex.str +  " and ");
        System.out.println(ex.ch);
    }
}
输出:
hello and hava

内存分布图:
在这里插入图片描述
整体分析:
①:main方法中创建一个ex对象,所以进行类加载,ex中的属性就有str (属于String,所以 str 中还有 final 修饰的 value 属性)和 ch [ ] 数组,内容为 java

②:ex调用change方法,那就开辟一个新栈,方法中由两个参数 str (参数中的str和对象的str一样,指向对象堆中的 value属性,但是呢,方法中又去将str 赋值为 java ,因为value是final 修饰的,所以方法中的str就不再指向堆中的value 了,就在指向常量池中创建的java )和 ch(参数中的ch 和对象属性ch 一样,都指向 一个数组引用,方法中去修改ch[0]d 值,那自然对象堆中的ch[0]就被修改了)

③ 方法change结束后,change栈就消了,然后继续下面的代码,因为堆中的str没有被修改 ,而堆中的ch数组内容被修改了,所以输出就是: hello and hava

13.2.5 String常见方法.

在这里插入图片描述
案例:

public class StringMethod {
    public static void main(String[] args) {
        String s1 = "jiangzai";
        String s2 = " * xiaowang   ";
        //1、equals 区分大小写,判断内容是否相等
        System.out.println(s1.equals("JiangZai"));//false
        //2、equalsIgnoreCase  不区分大小写,判断内容是否相等
        System.out.println(s1.equalsIgnoreCase("JiangZai"));//true
        //3、length 获取字符的个数,字符串的长度
        System.out.println(s1.length());//8
        //4、indexOf 获取字符或者局部字符串在整个字符串中,索引从0开始,第一次出现的索引,没有就返回-1
        System.out.println(s1.indexOf("ex"));//获取字符串ex首次出现在s1中的索引,没有,所以-1
        System.out.println(s1.indexOf('a'));//获取字a首次出现在s1中的索引,2
        //5、lastIndexOf 获取字符或者局部字符串在整个字符串中,索引从0开始,最后一次出现的索引,没有就返回-1
        System.out.println(s1.lastIndexOf('a'));//获取字a最后一次出现在s1中的索引,6
        //6、substring(i,j) 获取指定索引(i,j)之间的字符串,索引从0开始,也就是获取i-(j-1)之间,注意是之间,所以不包括j
        System.out.println(s1.substring(1,4));//获取s1:jiangzai中,索引为1-(4-1)之间的字符串 ian
        //7、trim 去掉字符串最前面和最后面的空格
        System.out.println(s2.trim());//要是不使用 肯定输出: * xiaowang   ,但是trim所以输出:* xiaowang
        //8、charAt 获取某索引处的字符,注意不能用 Str[index]数组这种方式
        System.out.println(s1.charAt(1));//只能输出单个字符  i
    }
}
输出:
false
true
8
-1
2
6
ian
* xiaowang
i

在这里插入图片描述

public class StringMethod1 {
    public static void main(String[] args) {
        String s1 = "xiaowang";
        String s2 = "XIAOWANG";
        //1.toUpperCase 将字符串转换成大写
        System.out.println(s1.toUpperCase(Locale.ROOT));//XIAOWANG
        //2.toLowerCase 将字符串转换成小写
        System.out.println(s2.toLowerCase(Locale.ROOT));//xiaowang
        //3.concat 在字符串后面拼接字符串,可以多次拼接
        System.out.println(s1.concat(" sds").concat("tnt"));//xiaowang sdstnt
        //4.replace 替换字符串中的字符(前面是久字符,后面是新字符),这里是区分大小写的
        //注意:在这里,s1.replace 是返回替换后的对象,
        // 相当于有一个对象去接收了s1.replace的结果,但是对于s1本身是没有影响的
        System.out.println(s1.replace('a','A'));//xiAowAng
        System.out.println(s1);//s1.replace对于s1没有任何影响 输出:xiaowang
        //7.toCharArray 转换成字符数组
        char [] cha = s1.toCharArray();//既然要转换成字符数组,那就要用一个字符数组来接收
        System.out.println("=====转化成字符数组后=======");
        for (int i = 0; i < cha.length ; i++) {
            System.out.print(cha[i]+"\t");//不换行输出,用制表位去分割
        }
        //8.format 格式化字符串,
    }
}
输出:
XIAOWANG
xiaowang
xiaowang sdstnt
xiAowAng
xiaowang
=====转化成字符数组后=======
x	i	a	o	w	a	n	g	

split的解析:

public class StringMethodSplit2 {
    public static void main(String[] args) {

        //5.split 分割字符串,用普通字符分割时
        String poem = "鹅鹅鹅,曲项向天歌,白毛浮绿水,红草拨清波";
        System.out.println("=========分割前的古诗========");
        System.out.println(poem);
        String [] split = poem.split(",");//()中间的是字符串中有的字符
        //因为一开始是一长串字符串,然后分割后就变成了很多串,所以要用数组去接收被分割的串
        //因为是字符串数组,所以要用for循环去输出
        System.out.println("=========分割后的古诗========");
        for (int i = 0; i < split.length ; i++) {
            System.out.println(split[i]);
        }
        //5.split 分割字符串,有特殊字符时,用转义符 \\ 修饰
        String s2 = "C:\\aa\\bb\\cc";
        System.out.println("=========分割前的文件路径========");
        System.out.println(s2);
        //String [] split2 =s2.split("\\");//在字符串中以 \\ 去分割时,,会抛出错误
        String [] split2 = s2.split("\\\\");//需要使用转移符 \\ 去修饰特殊字符
        System.out.println("=========分割后的文件路径========");
        for (int i = 0; i <split2.length ; i++) {
            System.out.println(split2[i]);
        }
    }
}
输出:
=========分割前的古诗========
鹅鹅鹅,曲项向天歌,白毛浮绿水,红草拨清波
=========分割后的古诗========
鹅鹅鹅
曲项向天歌
白毛浮绿水
红草拨清波
=========分割前的文件路径========
C:\aa\bb\cc
=========分割后的文件路径========
C:
aa
bb
cc

compareTo分析:

public class StringMethod3CompareTo {
    public static void main(String[] args) {
        String s1 = "xiaowang";
        String s2 = "XIAOWANG";
        //6.compareTo 比较来给你个字符串的大小,因为String有继承compare接口,所以可以比较
        System.out.println(s1.compareTo(s2));// 返回:(a-A) = 32
        //查看compareTo的底层:
//        public int compareTo(String anotherString) {
//            int len1 = value.length; //len1去接收第一个字符串的长度(s1长度:8)
//            int len2 = anotherString.value.length; //len1去接收第一个字符串的长度(s1长度:8)
//            int lim = Math.min(len1, len2); //取两个字符串中最小的长度(lim = 8)
//            char v1[] = value; //用v1字符数组取接收第一个字符串s1
//            char v2[] = anotherString.value; //用v1字符数组取接收第二个字符串s2
//
//            int k = 0;
//            while (k < lim) {//判断k和最小长度的大小,要是k的值小于最小长度,那么就执行下面代码,否则直接执行最后一句
//                char c1 = v1[k];//取第一个字符数组的第一个字符
//                char c2 = v2[k];//取第二个字符数组的第一个字符
//                if (c1 != c2) {//判断所取的字符相等不,不相等直接跳到k++去自加
//                    return c1 - c2;//不相等就用第一个的ASCII码减去第二个的ASCII码,然后返回其值
//                }
//                k++;//接着将k自加,
//            }
//            return len1 - len2;//如果 k >= lim 后,那就直接返回第一个字符串的长度减去第二个字符串的长度
//        }
        //说白了,compareTo的过程就是,
        // 1.先对比字符串中每一个对应的字符,相等就一直比较,直到不同或者比较晚都相同再处理
        // 2.比较到不同的时候,就返回:前面字符串的那个字符的ASCII码去减去后面字符串那个字符的ASCII码
        // 3.要是比较到某一个的最后一个字符,但是另外字符串还有字符的时候,
        //   就直接返回:前面字符串的长度减去后面字符串的长度
        // 4.要是两个字符串的值都相等,长度也相等,那么就返回0
    }
}
输出:
32

format分析:

public class StringMethodFormat {
    public static void main(String[] args) {
        String name = "江仔";
        int age = 22;
        char sex = '男';
        double score = 90/6;
        //输出学生的信息
        //方法1;  用字符串拼接  不是很方便更换信息
        System.out.println("我是"+name+"今年"+age+"岁,性别"+sex+",得分"+score);
        //方法2:   用format方法
        String info = String.format("我是%s今年%d岁,性别%c,得分%.2f",name,age,sex,score);
        System.out.println(info);
        //方法3:   用一个String字符串去接收format
        String formatStr = "我是%s今年%d岁,性别%c,得分%.2f";
        String info2 = String.format(formatStr,name,age,sex,score);
       System.out.println(info2);
       //注意:
        //1.%s %c %d %f 这些都是占位符 ,后面输入相应类型的变量就可以被替换
        //2.%s 用字符串String替换
        //3.%c 用字符char替换
        //4.%d 用整数int替换
        //5.%f 用小小数替换,可以去设定保留几位小数,%.2f保留两位,在.后面加上数字就代表保留几位
    }
}
输出:
我是江仔今年22岁,性别男,得分15.0
我是江仔今年22岁,性别男,得分15.00
我是江仔今年22岁,性别男,得分15.00
13.3 StringBuffer类
13.3.1 StringBuffer 理解

基本介绍:
① StringBuffer是java.lang包下面的,代表可变的字符序列,可以对字符串内容进行增删
② 很多方法和String相同,但StringBuffer是可变长度的
③ StringBuffer是一个容器

实例介绍:
1.StringBuffer 的直接父类是 AbstractStringBuilder
2.StringBuffer 实现了 Serializable 接口,所以StringBuffer对象是可以串行化的

在这里插入图片描述
3.在父类中 AbstractStringBuilder 有char[] value属性,并且不是final修饰的,该 value 数组存放的字符串内容(这里便是 hello 字符串),是存放在堆中的
在这里插入图片描述
4.StringBuffer 是一个final类,所以不能被继承
在这里插入图片描述
5.因为StringBuffer的内容存放在 char value[] 中,所以在内容有变化的时(增删) 不用每一次都更换地址(也就是不用每一次都创建对象),所以效率高于String

13.3.2 String VS StringBuffer

① String保存的是字符串常量,里面的值不能被修改,每次String类的更新,实际上就是更改地址,效率很低

② StringBuffer 保存的是字符串变量,里面的值可以被修改,每次StringBuffer的更新,实际上都是在更新内容,不用更改地址,效率比较高
在这里插入图片描述

13.3.3 StringBuffer 构造器
  1. StringBuffer()
    构造一个没有字符的字符串缓冲区,初始容量为16个字符。
    在这里插入图片描述

在这里插入图片描述

  1. StringBuffer(int capacity)
    构造一个没有字符的字符串缓冲区和指定的初始容量(capacity)。
    在这里插入图片描述
  2. StringBuffer(String str)
    构造一个初始化为指定字符串内容的字符串缓冲区。(数组长度为 内容长度 + 16)

在这里插入图片描述

13.3.4 String 和 StringBuffer 的转换

1.String —> StringBuffer

public class StringToStringBuffer {
    public static void main(String[] args) {
        //String ---> StringBuffer
        String str = "hello";
        //方法1: 使用构造器
        //注:返回的对象才是StringBuffer类,而对于str是没有任何影响的
        StringBuffer stringBuffer = new StringBuffer(str);
        
        //方法2:使用append方法
        //注:append方法是将其后面的参数的字符串,给附加到StringBuffer序列,可以是多种数据类型
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1 = stringBuffer1.append(str);
    }
}

  1. StrinBuffer ----> String
public class StringToStringBuffer {
    public static void main(String[] args) {
   
        //StrinBuffer ----> String
        StringBuffer stringBuffer2 = new StringBuffer("xiaowang");
        //方法1: 使用StringBuffer的toString方法
        String s = stringBuffer2.toString();
        //方法2: 使用构造器
        String s1 = new String(stringBuffer2);
    }
}

13.3.5 StringBuffer 常见方法

所有方法,可以通过查看API和查看StringBuffer的关系图去看

  1. 增:append()方法
    注:可以增加各种类型的字符,在API中可以具体查看
  2. 删:delete(start,end) 方法
    注:删除的是 start ~ end 中间的字符,索引从0开始,start包含,end不包含
  3. 改:replace(start,end,string)
    注:修改的是 start ~ end 中间的字符,所要替换的可以不是具体删除字符个数的字符串
  4. 查:indexOf()
    注:返回的是 所要查的字符第一次所出现的索引,没有返回-1
  5. 插:insert()
    注:是在 所要插入索引处,去插入要插入的字符,原来字符自动后移
  6. 获取长度:length()
    注:获取字符串的总长度
public class StringBufferMethod {
    public static void main(String[] args) {
        StringBuffer stringBuffer = new StringBuffer("hello");
        System.out.println("原字符串= "+stringBuffer);
        //1.append(),注:可以增加各种类型的字符,在API中可以具体查看
        stringBuffer.append(",");//"hello,"
        stringBuffer.append("小王");//"hello,小王"
        stringBuffer.append(100).append(true).append(52.21);//在这里是将其里面内容字符化了
        System.out.println("append方法后= "+stringBuffer);//输出:hello,小王100true52.21

        //2.delete() 注:删除的是 start ~ end 中间的字符,索引从0开始,start包含,end不包含
        stringBuffer.delete(6,8);
        System.out.println("delete方法后= "+stringBuffer);//输出:hello,100true52.21

        //3.replace()方法 注:修改的是 start ~ end 中间的字符,所要替换的可以不是具体删除字符个数的字符串
        stringBuffer.replace(5,9,"小王");
        System.out.println("replace方法后= "+stringBuffer);

        //4.查:indexOf()  注:返回的是 所要查的字符第一次所出现的索引,没有返回-1
        System.out.println("indexOf方法后= "+stringBuffer.indexOf("小王"));//5

        //5.插:insert()  注:是在 所要插入索引处,去插入要插入的字符,原来字符自动后移
        System.out.println("insert方法后= "+stringBuffer.insert(5,"江仔"));

        //6. length()  注:获取字符串的总长度
        System.out.println(stringBuffer.length());
    }
}
输出:
原字符串= hello
append方法后= hello,小王100true52.21
delete方法后= hello,100true52.21
replace方法后= hello小王true52.21
indexOf方法后= 5
insert方法后= hello江仔小王true52.21
18
13.3.6 StringBuffer 测试

A01:分析下列代码的输出,有错指明:

在这里插入图片描述

public class StringBufferExercise01 {
    public static void main(String[] args) {
        String str = null;//ok
        StringBuffer sb = new StringBuffer();
        sb.append(str);//查看底层源码,调用了父类AbstractStringBuilder的appendNull()方法
        /* appendNull()方法:
        private AbstractStringBuilder appendNull() {
        int c = count;
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;   字符数组长度就为 null的长度  4
        return this;
    }*///其本质就是将 null给字符化了,形成了字符数组,内容为‘n’,‘u’,‘l’,‘l’
        System.out.println(sb.length());//输出4

        System.out.println(sb);//null
        StringBuffer sb1 = new StringBuffer(str);//str是一个空对象,查构造器底层源码:
        /*StringBuffer(str)构造器
        public StringBuffer(String str) {
        super(str.length() + 16);//这里str是null,所以回报出空指针异常 NullPointException
        append(str);
    }
        * */
        System.out.println(sb1);//异常发生没有处理,所以不执行
    }
}
输出:
4
null
Exception in thread "main" java.lang.NullPointerException
	at java.lang.StringBuffer.<init>(StringBuffer.java:139)
	at com.xiaowang.StringBuffer_.StringBufferExercise01.main(StringBufferExercise01.java:27)

Process finished with exit code 1

A02:
输入商品名称和商品价格,要求打印效果示例
商品名 商品价格
手机 123,456,78
要求:价格的小数点前面每三位用逗号隔开

public class StringBufferExercise02 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入商品名称:");
        String name = scanner.next();
        System.out.println("请输入商品价格:");
        String price = scanner.next();

        StringBuffer sbPrice = new StringBuffer(price);
        //String转换成StringBuffer,方便调用StringBuffer的方法
        for (int i =sbPrice.indexOf(".")-3 ; i >0 ; i-=3) {
            //从小数点的索引开始去判断,先减了3后再去判断
            sbPrice = sbPrice.insert(i , ",");//添加,
        }
        System.out.println("商品名称"+"\t"+"商品价格");//输出值
        System.out.println(name+"\t\t"+sbPrice);
    }
}
13.4 StringBuilder类
13.4.1 StringBuilder理解

基本介绍:

1、是一个可变的字符序列,和 StringBuffer 的API是兼容的,但不保证同步(也就不是线程安全的,是单线程),该类被用作StringBuffer的替换,用在字符串缓冲区被单个线程使用的时候i(会更快)。

2、StringBuilder 的主要操作是:append(增)和 insert(插),方法是可以重载的,可以接收任意类型的数据

继承关系图:
说明是可以去简易替换StringBuffer的,而且主要用于单线程
在这里插入图片描述
实例介绍:

1.StringBuilder 继承了 AbstractStringBuilder类
2.实现了 Serializable ,说明StringBuilder对象是可以串行化的(对象可以网络传输,也可以保存到文件)

在这里插入图片描述

3.StringBuilder是 final类 ,所以不能被继承
在这里插入图片描述

4.StringBuilder 对象字符序列仍然存放在父类AbstractStringBuilder的
char[] value 属性中,所以也是在堆中

在这里插入图片描述

5. StringBuilder 的方法,没有做互斥处理,即没有 synchronized 关键字,因此在单线程情况下去使用
在这里插入图片描述

13.5 String VS StringBuffer VS Stringbuilder
13.5.1 基本区别

在这里插入图片描述
在这里插入图片描述

13.5.2 效率测试

效率:
StringBuilder > StringBuffer >String

案例测试:

//通过让三个类去执行同一个拼接的方法,去统计其所用的时间去比较其效率
public class StringVSStringBufferVSStringbuilder {
    public static void main(String[] args) {
        //1.String类效率测试
        String str = " ";//定义一个空串
        long startTime = 0l;//存放开始时间
        long endTime = 0l;//存放结束时间
        startTime = System.currentTimeMillis();//获取当前时间去赋值给开始时间
        for (int i = 0; i < 20000; i++) {//拼接20000次
            str = str +  i;
        }
        endTime = System.currentTimeMillis();//获取完成后时间
        System.out.println("String所执行的时间"+(endTime - startTime));

        //2.StringBuffer类效率测试
        StringBuffer stringBuffer = new StringBuffer(" ");//定义一个StringBuffer对象
        startTime = System.currentTimeMillis();//获取当前时间去赋值给开始时间
        for (int i = 0; i < 20000; i++) {//拼接20000次
            stringBuffer.append((i));
        }
        endTime = System.currentTimeMillis();//获取完成后时间
        System.out.println("StringBuffer所执行的时间"+(endTime - startTime));

        //2.StringBuilder类效率测试
        StringBuilder stringBuilder = new StringBuilder(" ");//定义一个StringBuffer对象
        startTime = System.currentTimeMillis();//获取当前时间去赋值给开始时间
        for (int i = 0; i < 20000; i++) {//拼接20000次
            stringBuilder.append((i));
        }
        endTime = System.currentTimeMillis();//获取完成后时间
        System.out.println("StringBuilder所执行的时间"+(endTime - startTime));
    }
}
输出:
String所执行的时间1013
StringBuffer所执行的时间1
StringBuilder所执行的时间0

总结:
效率:StringBuilder > StringBuffer >String,每一次的运行时间是不一样的,但是呢,StringBuilder的安全系数不高

13.5.3 三者选择

在这里插入图片描述

13.6 Math类

1、基本介绍
Math类用于计算数学中的运算方法,因为方法都是static静态的,所以直接用Math.方法名可以使用

2、常用方法
1.abs 求绝对值
在这里插入图片描述

2.pow 求幂
在这里插入图片描述

3.ceil 向上取整
在这里插入图片描述

4.floor 向下取整
在这里插入图片描述

5.round 四舍五入
在这里插入图片描述

6.sqrt 开平方
在这里插入图片描述

7.random 获取随机数

在这里插入图片描述

8.max 求两个数的最大值
在这里插入图片描述

9.min 求两个数的最小值
在这里插入图片描述
案例理解:

public class MathMethod {
    public static void main(String[] args) {
        //1.abs 求绝对值
        int abs = Math.abs(-9);//括号里面可以是多种数据类型
        System.out.println(abs);//输出:9

        //2.pow  求幂
        double pow = Math.pow(12,2);//只能是double类型
        System.out.println(pow);//输出:144.0

        //3.ceil 向上取整
        double ceil = Math.ceil(12.3);//只能是double类型
        System.out.println(ceil);//输出:13.0

        //4.floor 向下取整
        double floor = Math.floor(12.3);//只能是double类型
        System.out.println(floor);//输出:12.0

        //5.round 四舍五入,有long(接近long) 和 float(接近int) 类型的round方法,
        long round = Math.round(13.254);//数据中可以是float和double数据类型
        System.out.println(round);//输出:13

        //6.sqrt 开平方
        double sqrt = Math.sqrt(12.5);//只能是double类型
        System.out.println(sqrt);//输出:3.5355339059327378

        //7.random 获取随机数
        double random = Math.random();//返回值为 double值为正号,大于等于 0.0 ,小于 1.0 。
        System.out.println(random);
        int random1 = (int) Math.random();//随机生成int随机数,用强制转换,转换了都是0
        System.out.println(random1);

        //8.max 求两个数的最大值
        System.out.println(Math.max(1.2,1.5));//可以是多种数据类型,输出:1.5

        //9.min 求两个数的最小值
        System.out.println(Math.min(1.2,1.5));//可以是多种数据类型,输出:1.2

        //获取a-b之间的随机数,例子:返回2--7之间的随机整数
        for (int i = 0; i <10 ; i++) {
            System.out.println((int)(2+Math.random()*(7-2+1)));
        }
    }
}

获取随机数加强:
随机生成a-b之间的随机整数,例如(2-7)之间是整数

public class MathMethod {
    public static void main(String[] args) {
        //获取a-b之间的随机数,例子:返回2--7之间的随机整数
        //分析:
        //1.  Math.random()是获取0-1之间的随机小数,0可取,1不可取, 0 <= Math.random() < 1
        //2.获取a-b之间是随机数,就: a + (Math.random()*(b-a+1))
        //   分析: 因为 0 <= Math.random() < 1  ,(b-a)< (b-a+1) < (b-a+1)
        //         所以:0*(b-a) <= Math.random()*(b-a+1) < 1*( b-a+1 )
        //         所以:0 <= Math.random()*(b-a+1) < (b-a+1)
        //         又因为:a+0 <= Math.random()*(b-a+1) < a+(b-a+1)
        //         所以:a <= Math.random()*(b-a+1) < b+1
        //3.要想获得整数,就需要用 int 去强制转换所获得的随机值,单纯 (int)Math.random()=0
        //4.所以要想获得a-b之间的随机整数就:(int)(a + (Math.random()*(b-a+1)))
        //5.用a=2,b=7,循环十次来测试是否正确
        for (int i = 0; i <10 ; i++) {
            System.out.print(((int)(2+Math.random()*(7-2+1)))+"\t");
            //用制表位去改输出格式,就不用换行输出了
        }
    }
}
输出:
2	2	4	7	3	7	7	2	7	6	
13.7 Arrays类

基本介绍:
包含一系列静态方法,用于管理或操作数组(比如排序或者搜索)

13.7.1常用方法:
13.7.1.1 toString()方法

从API可以看出来,toString方法可以输出多种数据类型的数组
在这里插入图片描述
案例演示:
比较for循环和toString方法

public class ArraysMethod {
    public static void main(String[] args) {
        Integer [] integer = {1,20,15,50};
        //1.遍历数组
        //老方法for循环
        System.out.println("======for循环======");
        for (int i = 0; i <integer.length ; i++) {
            System.out.print(integer[i]+"\t");//制表位分开
        }
        System.out.println();
        //toString方法
        System.out.println("======toString循环======");
        System.out.println(Arrays.toString(integer));
        //查看toString底层源码:
        /*
        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {//其实也是用了for循环
            b.append(String.valueOf(a[i]));//将其每一个字符用valueOf去字符化,然后用append去拼接
            if (i == iMax)
                return b.append(']').toString();
            b.append(", ");//中间用 , 隔开
        }*/
    }
}
输出:
======for循环======
1	20	15	50	
======toString循环======
[1, 20, 15, 50]
13.7.1.2 sort排序

① 是从小到大排序,从API可以看出sort方法可以有很多数据类型,每一种数据类型都有两种排序方式,一个是整个数组进行排序,另一个是指定某个索引范围内的数进行排序
int为例:
在这里插入图片描述案例分析:

public class ArraysMethodSort {
    public static void main(String[] args) {
        Integer [] arr={1,-1,0,5,3};
        //1.sort整体排序
        Arrays.sort(arr);//数组是引用型的,所以排序过后,会影响原始的integer数组顺序
        System.out.println("======sort排序后数组=====");
        System.out.println(Arrays.toString(arr));//用toString方法去输出

        //2.sort指定范围排序(注意:包含前面不包含后面)
        Integer [] arr1 = {-1,8,5,9,3,2,6};
        Arrays.sort(arr1,1,6);//索引为1 <= arr1[i] < 6之间的数组排序:
        //所以输出:-1,2,3,5,8,9,6
        System.out.println(Arrays.toString(arr1));
    }
}
输出:
======sort排序后数组=====
[-1, 0, 1, 3, 5]
[-1, 2, 3, 5, 8, 9, 6]

② 定制排序
在这里插入图片描述
案例分析:

public class ArraysMethodSort {
    public static void main(String[] args) {

        //3.定制排序:(自己通过debug去调试去深刻理解)
        //主要是判断public int compare(Object o1, Object o2)方法的返回值是 >0 还是 <0,
        //这就会影响最后的排序方法(从大到小,还行,从小到大)
        Integer [] arr2 = {1,9,5,6,2,4,7};
        Arrays.sort(arr2, new Comparator() {//new Comparator是一个接口,整个是一个匿名内部类
            @Override
            public int compare(Object o1, Object o2) {//当执行的时候,就会进入compare底层代码
                Integer i1 = (Integer) o1;//向下转型
                Integer i2 = (Integer) o2;
                return i1-i2;//这里可以通过(i1-i2),或者(i2-i1)的大小去判断排序的方式(从大到小还是从小到大)
            }
        });
    }
}
输出:
i1-i2的结果:[1, 2, 4, 5, 6, 7, 9]
i2-i1的结果:[9, 7, 6, 5, 4, 2, 1]

定制排序比较难以理解,我们通过自己去写一个定制排序来进一步理解:

import java.util.Arrays;
import java.util.Comparator;
public class ArraysExercise {
    public static void main(String[] args) {
        int [] arr = {1,5,6,0,8,4};
       // bubbleSort(arr);
        customSort(arr, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {//o1,o2也就是后面要传入的arr[j],arr[j+1]

                int i1 = (Integer)o1;//先拆箱将其int化
                int i2 = (Integer)o2;
                return i1-i2;//在这里可以是return i2-i1;
                //return i2-i1;
                // 在这里的值,就相当于是c.compare(arr[j],arr[j+1])方法 的大小判断了
            }
        });
        System.out.println(Arrays.toString(arr));

    }
    //化繁为简:
    //1.数组排序平常都是用冒泡排序(但是当要修改排序方式的时候,只能去修改方法中的代码去改变不方便)
    public static void bubbleSort(int [] arr){
        int temp = 0;//中间变量
        for (int i = 0; i < arr.length-1; i++) {//因为外层要少循环一次底层
            for (int j = 0; j < arr.length-1-i; j++) {//内层循环
                //从小到大排序(要是从大到小:(arr[j] < arr[j+1])即可)
                if (arr[j] > arr[j+1]){
                    temp = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
    //定制排序(通过Comparator接口就可以直接实现排序方法)
    public static void customSort(int [] arr, Comparator c){
        int temp1 = 0;//中间变量
        for (int i = 0; i < arr.length-1; i++) {//因为外层要少循环一次底层
            for (int j = 0; j < arr.length-1-i; j++) {//内层循环
                //主要确定排序方式的就是if中的语句,
                // 所以将其改成接口,通过匿名内部类去确定排序方式更加方便
                if (c.compare(arr[j],arr[j+1])>0){//如果c.compare(arr[j],arr[j+1])>0则从小到大,反之从大到小
                    temp1 = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp1;
                }
            }
        }
    }
}

总结:指定排序的方法主要体现了接口编程的思想,这样是很方便的。

13.7.1.3 binarySearch 二分法
13.7.1.4 copyOf 数组元素的复制
13.7.1.5 fill数组元素填充
13.7.1.6 equals 比较两个数组
13.7.1.7 asList 转换集合

以上方法统统用案例演示:

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

/**
 * @Author 小王
 * @DATE: 2022/4/9
 */
public class ArraysMethod01 {
    public static void main(String[] args) {
        Integer [] arr = {1,2,3,5,6};
        // 3.binarySearch二分法查找,必须是排好序的数组去使用,可以正序可以负序
        //   注: 要查找的数据前面的数据保证是有顺序的就行
        // 如果数组中存在该元素就输出索引,
        System.out.println(Arrays.binarySearch(arr,2));//输出:1
        //如果数组中不存在,就返回 -(low + 1); low是应该存在位置,通过底层去查看
        System.out.println(Arrays.binarySearch(arr,4));//-(3+1)==-4

        //4.copyOf 数组元素的复制
        //   Arrays.copyOf(arr,arr.length);
        //   arr是所要去拷贝的数组,arr.length是确定拷贝多少个数据
        //   如果所要拷贝的数据长度不够,那就用null去填充
        //   如果arr.length = 0,则返回空数组
        //   如果arr.length < 0,则抛出NegativeArraysSizeException异常
        // 注:copyOf方法,底层使用的方法是:arraycopy
        Integer [] arr1 = Arrays.copyOf(arr,0);
        System.out.println("拷贝后arr1="+Arrays.toString(arr1));

        //5.fill数组元素填充
        // 5.1 Arrays.fill(arr2,num);填充后的结果是将数组中所有的数据改成所填充的num
        // 5.2  Arrays.fill(arr2,fromIndex,toIndex,num);将fromIndex,toIndex之间的数给替换成num
        Integer [] arr2 = {1,2,3,4};
        System.out.println("填充前的arr2=" +Arrays.toString(arr2));
        Arrays.fill(arr2,0,2,20);//将索引0-2之间的数替换成20
        System.out.println("部分填充后的arr2="+Arrays.toString(arr2));
        Arrays.fill(arr2,20);//所有的都替换成num = 20
        System.out.println("填充后的arr2="+Arrays.toString(arr2));

        //6.equals 比较两个数组内容是否完全一样
        Integer [] arr3 = {1,2,3};
        Integer [] arr4 = {1,2,3};
        boolean equals = Arrays.equals(arr3,arr4);//用一个boolean变量去接收判断后的结果
        System.out.println(equals);//相同返回ture,不同返回false

        //7.asList 将一组值,转换成list(集合)
        // 7.1 asList方法会把(1,2,3,4,5)转换成一个集合
        // 7.2 asLIst的编译类型是:List(接口类)
        // 7.3 asList的运行类型是:java.util.Arrays$ArrayList
        //     是Arrays类里面的一个静态内部类:底层:
        //        private static class ArrayList<E> extends AbstractList<E>
        //        implements RandomAccess, java.io.Serializable

        List asList = Arrays.asList(1,2,3,4,5);
        System.out.println("asList="+asList);
        System.out.println("asList的运行类型="+asList.getClass());

    }
}
输出:
1
-4
拷贝后arr1=[]
填充前的arr2=[1, 2, 3, 4]
部分填充后的arr2=[20, 20, 3, 4]
填充后的arr2=[20, 20, 20, 20]
true
asList=[1, 2, 3, 4, 5]
asList的运行类型=class java.util.Arrays$ArrayList
13.7.1.7 Arrays练习题

题目:
定义Book类,包含name和price,按price两种方式排序,按书名长度排序,,Book类有4个对象
book[0]=new Book(“红楼梦新版”,100);
book[1]=new Book(“西游记”,80);
book[2]=new Book(“水浒传20年”,120);
book[3]=new Book(“三国演义”,50);

  • 提示:可以通过Comparator接口匿名内部类,也就是定制排序*/

分析:
1.为了方便切换从大到小还是从小到大,我们使用Comparator接口去实现。
2.我们先自己去写接口编程方法去实现价格的排序:

package com.xiaowang.arrays;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;

/**
 * @Author 小王
 * @DATE: 2022/4/9
 */
/*定义Book类,包含name和price,按price两种方式排序,,Book类有4个对象
* 提示:可以通过Comparator接口匿名内部类,也就是定制排序*/
public class ArraysExercise {
    public static void main(String[] args) {
        Book [] book = new Book[4];
        book[0]=new Book("红楼梦新版",100);
        book[1]=new Book("西游记",80);
        book[2]=new Book("水浒传20年",120);
        book[3]=new Book("三国演义",50);

        //因为是通过price去排序,book是Book类,price是double类,所以用double数组去存放book的价格
        double [] price = new double[4];
        for (int i = 0; i < book.length; i++) {
            price[i]=book[i].getPrice();
        }
        customSort(price, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {//o1,o2也就是后面要传入的arr[j],arr[j+1]
                double i1 = (Double) o1;//先拆箱将其int化
                double i2 = (Double) o2;
               // return ((int)i1)-((int)i2);//从小到大
                return ((int)i2)-((int)i1);//从大到小
                //因为是重写判断price对象相减的值,所以我们需要去强制转换数据类型
                // 在这里的值,就相当于是c.compare(arr[j],arr[j+1])方法 的大小判断了
            }
        });
        System.out.println(Arrays.toString(price));

    }
    //定制排序(通过Comparator接口就可以直接实现排序方法)
    public static void customSort(double [] arr, Comparator c){
        double temp1 = 0;//中间变量
        for (int i = 0; i < arr.length-1; i++) {//因为外层要少循环一次底层
            for (int j = 0; j < arr.length-1-i; j++) {//内层循环
                //主要确定排序方式的就是if中的语句,
                // 所以将其改成接口,通过匿名内部类去确定排序方式更加方便
                if (c.compare(arr[j],arr[j+1])>0){//如果c.compare(arr[j],arr[j+1])>0则从小到大,反之从大到小
                    temp1 = arr[j+1];
                    arr[j+1] = arr[j];
                    arr[j] = temp1;
                }
            }
        }
    }
}
class Book{
    private String name ;
    private double price;

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

    public double getPrice() {
        return price;
    }
}
输出:
[120.0, 100.0, 80.0, 50.0]

此时只有价格被排序输出,同理也可以使用此方法去通过书名长度去排序,但是。我们的要求根据价格或者书名长度去输出是整个书的信息,所以判断对象得要是Book对象,所以我们可以在刚刚的基础上去修改代码
在这里插入图片描述
如果每一次我们都自己去写定制排序的内部结构的话,也是很麻烦的,而且本来Java就有定制排序的方法,我们直接用就可以

package com.xiaowang.arrays;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

/**
 * @Author 小王
 * @DATE: 2022/4/9
 */
public class ArraysExercise01 {
    public static void main(String[] args) {
        Book1 [] book1 = new Book1[4];
        book1[0]=new Book1("红楼梦新版",100);
        book1[1]=new Book1("西游记",80);
        book1[2]=new Book1("水浒传2020年",120);
        book1[3]=new Book1("三国演义",50);

        //使用Arrays自己有的定制排序方法
        // 1. price排序
        Arrays.sort(book1, new Comparator<Book1>() {
            @Override
            public int compare(Book1 o1, Book1 o2) {//这里o1,o2传入的是book对象
                return ((int)o1.getPrice())-((int)o2.getPrice());//从小到大排序
            //    return ((int)o2.getPrice())-((int)o1.getPrice());//从大到小排序
            }
        });
        System.out.println("==price排序==");
        System.out.println(Arrays.toString(book1));

        //1.name长度排序
        Arrays.sort(book1, new Comparator<Book1>() {
            @Override
            public int compare(Book1 o1, Book1 o2) {
                return o1.getName().length()-o2.getName().length();//名字长度从短到长
              //  return o2.getName().length()-o1.getName().length();//名字长度从长到短
            }
        });
        System.out.println("==name排序==");
        System.out.println(Arrays.toString(book1));
    }
}
class Book1{
    private String name;
    private double price;

    public Book1(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 "Book1{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}'+'\n';
    }
}
输出:
==price排序==
[Book1{name='三国演义', price=50.0}
, Book1{name='西游记', price=80.0}
, Book1{name='红楼梦新版', price=100.0}
, Book1{name='水浒传2020年', price=120.0}
]
==name排序==
[Book1{name='西游记', price=80.0}
, Book1{name='三国演义', price=50.0}
, Book1{name='红楼梦新版', price=100.0}
, Book1{name='水浒传2020年', price=120.0}
]

总结:
Arrays的sort方法,真的很有用,特别是Comparator接口编程的sort方法,减少了很多时间。

13.8 System类
13.8.1 常见方法

1.exit 退出当前程序在这里插入图片描述
案例:

import java.util.Arrays;

/**
 * @Author 小王
 * @DATE: 2022/4/9
 */
public class System_ {
    public static void main(String[] args) {
        //1.exit 退出当前程序
        System.out.println("xiaowang");
        System.exit(0);//0 表示一个状态,是正常状态
        System.out.println("jiangzai");//因为前面退出了当前程序,所以下面的jiagnzai不会被执行
    }
}
输出:
xiaowang

2.arraycopy:复制数组元素
在这里插入图片描述
案例:

import java.util.Arrays;

/**
 * @Author 小王
 * @DATE: 2022/4/9
 */
public class System_ {
    public static void main(String[] args) {
        //2.arraycopy:复制数组元素,比较合适底层调用
        /*arraycopy方法底层源码:
        public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);*/
         /*五个参数解读:
           src – the source array.  源数组
           srcPos – starting position in the source array.  从源数组的哪个索引开始拷贝
           dest – the destination array.    目标数组,即要把源数组数据拷贝到哪个数组
           destPos – starting position in the destination data.   把源数组的数据拷贝到目标数组哪个索引
           length – the number of array elements to be copied.   需要拷贝的个数(不能超过源数组的个数)
           */
        int [] arr={1,2,3};
        int [] arr1 = new int[3];
        System.arraycopy(arr,1,arr1,1,2);//应该输出:[0,2,3]
        System.out.println("拷贝后的数组arr1="+Arrays.toString(arr1));
    }
}
输出:
拷贝后的数组arr1=[0, 2, 3]

3.currentTimeMillis()
在这里插入图片描述
案例:

package com.xiaowang.system_;

import java.util.Arrays;

/**
 * @Author 小王
 * @DATE: 2022/4/9
 */
public class System_ {
    public static void main(String[] args) {
        //3.currentTimeMillis() 返回当前时间,距离(1970-1-1)年的毫秒数
        System.out.println(System.currentTimeMillis());
    }
}

4.gc 虚拟机回收
在这里插入图片描述

解析:在这里插入图片描述

13.9 BigInteger和BigDecimal类

基本介绍:
1、BigInteger 适合保存较大的整型

在这里插入图片描述
常用方法案例:

package com.xiaowang.bigNum_;

import java.math.BigInteger;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class BigInteger_ {
    public static void main(String[] args) {
     //long l = 1234567899999999999999999999999;//超出了long的范围
        //平时定义一个大的数的时候,一般都是long类型,但是当我们的数大于long了后,就需要用BigInteger
        //1.BigInteger因为是一个类,所以在定义一个超级大的数的时候,用对象去表示
        //2.要注意,当去创建BigInteger对象的时候,里面的值要用字符串去表示,在底层会去自动转换成整型
        BigInteger bigInteger1 = new BigInteger("1234567899999999999999999999999");
        BigInteger bigInteger2 = new BigInteger("1000");
        //3.BigInteger可以做加减乘除,但是呢,因为这是一个类对象,所以是不可以直接用 + - * /这些去直接做运算的
        //4.所以BigInteger的运算就直接调用BigInteger类对象相应的方法去处理就好,可以查看体系图了解BigInteger的方法
        //5. add()加法
        System.out.println("加法:"+bigInteger1.add(bigInteger2));
        //6. subtract() 减法
        System.out.println("减法:"+bigInteger1.subtract(bigInteger2));
        //7. multiply() 乘法
        System.out.println("乘法:"+bigInteger1.multiply(bigInteger2));
        //8. divide() 除法
        System.out.println("除法:"+bigInteger1.divide(bigInteger2));
    }
}
输出:
加法:1234567900000000000000000000999
减法:1234567899999999999999999998999
乘法:1234567899999999999999999999999000
除法:1234567899999999999999999999

2、BigDecimal适合保存精度更高的浮点型(小数)

在这里插入图片描述

常用方法案例:

package com.xiaowang.bigNum_;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class BigDecimal_ {
    public static void main(String[] args) {
        double num = 1234567899999999999999.9999999;//很明显double数值的大小超过了double的最大数,所以会被截取一段输出
        System.out.println("double类型的num:"+num);//输出:1.2345679E21
        //平时定义一个大的小数的时候,一般都是double类型,但是当我们的数大于double了后,就需要用BigDecimal
        //1.BigDecimal因为是一个类,所以在定义一个超级大的数的时候,用对象去表示
        //2.要注意,当去创建BigDecimal对象的时候,里面的值要用字符串去表示,在底层会去自动转换成浮点型
        BigDecimal bigDecimal1 = new BigDecimal("1234567899999999999999.9999999");
        BigDecimal bigDecimal2 = new BigDecimal("100.0001");
        //3.BigDecimal可以做加减乘除,但是呢,因为这是一个类对象,所以是不可以直接用 + - * /这些去直接做运算的
        //4.所以BigDecimal的运算就直接调用BigDecimal类对象相应的方法去处理就好,可以查看体系图了解BigDecimal的方法
        //5. add()加法
        System.out.println("加法:"+bigDecimal1.add(bigDecimal2));
        //6. subtract() 减法
        System.out.println("减法:"+bigDecimal1.subtract(bigDecimal2));
        //7. multiply() 乘法
        System.out.println("乘法:"+bigDecimal1.multiply(bigDecimal2));
        //8. divide() 除法
       // System.out.println("除法:"+bigDecimal1.divide(bigDecimal2));//会有异常(除不尽,有无限小数)
        //注意:对于divide()除法的时候,有可能会抛出异常:
        // ArithmeticException: Non-terminating decimal expansion(除不尽异常)
        //为了使其能够正常运行,我们可以通过BigDecimal.ROUND_CEILING去完成
        //BigDecimal.ROUND_CEILING解读:
        //这个的意思是,保留分母的小数位数,也就是,分母有几位,得出来的结果就是保留几位小数
        System.out.println("除法:"+bigDecimal1.divide(bigDecimal2,BigDecimal.ROUND_CEILING));
        System.out.println("除法:"+bigDecimal1.divide(bigDecimal2));//会有异常(除不尽,有无限小数)
    }
}
输出:
double类型的num:1.2345679E21
加法:1234567900000000000100.0000999
减法:1234567899999999999899.9998999
乘法:123456913456789999999999.99998999999
除法:12345666654333345666.6543334
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
	at java.math.BigDecimal.divide(BigDecimal.java:1693)
	at com.xiaowang.bigNum_.BigDecimal_.main(BigDecimal_.java:35)

13.10 日期类
13.10.1 第一代 Date类

Date类是第一代时间类

构造器:
在这里插入图片描述

方法案例分析:

package com.xiaowang.date_;

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

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class Date01 {
    public static void main(String[] args) throws ParseException {
        //1.获取当前系统的时间,(
        //  1.1 使用Date()构造器)
        Date date1 = new Date();
        System.out.println("Date当前日期:"+date1);
        //  1.2 使用Date(long)构造器
        Date date2 = new Date(123456);//里面传的是long 毫秒数

        //2.这里的Date是在 java.util.Date包里面,不是 java.sql.Date(这个是链接数据库时候的)

        // 3.默认的输出日期格式,是国外的输出方式,因此通常都要转换格式
        //   3.1 创建SimpleDateFormat对象,可以指定相应的输出格式
        //   3.2 相应格式是有h标准规定的,字母不能乱写,可以去查API了解每个字母的含义
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss E");
        System.out.println("转换后日期:"+simpleDateFormat.format(date1));//format:将日期转换为指定格式的字符串

        //4.可以把格式化的String字符串,转换成对应的Date
        // 注:所需要转换的String字符串时间的格式,必须要和你定义的SimpleDateFormat类对象的格式一样,不然要报错
        String date = "2022年04月10日 14:50:11 星期日";//必须和上面SimpleDateFormat类对象的时间格式一样
        Date date3 = simpleDateFormat.parse(date);//这里会抛出一个转换异常,所以我们通常要去接收这个异常用throws
        System.out.println("转换后时间:"+date3);//这时的转换是国外的输出格式,所以可以再用一次format去指定格式
        System.out.println("格式转换后时间:"+simpleDateFormat.format(date3));//
    }
}
输出:
Date当前日期:Sun Apr 10 14:57:53 CST 2022
转换后日期:2022041014:57:53 星期日
转换后时间:Sun Apr 10 14:50:11 CST 2022
格式转换后时间:2022041014:50:11 星期日

注:
① 这里的Date是在 java.util.Date包里面,不是 java.sql.Date(这个是链接数据库时候的)

② 创建SimpleDateFormat对象,相应格式是有标准规定的,字母不能乱写,可以去查API了解每个字母的含义
在这里插入图片描述
③ 所需要转换的String字符串时间的格式,必须要和你定义的SimpleDateFormat类对象的格式一样,不然要报错

13.10.2 第二代 Calendar类

Calendar是第二类时间类

构造器:
在这里插入图片描述
字段:
Calendar的字段超级多,使用的时候最好去查API

案例分析:

package com.xiaowang.date_;

import java.util.Calendar;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class Calendar_ {//日历类
    public static void main(String[] args) {
        //1.Calendar是一个抽象类,并且是private私有的
        //2.可以通过 getInstance()方法来获取实例
        //3.Calendar提供了大量的方法和字段去使用,可以查看Calendar底层或者API
        //实例演示:

        //1.获取实例对象
        //Calendar calendar1 = new Calendar();//因为是抽象类,所以通过new一个对象就是错的
        Calendar calendar = Calendar.getInstance();//因为是抽象的,所以通过方法来获取实例
        System.out.println(calendar);//这里输出的是Calendar的所有字段

        //2.获取某个日历对象的某个日历字段
        //通过Calendar对象去调用get(Calendar.字段名)方法去获取
        //Calendar有很多字段,可以通过API去查每一个字段的意思
        System.out.println("Calendar年:"+calendar.get(Calendar.YEAR));
        //注意:获取月份的时候,要+1,因为month是从0开始编号的
        System.out.println("Calendar月:"+(calendar.get(Calendar.MONTH)+1));
        System.out.println("Calendar日:"+calendar.get(Calendar.DAY_OF_MONTH));
           //注意:获取小时的时候,有12小时的,也有24小时的
        System.out.println("Calendar时:"+calendar.get(Calendar.HOUR));//Calendar.HOUR 是 12小时
        System.out.println("Calendar时:"+calendar.get(Calendar.HOUR_OF_DAY));//Calendar.HOUR_OF_DAY 是 24小时
 
        //3.Calendar没有专门的格式转换方法,一般都是程序员自己去设定
        System.out.println(calendar.get(Calendar.YEAR)+"年"+(calendar.get(Calendar.MONTH)+1)+"月"+calendar.get(Calendar.DAY_OF_MONTH)+"日");
    }
}

注:
1.Calendar是一个抽象类,并且是private私有的,通常通过 getInstance()方法来获取实例
2.获取月份的时候,要+1,因为month是从0开始编号的
3.Calendar没有专门的格式转换方法,一般都是程序员自己去设定

4.Calendar.HOUR 是 12小时
5. Calendar.HOUR_OF_DAY 是 24小时

13.10.3 第三代日期类

为什么会出现第三代日期类?
第三类日期类是在jdk8后才出现的
在这里插入图片描述

13.10.3.1日期时间类

第三代是在 java.time.包里面
第三代的体系图很复杂,同时实现了很多接口,所以所包含的方法也很多

案例方法分析:

package com.xiaowang.date_;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class LocalDate_ {
    public static void main(String[] args) {
        //1.使用now()方法去获得当前日期及时间的对象
        LocalDateTime localDateTime = LocalDateTime.now();//获得当前日期及时间的对象
        System.out.println("格式化前的时间:"+localDateTime);
        LocalDate localDate = LocalDate.now();//获取当前日期对象,也就是只获得 年月日 同时没有获取时分秒的方法
        LocalTime localTime = LocalTime.now();//获取当前时间对象,也就是只获得 时分秒 同时没有获取年月日的方法

        //2.仅仅只要获取某一个字段,那么直接用get相关方法就行,在diagrams体系图中可以查看所有方法,也可以查看API
        System.out.println("年"+localDateTime.getYear());
        System.out.println("月"+localDateTime.getMonth());//获取的是英文月份
        System.out.println("月"+localDateTime.getMonthValue());//获取的是中文数字月份
        System.out.println("日"+localDateTime.getDayOfMonth());//获取这个月的某一天
        System.out.println("时"+localDateTime.getHour());//获取的是24小时的时间
        System.out.println("分"+localDateTime.getMinute());
        System.out.println("秒"+localDateTime.getSecond());
    }
}
输出:
格式化前的时间:2022-04-10T16:16:34.7462022
月APRIL
月410161634
13.10.3.2格式化时间类

DateTimeFormatter类是java.time.format包里面的一格式化时间的一个类,是用DateTimeFormatter类对象去调用其format方法去格式化,

DateTimeFormatter类对象的获取是:
在这里插入图片描述

格式化对象方法是
在这里插入图片描述
案例分析:

package com.xiaowang.date_;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class LocalDate_ {
    public static void main(String[] args) {
        //1.使用now()方法去获得当前日期及时间的对象
        LocalDateTime localDateTime = LocalDateTime.now();//获得当前日期及时间的对象
        System.out.println("格式化前的时间:"+localDateTime);
        //3.格式化时间
        //  使用DateTimeFormatter对象去格式化
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");//使用指定的模式创建格式化程序。
        String format = dateTimeFormatter.format(localDateTime);//返回后的字符串对象才是格式化过后的
        System.out.println("格式化后的时间:"+format);
    }
}
输出:
格式化前的时间:2022-04-10T16:26:03.098
格式化后的时间:20220410162603
13.10.3.3 instant 时间戳

instant是在java.time 包里面的
在这里插入图片描述
案例分析;

package com.xiaowang.date_;

import java.time.Instant;
import java.util.Date;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
public class Instant_ {
    public static void main(String[] args) {
        //1.通过静态方法 now()去获取instant对象实例
        Instant now = Instant.now();
        System.out.println(now);//返回当前时间点的时间戳
        //2.如果要将instant类对象转换成一个Date对象就是用from()方法即可
        Date date = Date.from(now);
        System.out.println(date);//返回当前时间的Date对象
        //3.如果将Date对象转换成一个instant对象就用toInstant()方法即可
        Instant instant = date.toInstant();
        System.out.println(instant);

    }
}
输出:
2022-04-10T08:35:05.827Z
Sun Apr 10 16:35:05 CST 2022
2022-04-10T08:35:05.827Z

注意:第三类日期类有很多很多的方法,使用的时候,可以通过API去查看每一个方法的使用。

13.11 练习题
13.11.1 A01:String翻转

题目:
将字符串指定部分进行反转,比如将“abcde”,反转成“aedcb”,
要求:写一个方法去完成
public static String reverse(String str,int startIndex,int endIndex)
分析:

package com.xiaowang.homWork_;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
/*将字符串指定部分进行反转,比如将“abcde”,反转成“aedcb”,
* 要求:写一个方法去完成
* public static String reverse(String str,int startIndex,int endIndex)*/
public class Homework01 {
    public static void main(String[] args) {
        String str ="abcde";
        System.out.println("交换前="+str);
        str =  reverse("abcde", 1, 4);
        //因为是要将iyge字符串给翻转,所以将翻转后的还是赋值给本字符串,就不用再去new一个String
        System.out.println("翻转后="+str);
    }

    public static String reverse(String  str, int startIndex, int endIndex) {
        //1.先将字符串转换成一个数组,因为String是不可以直接修改的,
        char [] arrstr = str.toCharArray();
        //2.用一个char字符去做中间变量
        char temp = ' ';
        //3.用for循环去翻转数组间的字符
        for (int i = startIndex,j = endIndex; i < j; i++,j--) {
            temp = arrstr[i];
            arrstr[i] = arrstr[j];
            arrstr[j] = temp;
        }
        //4.然后再将字符数组转换成String返回
        String str1 = String.valueOf(arrstr);
        return str1;
    }
}

以上方法虽然可以实现功能,但是不稳定,不坚固,当所传入的数组为null,或者startIndex和endIndex越界什么的就会直接报错,所以,为了避免这些错误,我们需要去考虑找方法使其代码更加稳固。

修改后的代码:

package com.xiaowang.homWork_;

/**
 * @Author 小王
 * @DATE: 2022/4/10
 */
/*将字符串指定部分进行反转,比如将“abcde”,反转成“aedcb”,
* 要求:写一个方法去完成
* public static String reverse(String str,int startIndex,int endIndex)*/
public class Homework01 {
    public static void main(String[] args) {
        String str ="abcde";
        System.out.println("交换前="+str);
        try {
            str = reverse("abcde", 1, 4);//因为这里可能会有异常,所以我们去处理一下
        } catch (NullPointerException e) {
            System.out.println(e.getMessage());//输出我们的异常信息
            return;//出错了就不往下面执行了
        } catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e.getMessage());
            return;
        }
        //因为是要将iyge字符串给翻转,所以将翻转后的还是赋值给本字符串,就不用再去new一个String
        System.out.println("翻转后="+str);
    }

    public static String reverse(String  str, int startIndex, int endIndex) {
        //为了使代码更稳固我们需要去处理一些异常,
        // 从正确的想法去取反就可以包括所有的错误想法
        
       /*整体作为一个异常
        if (!(str != null && startIndex<endIndex && endIndex<str.length())){
            throw new RuntimeException("参数不正确");
            //也可以将具体的异常类型写出来,然后相应的去输出
        }*/
        
        //空指针异常
        if (!(str!=null)){
            throw new NullPointerException("空指针异常");
        } //越界异常
        else if (!(startIndex<endIndex && endIndex<str.length())){
            throw new ArrayIndexOutOfBoundsException("越界异常");
        }
        //1.先将字符串转换成一个数组,因为String是不可以直接修改的,
        char [] arrstr = str.toCharArray();
        //2.用一个char字符去做中间变量
        char temp = ' ';
        //3.用for循环去翻转数组间的字符
        for (int i = startIndex,j = endIndex; i < j; i++,j--) {
            temp = arrstr[i];
            arrstr[i] = arrstr[j];
            arrstr[j] = temp;
        }
        //4.然后再将字符数组转换成String返回
        String str1 = String.valueOf(arrstr);
        return str1;
    }
}

13.11.2 A02:注册登录

题目:
用户输入用户名,密码,邮箱去注册一个账号,要是不满足以下要求,就返回相应的异常信息
要求,
1.用户名只能是2或3或4长度
2.密码只能是6位,并且全为数字
3.邮箱必须有@和. 并且@要在.的前面,并且都不能在首位
分析:

package com.xiaowang.homWork_;

import java.util.Scanner;

/**
 * @Author 小王
 * @DATE: 2022/4/11
 */
/*思路:
* 1.化繁为简,先写死的字符串去实现
* 2.先写一个方法去判断所要输入的信息是否正确
* 3.再写每一个判断所需要用到的方法(1.判断是否全为数字 2.@和.的存在和顺序),在第二步判断中直接去调用具体的判断方法
* 4.每写完一个判断方法就在main中去用字符串去测试一下
* 5.用字符串测试没问题后,再去用Scanner去接收再去测试
* 6.如果要求更多也可以在先有基础上继续加条件去校验
* */
public class HomeWork02 {
    public static void main(String[] args) {
        System.out.println("请输入你的用户名,密码和邮箱");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.next();
        String password = scanner.next();
        String email = scanner.next();
        try {
            message(name,password,email);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return;//有错输出就不再执行
        }
        System.out.println("注册成功");
    }
    //写一个方法来做判断
    public static void message(String name,String password,String email){
        if (!(name.length()>=2 && name.length()<=4)){//判断用户名长度
            throw new RuntimeException("用户名长度错误");
        }else if (!(password.length()==6 && checkStrIsNum(password))){
            throw new ArithmeticException("密码长度不正确或者不全为数字");
        }else if (!(checkStrIsEmail(email))){
            throw new NumberFormatException("邮箱格式不正确");
        }
    }
    //写个方法用来判断输入的字符串是否全是数字,利用isDigit方法去完成,
    //也可以将字符串转换成字符数组,然后去判断每一个索引处值的ASCII码是否在0-9之间
    public static boolean checkStrIsNum(String str){
        for (int i = 0; i < str.length(); i++) {
           // System.out.println(str.charAt(i));
            // str.charAt(i)方法是返回指定索引处的值
            if (!Character.isDigit(str.charAt(i))){//利用Character.isDigit的方法去判断是否是数字
                //如果不是返回false
                return false;
            }
        }
        return true;//如果使数字就返回true
    }
    //写个方法用来判断邮箱中是否包含@和.  并且@再.的前面
    public static boolean checkStrIsEmail(String str) {
        /*这是我最先想到的方法
        String str1 ="@";
        String str2 =".";
        //1.先判断是否有这两个符号
        boolean have = str.contains(str1) && str.contains(str2);
        if (have){//如果含有那两个字符则进行顺序的判断,并且肯定不能开头
            if (str.indexOf(str1)<str.indexOf(str2) && str.indexOf(str1)>0){
                return true;
            }
        }
        return false;*/
        //第二种方法
        //先获取字符串中两个符号的索引值
        int i= str.indexOf("@");//如果是字符串中没有这个字符,那么就返回-1
        int j= str.indexOf(".");
        if (i>0 && j>i){
            return true;
        }//如果是满足条件,那么返回true
        //如果没有这两个字符,那么i和j都是-1,上面if判断也是错的,所以还是会返回false
        return false;
    }
}

13.11.3 A03:人名调序输出

题目:
编写Java程序,输入形式为:"Wang hai Yang"的人名,然后以Yang,Wang.H输出
注意:中间用,隔开,最后是.H是中间单词的大写首字母
分析:

package com.xiaowang.homWork_;

import java.util.Locale;

/**
 * @Author 小王
 * @DATE: 2022/4/11
 */
/*
* 编写Java程序,输入形式为:"Wang hai Yang"的人名,然后以Yang,Wang.H输出
* 注意:中间用,隔开,最后是.H是中间单词的大写首字母*/
public class HomeWork03 {
    public static void main(String[] args) {
        String name = "Wang hai Yang";
        form(name);
    }
    /*
     * 编写一个方法去完成:
     * 1.分割字符串,split(),按照空格去分割
     * 2.对分割了的String[],进行格式化 String.format()
     * 3.因为最后输出的是中间数的大写首字母,所以先将其所有转成大写,然后去得到第一个索引的字母
     * 3.进行校验
     * */
    public static void form(String str){
        if (str == null) {
            System.out.println("数组不能为空");
        }
        String[] str1=str.split(" ");
        if (str1.length !=3){
            System.out.println("输入格式不正确");
            return;
        }else
            System.out.println(String.format("%s,%s.%c",str1[2],str1[0],str1[1].toUpperCase().charAt(0)));
        //str1[1].toUpperCase().charAt(0)解读
        //1.先将str[1]字符串全大写
        //2.再去获取索引为0的字符
    }
}
输出:
Yang,Wang.H
13.11.4 A04:统计个数

题目:
输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字
分析:

package com.xiaowang.homWork_;

/**
 * @Author 小王
 * @DATE: 2022/4/12
 */
/*
* 输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字*/
public class HomeWork04 {
    public static void main(String[] args) {
        String str = "asd1325zxASSA2121";
        count(str);
    }
    /*思路分析:
    * 1.编写一个方法去完成需求count(String str)
    * 2.通过ASCII码去判断
    * 3.可以直接用String方法的charAt()方法去判断
    *   也可以先将其字符化char[],通过char[]去判断也行
    * */
    public static void count(String str){
        //1.先判断是否为空
        if (str ==null){
            System.out.println("字符串输入有误");
            return;//为空就不执行了
        }
        int numA=0;//统计大写
        int numa=0;//统计小写
        int nums=0;//统计数字

        for (int i = 0; i <str.length() ; i++) {
            if (str.charAt(i)>='A' && str.charAt(i)<='Z'){
                numA++;
            }else if (str.charAt(i)>='a' && str.charAt(i)<='z'){
                numa++;
            } else if (str.charAt(i) >= '1' && str.charAt(i) <= '9') {
                nums++;
            }
        }
        System.out.println("大写字母:"+numA+"\t"+"小写字母:"+numa+"\t"+"数字:"+nums);
    }
}
输出:
大写字母:4	小写字母:5	数字:8

13.11.5 A05:String内部结构

分析下列代码的输出:

分析:

package com.xiaowang.homWork_;

/**
 * @Author 小王
 * @DATE: 2022/4/12
 */
public class HomeWork05 {
    public static void main(String[] args) {
        String s1="xiaowang";//池中s1为"xiaownag"
        Animal a = new Animal(s1);//堆中有一个name属性去指向池中的s1,但是a是直接指向堆中name属性的
        Animal b = new Animal(s1);//堆中有一个name属性去指向池中的s1,但是a是直接指向堆中name属性的

        System.out.println(a==b);//false,这是判断是否是同一个对象,a和b指向不同的name对象属性
        System.out.println(a.equals(b));//false,这里判断的还是a和b是否是同一个对象
        //一开始可能都会觉得,equals是判断内容是否相等,那是在a和b都是String类型的变量的时候才相等,而这里:
        // 因为:a和b都是Animal对象,所以调用的也是Animal对象的equals,
        // 又因为Animal对象的equals方法并没有被重写,所以相当于还是判断是否是同一个对象
        //底层源码:
        /*
        public boolean equals(Object obj) {
        return (this == obj);//可以看到,返回的是父类obj的equals方法,并没有被重写,,所以比较的是对象
    }*/
        System.out.println(a.name == b.name);//true,a.name 和 b.name 都是指向池中s1的"xiaownag"

        String s4 =new String("xiaowang");//堆中有一个value属性去指向池中的s1,但是s4 是直接指向堆中value属性的
        String s5 ="xiaowang";//s5直接指向池中s1的“xaiowang”
        System.out.println(s1 == s4);//false,s4指向堆中value,s1指向池中“xiaowang”,所以不等
        System.out.println(s4 == s5);//false,s4指向堆中value,s5指向池中s1,所以不等

        String t1 ="hello"+s1;
        //字符串和对象相加的时候,是在先创建一个StringBuilder,然后相加后,返回给堆中的一个value再传给对象
        String t2 ="helloxiaowang";
        System.out.println(t1.intern() == t2);//true
        //intern():返回字符串对象的规范表示
    }
}
class Animal{
    String name;
    public Animal(String name){
        this.name =name;
    }
}
输出:
false
false
true
false
false
true

常用类篇幅就在这结束了吖,这是整个Java学习中的第十三章哦,觉得还不错的可以查看我完整的Java笔记哦:
Java学习第二阶段(仍然在继续更新中~~~~)
Java学习第一阶段

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值