第十一章、 Java常用类
11.1 包装类
11.1.1 包装类的分类
- 针对八种基本数据类型相应的引用类型-包装类
 - 有了类的特点,就可以调用类中的方法。


 


11.1.2 包装类和基本数据的转换
- Jdk5前的手动装箱和拆箱方式,装箱:基本类型->包装类型(即把基本类型变成包装类型的过程称为装箱);拆箱反之。
 - Jdk5以后(含jdk5)的自动装箱和拆箱方式
 - 自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
 - 其他类型同理,面试题常考
 
package chapter11.wrapper;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Integer01 {
    public static void main(String[] args) {
        //jdk5前是手动装箱和拆箱
        //手动装箱 int->Integer
        int n1=100;
        Integer integer=new Integer(n1);
        Integer integer1=Integer.valueOf(n1);
        //手动拆箱 Integer->int
        int n2=integer.intValue();
        //jdk5后,就可以自动装箱和拆箱
        int n3=100;
        //自动装箱
        Integer integer2=n3;//底层使用的是Integer.valueOf(n2)
        //自动拆箱
        int n4=integer2;//底层仍然使用的是 intValue()方法
    }
}
 
11.1.3 包装类练习
- 下面代码是否正确,为什么?
 - 并判断两个输出语句输出是一样吗,如果不一样各是什么?为什么?
 
package chapter11.wrapper;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class WrapperType {
    public static void main(String[] args) {
        Double d=100d;//对,自动装箱,底层是Double.valueOf(100d);
        Float f=1.5f;//对,自动装箱,底层是Float.valueOf(1.5d);
        Object obj1=true?new Integer(1):new Double(2.0);
        System.out.println(obj1);//1.0,三元运算符是一个整体,会自动转型
        Object obj2;
        if(true){
            obj2=new Integer(1);
        }else{
            obj2=new Double(2.0);
        }
        System.out.println(obj2);//1
    }
}
 
11.1.4 包装类型和String类型的相互转换
- 通过代码来理解:包装类型和String类型之间的相互转换
 
package chapter11.wrapper;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class WrapperVSString {
    public static void main(String[] args) {
        //包装类型--->String类型
        Integer i=10;//自动装箱
        //方式1:
        String s1=i.toString();
        //方式2:
        String s2=String.valueOf(i);
        //方式3:这种方式不会改变i本身
        String s3=""+i;
        //String类型--->包装类类型
        String s="100";
        //方式1:
        Integer j1=new Integer(s1);//构造器
        //方式2:
        Integer j2=Integer.valueOf(s);
        //方式3:
        Integer j3=Integer.parseInt(s);//parseInt本身是返回int,但是这个可以进行自动装箱
    }
}
 
11.1.5 Integer类和Character类的常用方法
- Integer类和Character有些常用的方法(会常用方法即可。其他方法太多了,会查即可)。通过下面代码来理解。
 
package chapter11.wrapper;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class WrapperMethod {
    public static void main(String[] args) {
        System.out.println(Integer.MIN_VALUE);//通过访问属性,返回最小值
        System.out.println(Integer.MAX_VALUE);//返回最大值
        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'));//转成小写
    }
}
/*
-2147483648
2147483647
false
true
false
true
false
A
a
 */
 
11.1.6 Integer创建机制
- 查看下面代码,输出什么结果?为什么?
 
package chapter11.wrapper;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class WrapperExercise01 {
    public static void main(String[] args) {
        
    }
    public void method(){
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i==j);//false
        
        Integer m=1;
        Integer n=1;
        System.out.println(m==n);//true
        
        Integer x=128;
        Integer y=128;
        System.out.println(x==y);//false
    }
}
 
(1). 分析ij为什么是false,因为i和j分别是对象引用,对比的它的地址,所以是false。
 (2). 分析mn为什么是true,首先要知道底层代码是Integer.valueOf(1)。查看源码得知,当传入-128~127时,直接返回;否则就返回new Integer(x);
 (3). 分析xy为什么是false,由上面解释可得。
部分代码如下:(具体代码自行查看)
 
 2. 查看下面代码,输出什么结果?为什么?
package chapter11.wrapper;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class WrapperExercise02 {
    public static void main(String[] args) {
        //1.
        Integer i1=new Integer(127);
        Integer j1=new Integer(127);
        System.out.println(i1==j1);//f
        //2.
        Integer i2=new Integer(128);
        Integer j2=new Integer(128);
        System.out.println(i2==j2);//f
        //3.
        Integer i3=127;
        Integer j3=127;
        System.out.println(i3==j3);//t
        //4.
        Integer i4=128;
        Integer j4=128;
        System.out.println(i4==j4);//f
        //5.
        Integer i5=127;
        Integer j5=new Integer(127);
        System.out.println(i5==j5);//f
        //6.如果存在基本数据类型,那么判断的是值是否相等
        Integer i6=127;
        int j6=127;
        System.out.println(i6==j6);//t
        //7.
        Integer i7=128;
        int j7=128;
        System.out.println(i7==j7);//t
    }
}
 
分析:如果存在基本数据类型,那么判断的是值是否相等
11.2 String
11.2.1 String类的理解和创建对象
- String对象用于保存字符串,也就是一组字符序列String 01.java
 - 字符串常量对象是用双引号括起来的字符序列。例如:”你好”,”12.97”,”boy”等
 - 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
 - String类较常用构造方法(其他看手册)
(1). String s1=new String();
(2). String s2=new String(String original);
(3). String s3=new String(char[] a);
(4). String s4=new String(char[] a,int startIndex,int count);
(5). String 类实现了接口Serializable【String 可以串行化:可以在网络传输】、Comparable 【String 对象可以比较大小】
(6). String 是final类,即不能被其他类继承
(7). String有属性 private final byte[] value;用于存放字符串内容/,JDK8之前是char[]
(8). 一定要注意:value 是一个finally类型,不可以修改(重点):即内容可以修改,但是指向的地址不能修改(即value不能指向新地址) 

 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class String01 {
    public static void main(String[] args) {
        String name="jack";
        name="mark";
        //1.String 对象用于保存字符串,也就是一组字符序列
        //2."jack" 是字符串常量,双引号括起来的字符序列
        //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 s4=new String(char[] a,int startIndex,int count);
        //        (5). String s5=new String(byte[] b)
        //5.String 类实现了接口Serializable【String 可以串行化:可以在网络传输】
        //               接口Comparable 【String 对象可以比较大小】
        //6.String 是final类,即不能被其他类继承
        //7.String有属性 private final byte[] value;用于存放字符串内容/,JDK8之前是char[]
        //8.一定要注意:value 是一个finally类型,不可以修改(重点):
        //  即内容可以修改,但是指向的地址不能修改(即value不能指向新地址)
        final byte[] value={1,2,3,4};
        value[0]=3;//可以修改内容
        byte[] v2={1,2,3,4};
//        value=v2;//报错,不可以修改value地址
    }
}
 
11.2.2 String结构剖析
-  
创建String对象的两种方式
(1). 方式一:直接复制 String s=”hello”;
(2). 方式二:调用构造器String s2=new String(“hello”); -  
两种创建String对象的区别
(1). 方式一:先从常量池查看是否有”hello”的数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址。
(2). 方式二:先从堆中创建空间,里面维护了value属性,指向常量池的hello空间。如果常量池没有”hello”,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
(3). 画出两种方式的内存分布图

 
11.2.3 练习
- 思考下面代码输出什么?
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise01 {
    public static void main(String[] args) {
        String a="hello";
        String b="hello";
        System.out.println(a.equals(b));//true,对比的是值
        System.out.println(a==b);//false,对比的是地址
    }
}
 
- 思考下面代码输出什么?
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise02 {
    public static void main(String[] args) {
        String a=new String("hello");
        String b=new String("hello");
        System.out.println(a.equals(b));//true
        System.out.println(a==b);//false
    }
}
 
- 思考下面代码输出什么?
知识点:
当调用intern方法时,如果池中已经包含有一个等于这个String(用equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise03 {
    public static void main(String[] args) {
        String a="hello";   //指向 常量池中 hello的地址
        String b =new String("hello");  //指向的是堆中的对象,这个对象有个value指向常量池中 hello的地址
        String c = "hi";
        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
        System.out.println(c==b.intern());//false
        /*
        理解这个intern()的使用:
        由前面代码知道"hello",已经在常量池中存在了,那么执行b.intern(),
        如果常量池中存在和b对象的字符串一样的话,就将该返回池中的字符串,
        也就是b.intern指向的是常量池字符串"hello",否则,就将这个字符串"hello"
        添加到常量池中,返回这个b对象的引用,也就是b.intern指向的是堆中的对象
         */
    }
}
 
- 思考下面代码输出什么?
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise04 {
    public static void main(String[] args) {
        String s1= "hello";
        String s2= "hi";
        String s3= "hi";
        String s4= new String("hi");
        System.out.println(s2==s3);//true
        System.out.println(s2==s4);//false
        System.out.println(s2.equals(s4));//true
        System.out.println(s1==s2);//false
    }
}
 
- 思考下面代码输出什么?
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise05 {
    public static void main(String[] args) {
        Person p1=new Person();
        p1.name="hello";
        Person p2=new Person();
        p2.name="hello";
        System.out.println(p1.name.equals(p2.name));//true
        System.out.println(p1.name==p2.name);//true
        System.out.println(p1.name=="hello");//true
        String s1=new String("abc");
        String s2=new String("abc");
        System.out.println(s1==s2);//false
    }
}
class Person{
    public String name;
}
 
11.2.4 字符串的特性(面试题)
- 以下语句创建了几个对象?
 
String s1="hello";
s1="haha";
/*
2
理解:首先s1会去常量池寻找有没有hello这个字符串常量对象,如果没有就创建。
然后s1="haha",同理它会去常量池中寻找haha这个字符串常量对象,如果没有就创建。
并不会修改hello这个字符串常量对象
 */
 
总结:
 (1). String是final类,代表不可变的字符序列
 (2). 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
- 以下语句创建了几个对象?
 
String a="hello"+"hi";
/*
创建了1个对象
 String a="hello"+"hi";底层优化等价于 String a="hellohi";
 */
 
总结:
 (1). 编译器会做一个优化,判断创建的是不是属于字符串常量,如果是就做优化
 (2). String a=“hello”+“hi”;==>底层优化等价于 String a=“hellohi”;
- 以下语句创建了几个对象?
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise3 {
    public static void main(String[] args) {
        String a="hello";
        String b="hi";
        String c=a+b;
        /*
        创建了3个对象,但是对象引用不一样。a和b指向的常量池的字符串常量对象;而c指向的堆中对象的value。
        底层实现:
        1. 先创建一个StringBuilder sb=StringBuilder();
        2. 执行 sb.append("hello");
        3. sb.append("hi");
        4. String c=sb.toString();
        最后 c 指向堆中的对象(String) value[]-->池中"hellohi"
         */
        //证明c指向的不是池中的hellohi
        String s="hellohi";
        String s2="hello"+"hi";
        System.out.println(c==s);//false
        System.out.println(c==s2);//false
    }
}
 
总结:
 (1). 底层是StringBuilder sb=StringBuilder(); sb.append(“hello”); sb.append(“hi”);
 (2). String c=sb.toString(); sb在堆中,并且append是在原来字符串的基础上追加的。
 (3). 重要规则:String c1=“ab”+“cd”;常量相加,看的是池。String c1=a+b; 变量相加,是在堆中。
- 判断下面代码输出什么?为什么?
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringExercise4 {
    public static void main(String[] args) {
        String s1="hello";//指向池中的"hello"
        String s2="hi";//指向池中的"hi"
        String s3="hellohi";//指向池中的"hellohi"
        String s4=(s1+s2).intern();//指向池中的"hellohi"
        System.out.println(s3==s4);//true
        System.out.println(s3.equals(s4));//true
    }
}
 
- 判断下面代码输出什么?为什么?(重点)
 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Test1 {
    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  wello
    }
    String str = new String("hello");
    final char[] ch ={'h','e','l','l','o'};
    public void change(String str ,char ch[]){
        str="hi";
        ch[0]='w';
    /*
    理解:首先在堆中创建了一个Test1对象指向main栈中的ex,在这个Test1对象中,有创建了一个str指向堆另一个String对象
    这个String对象有个属性value,value指向池中的"hello",ch就直接在静态区生成数组。
    然后ex引用变量调用方法change(),传入了str和ch.这时候在change栈中有一个str的变量指向了Test1对象的str
    而ch直接指向栈中静态区的数组。再然后执行str="hi",它是change栈中str的变量就去常量池中寻找或创建。
    也就是说这时候change栈的str指向的是池中的"hi"与Test1对象的str就没有关系了。
    而ch[0]='w'是栈中数组的引用传递,是可以直接在静态区的数组进行修改。所以最后输出:hello   and  wello
     */
    }
}
 
11.2.5 String类的常见方法
说明:
 String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder和StringBuffer来增强String的功能,并提高开发效率。
- String类的常见方法一览(不用背,用多就会啦)
(1). equals //区分大小写,判断内容是否相等
(2). equalsIgnoreCase //忽略大小写的判断内容是否相等
(3). length //获取字符的个数,字符串长度
(4). indexOf //获取字符或子串在字符串中第一次出现的索引,索引从0开始,如果找不到就返回-1
(5). lastIndexOf //获取字符或子串在字符串中最后一次出现的索引,索引从0开始,如果找不到就返回-1
(6). substring //截取指定范围的子串
(7). trim //去前后空格
(8). charAt //获取某索引处的字符,注意不能使用Str[index]这样的方式
(9). toUpperCase //将小写字母转换成大写
(10). toLowerCase //将大写字母转换成小写字母
(11). concat //拼接字符串
(12). replace //替换字符串中的字符,返回的是新的字符串,本身没有改变
(13). split //分割字符串,对于某些分割字符,需要用到转义 .比如| \等
(14). compareTo // 比较两个字符串的大小,如果前者大则返回正数;否则就返回负数;若相等则返回0
(15). toCharArray //将字符串转换成字符数组
(16). format //格式化字符串,占位符:%s字符串 %c字符 %d整型 %.2f浮点型(四舍五入) 
package chapter11.string_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringMethod01 {
    public static void main(String[] args) {
        //(1). equals  //区分大小写,判断内容是否相等
        String s1="hello";
        String s2="Hello";
        System.out.println(s1.equals(s2));//false
        //(2). equalsIgnoreCase //忽略大小写的判断内容是否相等
        String a1="hi";
        String a2="HI";
        System.out.println(s1.equalsIgnoreCase(a2));//false
        //(3). length //获取字符的个数,字符串长度
        System.out.println("hello".length());//5
        //(4). indexOf //获取字符或子串在字符串中第一次出现的索引,索引从0开始,如果找不到就返回-1
        String b1="ehi@hi@3@";
        System.out.println(b1.indexOf('@'));//3
        System.out.println(b1.indexOf("hi"));//1
        System.out.println(b1.indexOf('c'));//-1
        //(5). lastIndexOf  //获取字符或子串在字符串中最后一次出现的索引,索引从0开始,如果找不到就返回-1
        String b2="ehi@hi@3@";
        System.out.println(b2.lastIndexOf('@'));//8
        System.out.println(b1.lastIndexOf("hi"));//4
        System.out.println(b2.lastIndexOf('c'));//-1
        //(6). substring //截取指定范围的子串
        String c="hello,java";
        System.out.println(c.substring(1));//从索引开始截取到最后面:ello.java
        System.out.println(c.substring(1,3));//截取索引1-2(遵循左闭右开):el
        //(7). trim  //去前后空格
        String d="   hello    ";
        System.out.println(d.trim());//hello
        //(8). charAt  //获取某索引处的字符,注意不能使用Str[index]这样的方式
        String e="hello";
        System.out.println(e.charAt(2));//l
        //(9). toUpperCase //将小写字母转换成大写
        String f="HEllo";
        System.out.println(f.toUpperCase());//HELLO
        //(10).    toLowerCase  //将大写字母转换成小写字母
        String g="heLLO";
        System.out.println(g.toLowerCase());//hello
        //(11).    concat  //拼接字符串
        String h1="你好";
        String h2=",mark";
        System.out.println(h1.concat(h2));//你好,mark
        //(12).    replace //替换字符串中的字符,返回的是新的字符串,本身没有改变
        String i="hello,jack";
        System.out.println(i.replace("jack","mark"));//将所有的jack替换为mark:hello,mark
        System.out.println(i);//hello,jack
        //(13).    split  //分割字符串,对于某些分割字符,需要用到转义 \.比如| \\等
        String j1="hi,mark";
        System.out.println(j1.split(",")[0]);//以,为标准进行分割,返回的是一个数组:hi
        String j2="E:\\cd\\ef";
        System.out.println(j2.split("\\\\")[0]);//E:
        //(14).    compareTo  //比较两个字符串的大小,如果前者大则返回正数;否则就返回负数;若相等则返回0
        // 比较规则:从str1和str2两个字符串的索引0开始按字符逐一比较,若第一个相同,则一直往下比较,
        // 直到str1和str2的某个位置的字符不相同,用str1的字符 - str2的字符(按Unicode码来)。
        //若 str1 和 str2 直到最后一个字符都相同,则比较长度,返回 str1.length() - str2.length()。
        String str1="abff";//a-97,b-98,c-99
        String str2="acd";
        String str3="acdef";
        System.out.println(str1.compareTo(str2));//-1
        System.out.println(str2.compareTo(str3));//-2
        //(15).    toCharArray  //将字符串转换成字符数组
        String l="hello";
        char[] ch=c.toCharArray();
        System.out.println(ch[0]);//h
        //(16).    format  //格式化字符串,占位符:%s字符串 %c字符  %d整型 %.2f浮点型(四舍五入)
        String n="我的名字是%s  年龄是%d  成绩是%.2f 性别是%c . 很高兴认识大家....";
        String info=String.format(n,"mark",22,87.758,'男');
        System.out.println(info);//我的名字是mark  年龄是22  成绩是87.76 性别是男 . 很高兴认识大家....
    }
}
 
- 输入商品名称和商品价格,要求打印效果示例,使用String.format的方法来实现:
StringMethod02.java
商品名 商品价格
手机 123,456.79
要求:使用千位分隔符。 
package chapter11.string_;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringMethod02 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.print("请输入商品:");
        String goods=scanner.next();
        double price= 0;
        try {
            System.out.print("请输入手机价格:");
            price = scanner.nextDouble();
        } catch (InputMismatchException e) {
            System.out.println("你输入的价格不正确(默认0.00)");
        }
        String ans =String.format("商品名\t商品价格\n%s\t\t%,.2f",goods,price);
        System.out.print(ans);
    }
}
/*
请输入商品:菠萝手机
请输入手机价格:123
商品名	商品价格
菠萝手机		123.00
 */
 
11.3 StringBuffer
11.3.1 StringBuffer结构剖析
-  
基本介绍
(1). Java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。
(2). 很多方法和String相同,但StringBuffer是可变长度的。
(3). StringBuffer是一个容器。 -  
结构剖析
(1). StringBuffer 的直接父类是AbstractStringBuilder
(2). StringBuffer 实现了Serializable ,即StringBuffer的对象可以序列化(串行化)、比如保存文件、或网络传输。
(3). 在父类中 AbstractStringBuilder 有属性 byte[ ] value,不是final,该value数组存放的是字符串内容,因此存放在堆中,而不是常量池中。
(4). StringBuffer是一个fianl类,不能被继承
(5). 因为StringBuffer 字符内容是在 byte[ ] value,所以在变化(增加/删除)不用每次都更换地址(即不是每次都创建对象),所以效率高于String。 -  
String VS StringBuffer
String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低 //private final char value[ ];
StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址(除了空间不够),效率较高 // char[ ] value //放在堆中 
11.3.2 StringBuffer转换
- StringBuffer的构造器
 
| 构造方法 | 描述 | 
|---|---|
| StringBuffer() | 构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符。 | 
| StringBuffer(CharSequence seq) | 构造一个字符串缓冲区,它包含与指定的CharSequence相同的字符 | 
| StringBuffer(int capacity) | 构造一个不带字符,但具有指定初始容量的字符串缓冲区。即对byte[ ]大小进行指定 | 
| StringBuffer(String str) | 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。 | 
package chapter11.stringbuffer_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringBuffer01 {
    public static void main(String[] args) {
        //1.构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符。
        StringBuffer stringBuffer = new StringBuffer();//16
        System.out.println(stringBuffer.capacity());
        //2.构造一个不带字符,但具有指定初始容量的字符串缓冲区。即对byte[ ]大小进行指定
        StringBuffer stringBuffer1 = new StringBuffer(4);//4
        System.out.println(stringBuffer1.capacity());
        //3.构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。char[ ]大小 str.length()+16
        StringBuffer hello = new StringBuffer("hello");//21
        System.out.println(hello.capacity());
    }
}
 
- String和StringBuffer相互转换
在开发中,经常需要将String和StringBuffer进行转换,看看如何实现。 
package chapter11.stringbuffer_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringBuffer02 {
    public static void main(String[] args) {
        //String-->StringBuffer
        String s = "hello";
        //方式一 使用构造器,对s本身没有任何影响
        StringBuffer b1=new StringBuffer(s);
        //方式二 使用append()方法
        StringBuffer b2=new StringBuffer();
        b2.append(s);
        //StringBuffer-->String
        //方式一 使用StringBuffer提供的toString()方法
        String s2=b1.toString();//b1 [StringBuffer]
        //方式二 使用构造器
        String s3=new String(b2);
    }
}
 
11.3.3 StringBuffer方法
- StringBuffer类常用方法
StringBufferMethod.java
(1). 增 append()
(2). 删 delete(start,end)
(3). 改replace(start,end,string) //将start—end间的内容替换掉,不含end
(4). 查 indexOf() //查找子串在字符串第一次出现的索引,如果找不到返回-1
(5). 插 insert()
(6). 获取长度 length() 
package chapter11.stringbuffer_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringBufferMethod {
    public static void main(String[] args) {
        StringBuffer strbu=new StringBuffer("hello");
        //1. 增
        strbu.append(',');
        strbu.append("李四");
        strbu.append("王五").append(100).append(true).append(19.19);
        System.out.println(strbu);//hello,李四王五100true19.19
        //2.删 (start,end)左闭右开
        strbu.delete(6,10);
        System.out.println(strbu);//hello,100true19.19
        //3.改(start,end,"")左闭右开
        strbu.replace(9,13,"false");
        System.out.println(strbu);//hello,100false19.19
        //4.查
        int ans =strbu.indexOf("1");
        System.out.println(ans);//6
        //5.插
        strbu.insert(6,"小青");//索引6插入,原来索引为6后移
        System.out.println(strbu);//hello,小青100false19.19
        //6.获取长度
        int len=strbu.length();
        System.out.println(len);//21
    }
}
 
11.3.4 StringBuffer练习
- 看看下面代码输出什么?为什么?(不要猜,要看看源码)
 
package chapter11.stringbuffer_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringBufferExercise01 {
    public static void main(String[] args) {
        String str =null;
        StringBuffer sb=new StringBuffer();
        sb.append(str);//查看源码知:如果str=null,就生成一个null的字符串
        System.out.println(sb.length());//4
        System.out.println(sb);//null
        // null.lenth()存在异常:NullPointerException
        StringBuffer sb1=new StringBuffer(str);//查看源码知:super(str.length() + 16);
        System.out.println(sb1);//
    }
}
 
- 输入商品名称和商品价格,要求打印效果示例,使用StringBuffer的insert的方法来实现:
StringBufferExercise02.java
商品名 商品价格
手机 123,456.48
要求:使用千位分隔符(不考虑进行四舍五入)。 
package chapter11.stringbuffer_;
import java.util.Scanner;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringBufferExercise02 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.print("请输入商品:");
        StringBuffer goods=new StringBuffer(scanner.next());
        System.out.print("请输入价格:");
        StringBuffer price=new StringBuffer(scanner.next());
        int i=price.indexOf(".");
        int len=price.length();
        if(i==-1){
            i=len;
        }
        while(i>3){
            i-=3;
            price.insert(i,",");
        }
        System.out.println(goods);
        System.out.println(price);
    }
}
/*
请输入商品:123
请输入价格:123456.34
123
123,456.34
 */
 
11.4 StringBuilder
11.4.1 StringBuilder结构剖析
-  
StringBuilder基本介绍
(1). 一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。
(2). 在StringBuilder上的主要操作是append和insert方法,可重载这些方法,以接收任意类型的数据。 -  
StringBuilder常用方法
StringBuilder和StringBuffer均代表可变的字符序列,方法是一样的,所以使用和StringBuffer一样。 -  
StringBuilder结构剖析
(1). StringBuilder 继承 AbstractStringBuilder类
(2). 实现了Serializable,说明StringBuilder对象是可以串行化(网络传输、保存到文件)
(3). StringBuilder 是final类,不能被继承
(4). StringBuilder 对象字符序列仍然是存放在其父类AbstractStringBuilder 的byte[] value;因此,字符序列是在堆中的。
(5). StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此在单线程的情况下优先使用StringBuilder。 
11.4.2 StringBuilder应用
- String、StringBuffer和StringBuilder的比较(面试)
(1). StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样。
(2). String:不可变字符序列,效率低,但是复用率高(即可以被多个变量指向)
(3). StringBuffer:可变字符序列、效率较高(增删)、线程安全
(4). StringBuilder:可变字符序列、效率最高、线程不安全
(5). String使用注意事项: 
String s="a";
s+="b";//实际上原来的"a"字符串对象因为没有对象引用指向,所以就丢弃了(被JVM销毁了),现在又生成了一个字符串s+="b"(也就是"ab")。
//如果多次执行这些改变串内容的操作,会导致大量副本字符串对象留在内存中,降低效率。如果这样的操作放到循环中,
// 会极大影响程序的性能==>结论:如果我们对String做大量修改,不要使用String
 
- 测试String、StringBuffer和StringBuilder执行效率
 
package chapter11.StringBulider_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class StringBuilder01 {
    public static void main(String[] args) {
        final int ITERATIONS = 1000000;
        // 测试 String
        long startTime = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < ITERATIONS; i++) {
            str += "a";
        }
        long endTime = System.currentTimeMillis();
        System.out.println("String 执行时间: " + (endTime - startTime) + " ms");
        // 测试 StringBuffer
        startTime = System.currentTimeMillis();
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < ITERATIONS; i++) {
            stringBuffer.append("a");
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer 执行时间: " + (endTime - startTime) + " ms");
        // 测试 StringBuilder
        startTime = System.currentTimeMillis();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < ITERATIONS; i++) {
            stringBuilder.append("a");
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder 执行时间: " + (endTime - startTime) + " ms");
    }
}
/*
String 执行时间: 72706 ms
StringBuffer 执行时间: 12 ms
StringBuilder 执行时间: 9 ms
 */
 
- String、StringBuffer和StringBuilder的选择(使用的原则)
(1). 如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
(2). 如果字符串存在大量的修改操作,存在单线程的情况,使用StringBuilder
(3). 如果字符串存在大量的修改操作,存在多线程的情况,一般使用StringBuffer
(4). 如果字符串很少修改,被多个对象引用,使用String,比如配置信息等 
11.5 Math
- 基本介绍
Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。 - 方法一览(均为静态方法)只例举了部分(具体查看API)
 

 4. Math类常见方法应用案例MathMethod.java
 (1). abs绝对值
 (2). pow 求幂
 (3). ceil 向上取整
 (4). floor 向下取整
 (5). round 四舍五入
 (6). sqrt 求开方
 (7). random 求随机函数
 (8). max 求两个数的最大值
 (9). min 求两个数的最小值
package chapter11.math_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class MathMethod {
    public static void main(String[] args) {
        //(1). abs绝对值
        System.out.println(Math.abs(-99));//99
        //(2). pow 求幂,返回double
        System.out.println(Math.pow(2,3));//8.0,2的3次方
        //(3). ceil  向上取整,返回double
        System.out.println(Math.ceil(-2.000001));//-2.0
        //(4). floor  向下取整,返回double
        System.out.println(Math.floor(-1.0000001));//-2.0
        //(5). round 四舍五入,返回long
        System.out.println(Math.round(4.56768));//5
        //(6). sqrt  求开方,返回double
        System.out.println(Math.sqrt(4));//2.0
        //(7). random 求随机函数,一个伪随机 double大于或等于 0.0并小于 1.0,返回double
        System.out.println(Math.random());
        //(8). max 求两个数的最大值
        System.out.println(Math.max(10,9));//10
        //(9). min 求两个数的最小值
        System.out.println(Math.min(10,9));//9
    }
}
 
- 练习
(1). 请使用Math.random获取a-b之间的一个随机整数,a和b均为整数,比如:a=2,b=7 
package chapter11.math_;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class MathExercise {
    public static void main(String[] args) {
        int a=2;
        int b=7;
        for (int i = 0; i < 15; i++) {
            int ans=(int) (a+Math.random()*(b-a+1));
            System.out.println(ans);
        }
    }
}
//输出随机的2至7
 
11.6 Date、Calendar、LocalDate…
日期类分为了三代。【知道怎么查,怎么用即可,不用每个方法都背】
11.6.1 第一代日期类
- 日期和时间模式

 - Date:精确到毫秒,代表特定的时间
 - SimpleDateFormat:格式和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化
 
package chapter11.date_;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Date01 {
    public static void main(String[] args) {
        // 1.获取当前系统时间
        // 2.这里的Date类是在java.util中的,而不是在java.sql中
        // 3.默认输出的日期格式是外国的方式,通常需要进行格式化处理
        Date d1 = new Date();
        System.out.println(d1);//Sun Aug 11 23:21:36 CST 2024
        //获取某个时间对应的毫秒数
        System.out.println(d1.getTime());//1723389696776
        //通过指定毫秒数得到时间
        Date d2 = new Date(9234567);
        System.out.println(d2);//Thu Jan 01 10:33:54 CST 1970
        //这里的字母是规定好的,不可以乱写
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
        //将日期转换成指定格式的字符串
        String format =sdf.format(d1);
        System.out.println(format);//2024年08月11日 11:32:16 周日
        //1.将文本转换成日期格式
        //2.把Date输出时,仍然还是外国的方式,如需指定格式还是要转换
        //3.在把String-->Date  , 使用的sdf格式需要和String的格式一样,否则就会抛出ParseException异常
        String s="1996年02月23日 10:20:30 星期一";
        try {
            Date parse=sdf.parse(s);
            System.out.println(parse);//Fri Feb 23 10:20:30 CST 1996
        } catch (ParseException e) {
            System.out.println("日期格式不对");
        }
    }
}
 
11.6.2 第二代日期类
- 第二代日期类,主要就是Calendar类(日历)
 
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
 
- Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HUOR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法
 
package chapter11.date_;
import java.util.Calendar;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Calendar01 {
    public static void main(String[] args) {
        //1.Calendar是一个抽象类,并且构造器是protected
        //2.可以通过getInstance() 来获取实例
        //3.提供大量的方法和字段提供给程序员
        //4.Calendar没有专门的格式化方法,所以需要程序员自己来组合显示
        //5.如果需要按照 24小时进制来获取时间,Calendar.HOUR 改为 Calendar.HOUR_OF_DAY
        Calendar c = Calendar.getInstance();//创建日历类对象
        //获取日历对象的某个日历字段
        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.HOUR_OF_DAY));
        System.out.println("分钟:" + c.get(Calendar.MINUTE));
        System.out.println("秒:" + c.get(Calendar.SECOND));
        //Calendar没有专门的格式化方法,所以需要程序员自己来组合显示
        System.out.println(c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月"
                + c.get(Calendar.DAY_OF_MONTH) + "日");
    }
}
/*
年:2024
月:8
日:12
小时:3
小时:15
分钟:48
秒:5
2024年8月12日
 */
 
11.6.3 第三代日期类
-  
前面两代日期类的不足分析(具体使用请查看API文档)
(1). JDK1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK1.1引入了Calendar类之后被弃用了。
(2). 而Calendar也存在问题是:
① 可变性:像日期和时间这样的类应该是不可变的。
② 偏移性:Date中的年份是从1900开始的,而月份都从0开始
③ 格式化:格式化只对Date有用,Calendar则不行
④ 此外,它们也不是线程安全的;不能处理闰秒等(每隔两天,多出1s) -  
第三代日期类常见方法JDK8加入
LocalDate(日期/年月日)、LocalTime(时间/时分秒)、LocalDateTime(日期时间/年月日时分秒)
(1). LocalDate只包含日期,可以获取日期字段
(2). LocalTime只包含时间,可以获取时间字段
(3). LocalDateTime包含日期+时间,可以获取日期和时间字段 
package chapter11.date_;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class LocalDate_ {
    public static void main(String[] args) {
        //第三代日期
        LocalDateTime ldt =LocalDateTime.now();//返回当前日期时间(年月日时分秒)的对象
        System.out.println(ldt);//2024-08-12T16:09:01.867845500
        System.out.println(ldt.getYear());//2024
        System.out.println(ldt.getMonth());//AUGUST
        System.out.println(ldt.getMonthValue());//8
        System.out.println(ldt.getDayOfMonth());//12
        System.out.println(ldt.getHour());//16
        System.out.println(ldt.getMinute());//9
        System.out.println(ldt.getSecond());//1
        
        LocalDate.now();//返回当前年月日
        LocalTime.now();//返回当前时分秒
    }
}
 
(4). DateTimeFormatter格式日期类。类似于:
SimpleDateFormat
DateTimeFormat dtf=DatetimeFormatter.ofPattern(格式);
String str=dtf.format(日期格式);
 

package chapter11.date_;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class LocalDateFormat_ {
    public static void main(String[] args) {
        //创建当前日期时间(年月日时分秒)的对象
        LocalDateTime ldt = LocalDateTime.now();
        //创建DateTimeFormatter对象
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年mm月dd日 HH时mm分ss秒");
        String format = dtf.format(ldt);
        System.out.println(format);//2024年10月12日 19时10分53秒
    }
}
 
(5). Instant时间戳
 类似于Date
 提供了一系列和Date类转换的方式如下代码:
package chapter11.date_;
import java.time.Instant;
import java.util.Date;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Instant_ {
    public static void main(String[] args) {
        //1.通过 静态方法 now() 获取表示当前时间戳的对象
        Instant now=Instant.now();
        System.out.println(now);//2024-08-12T11:16:18.989720Z
        
        //2.将Instant----> Date:通过from
        Date date=Date.from(now);
        System.out.println(date);//Mon Aug 12 19:16:36 CST 2024
        
        //将Date---->Instant:通过Date的toInstant()
        Instant instant=date.toInstant();
        System.out.println(instant);//2024-08-12T11:16:52.273Z
    }
}
 
(6). 第三代日期类更多方法
- LocalDateTime类
 - MonthDay类:检查重复事件
 - 是否是闰年
 - 增加日期的某个部分
 - 使用plus方法测试增加时间的某个部分
 - 使用minus方法测试查看一年前和一年后的日期
 
package chapter11.date_;
import java.time.LocalDateTime;
import java.time.MonthDay;
import java.time.Year;
import java.time.temporal.ChronoUnit;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class DateTimeMethod_ {
    public static void main(String[] args) {
        // 当前日期和时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期和时间: " + now);
        // MonthDay类检查重复事件
        MonthDay event = MonthDay.now();
        System.out.println("今天的日期(月-日格式): " + event);
        // 是否是闰年
        int currentYear = now.getYear();
        boolean isLeapYear = Year.isLeap(currentYear);
        System.out.println(currentYear + " 是闰年吗? " + isLeapYear);
        // 增加日期的某个部分
        LocalDateTime futureDate = now.plusDays(10).plusMonths(1);
        System.out.println("增加10天和1个月后的日期: " + futureDate);
        // 使用plus方法测试增加时间的某个部分
        LocalDateTime dateInTwoWeeks = now.plusWeeks(2);
        System.out.println("从现在起2周后的日期: " + dateInTwoWeeks);
        // 使用minus方法测试查看一年前和一年后的日期
        LocalDateTime dateOneYearAgo = now.minusYears(1);
        LocalDateTime dateOneYearLater = now.plusYears(1);
        System.out.println("一年前的日期: " + dateOneYearAgo);
        System.out.println("一年后的日期: " + dateOneYearLater);
        // 使用ChronoUnit测试时间差
        long daysBetween = ChronoUnit.DAYS.between(now, dateOneYearLater);
        System.out.println("从现在到一年后共有 " + daysBetween + " 天");
    }
}
/*
当前日期和时间: 2024-08-12T19:32:29.285117800
今天的日期(月-日格式): --08-12
2024 是闰年吗? true
增加10天和1个月后的日期: 2024-09-22T19:32:29.285117800
从现在起2周后的日期: 2024-08-26T19:32:29.285117800
一年前的日期: 2023-08-12T19:32:29.285117800
一年后的日期: 2025-08-12T19:32:29.285117800
从现在到一年后共有 365 天
 */
 
11.7 System
11.7.1 System类常用的方法和案例
- exit退出当前程序
 - arraycopy:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
 - currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
 - gc:运行垃圾回收机制System.gc();
 
package chapter11.system_;
import java.util.Arrays;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class System01 {
    public static void main(String[] args) {
        //1.   exit退出当前程序
        System.out.println("hello");
//        System.exit(0);//0表示一个状态,正常的状态。
        System.out.println("hello");
        //2.   arraycopy:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组
        /*
        形参分析:
        src - 源数组。
        srcPos - 源数组中的起始位置。
        dest - 目标数组。
        destPos - 目标数据的起始位置。
        length - 要复制的数组元素个数。
         */
        int[] src={1,2,3};
        int[] dest= new int[3];//当前数组dest={0,0,0}
        System.arraycopy(src,1,dest,1,2);
        System.out.println(Arrays.toString(dest));//[0, 2, 3]
        //3.   currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
        long start=System.currentTimeMillis();
        System.out.println(start);//1723378894796
        //4.   gc:运行垃圾回收机制System.gc();
        System.gc();
    }
}
 
11.8 Arrays
11.8.1 Arrays类常见方法应用案例
- Arrays里面包含了一系列静态方法,用于管理或操作数据(比如排序和搜索)
(1). toString返回数组的字符串形式
(2). sort排序(自然排序和定制排序)。
(3). binarySearch 通过二分查找法进行查找,要求必须排好序。若无则return -(low + 1).
(4). copyOf数组元素的复制
(5). fill 数组元素的填充
(6). equals比较两个数组元素内容是否完全一致。
(7). asList 将一组值,转换成List集合 
package chapter11.arrays_;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class ArraysMethod {
    public static void main(String[] args) {
        //1.toString返回数组的字符串形式
        Integer arr1[] = {1, 2, 3, 4, 5, 6};
        System.out.println(Arrays.toString(arr1));//[1, 2, 3, 4, 5, 6]
        //2.sort排序(自然排序和定制排序)。
        Integer arr2[] = {1, -1, 7, 0, 89};
        //(1).默认排序,从小到大
        Arrays.sort(arr2);
        System.out.println(Arrays.toString(arr2));//[-1, 0, 1, 7, 89]
        //(2).定制排序,从大到小,传入两个参数,第一个是arr数组,第二个是实现了Comparator的匿名内部类,实现了compare方法。
        /*
        ①.体现的是接口编程的方式,源码分析:
        ②.Arrays.sort(arr3, new Comparator(),先进入Arrays的sort中
        最终到TimSort类的private static <T> void binarySort(T[] a, int lo, int hi, int start,
                                       Comparator<? super T> c)
         ③.执行到binarySort方法的代码,会根据动态绑定机制c.compare()执行传入的匿名内部类的方法compare()
          while (left < right) {
                int mid = (left + right) >>> 1;
                if (c.compare(pivot, a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
        ④.public int compare(Object o1, Object o2) 返回的是>0,还是<0;会影响整个排序结果
        这就充分体现了 接口编程+动态绑定+匿名内部类的综合使用;将来的底层框架和源码使用方式,会非常常见。
         */
        Integer arr3[] = {1, -1, 7, 0, 89};
        Arrays.sort(arr3, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Integer i1=(Integer) o1;
                Integer i2=(Integer) o2;
                return i2-i1;
            }
        });
        System.out.println(Arrays.toString(arr3));//[89, 7, 1, 0, -1]
        //(3). binarySearch 通过二分查找法进行查找,要求必须排好序。
        Integer[] arr4={1,4,5,9,12,34,45};
        int index=Arrays.binarySearch(arr4,5);
        System.out.println(index);//2
        int notindex=Arrays.binarySearch(arr4,35); // return -(low + 1);  // key not found.
        System.out.println(notindex);//-7,按道理35应该在34后面,即35的索引应该是6,即low=6
        //(4). copyOf数组元素的复制
        //拷贝的长度要>0,否则就会抛出异常NegativeArraySizeException,
        // 若大于拷贝数组arr的长度,就在新数组后面添加 null,若长度在0<=arr<arr.length(),则复制部分元素
        //该方法的底层使用的是  System.arraycopy()
        Integer[] arr5={1,2,3,4};
        Integer[] newArr = Arrays.copyOf(arr5,arr5.length+2);
        System.out.println(Arrays.toString(newArr));//[1, 2, 3, 4, null, null]
        //(5). fill 数组元素的填充
        Integer[] num = new Integer[]{9, 4, 3};
        Arrays.fill(num, 99);
        System.out.println(Arrays.toString(num));//[99, 99, 99]
        //(6). equals比较两个数组元素内容是否完全一致。
        Integer[] a1={1,2,3,4};
        Integer[] a2={1,2,3,4};
        boolean equals =Arrays.equals(a1,a2);
        System.out.println(equals);//true
        //(7). asList 将一组值,转换成list集合
        // 编译类型是List(接口)
        // 运行类型是java.util.Arrays$ArrayList,ArrayList是内部类
        // 静态内部类  private static class ArrayList<E> extends AbstractList<E>
        //        implements RandomAccess, java.io.Serializable
        List asList = Arrays.asList(1, 2, 3, 4, 5, 6);
        System.out.println("asList=" + asList);//asList=[1, 2, 3, 4, 5, 6]
        System.out.println(asList.getClass());//class java.util.Arrays$ArrayList
    }
}
 
11.8.2 Arrays类练习
- 实现冒泡排序
(1). 编写一个方法 Bubble 对整数数组进行冒泡排序,默认从小到大排序。
(2). 编写一个重载的方法 Bubble,接受一个 Comparator 对象,按照自定义的排序规则对整数数组进行冒泡排序。
要求:
(1). Bubble(Integer[] arr): 对给定的整数数组进行排序,按照从小到大的顺序。
(2). Bubble(Integer[] arr, Comparator c): 对给定的整数数组进行排序,按照 Comparator 提供的排序规则(可以是从大到小或其他自定义顺序)。 
package chapter11.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class ArraysBubble {
    public static void main(String[] args) {
        Integer arr[] = {3, -2, 12, 0, 4, 90};
        // 使用默认的冒泡排序(从小到大)
        Bubble(arr);
        System.out.println(Arrays.toString(arr)); // 输出: [-2, 0, 3, 4, 12, 90]
        Integer arr1[] = {3, -2, 12, 0, 4, 90};
        // 使用带有Comparator的冒泡排序(从大到小)
        Bubble(arr1, new Comparator<Integer>() {
            @Override
            public int compare(Integer i1, Integer i2) {
                // 比较两个整数,返回负数表示 i1 应该排在 i2 前面
                return i2 - i1;
            }
        });
        System.out.println(Arrays.toString(arr1)); // 输出: [90, 12, 4, 3, 0, -2]
    }
    /**
     * 冒泡排序算法,默认从小到大排序
     * @param arr 需要排序的整数数组
     */
    public static void Bubble(Integer[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                // 如果当前元素大于下一个元素,则交换它们
                if (arr[j] > arr[j + 1]) {
                    // 交换 arr[j] 和 arr[j + 1]
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
    /**
     * 带 Comparator 的冒泡排序算法,可以实现自定义排序规则
     * @param arr 需要排序的整数数组
     * @param c 自定义的 Comparator,用于决定排序规则
     */
    public static void Bubble(Integer[] arr, Comparator<Integer> c) {
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                // 使用 Comparator 比较当前元素和下一个元素
                if (c.compare(arr[j], arr[j + 1]) > 0) {
                    // 交换 arr[j] 和 arr[j + 1]
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}
 
- 案例:自定义Book类,里面包含name和price。有一个Book[] books= 5本书对象。使用Arrays.sort()方法 实现Comparator接口匿名内部类,也称为定制排序()。要求使用可以按照name长度排序、按照price排序(均可从大到小或从小到大)。
 
package chapter11.arrays_;
import java.util.Arrays;
import java.util.Comparator;
/**
 * @aim java基础学习
 * @note java笔记
 */
public 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;
    }
    public String getName() {
        return name;
    }
    @Override
    public String toString() {
        return "name='" + name + '\t' + ", price=" + price;
    }
}
class Test{
    public static void main(String[] args) {
        Book[] books=new Book[4];
        books[0]=new Book("西游记",200);
        books[1]=new Book("红楼梦",400);
        books[2]=new Book("水浒传",150);
        books[3]=new Book("三国演义",300);
        //这里没学过泛型就把<Book>去了。
        Arrays.sort(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book book1=(Book) o1;
                Book book2=(Book) o2;
                double price=book1.getPrice()-book2.getPrice();
                if(price>0){
                    return -1;
                }else if(price<0){
                    return 1;
                }else {
                    return 0;
                }
            }
        });
        for(Book book:books){
            System.out.println(book.toString());
        }
        //其他方式同理,这里就不写了,提示如果是书名,就length即可
    }
}
/*
name='红楼梦	, price=400.0
name='三国演义	, price=300.0
name='西游记	, price=200.0
name='水浒传	, price=150.0
*/
 
11.9 BigInteger、BigDecimal
11.9.1 BigInteger和BigDecimal介绍
-  
应用场景:
(1). BigInteger适合保存比较大的整型
(2). BigDecimal适合保存精度更高的浮点型(小数) -  
BigInteger和BigDecimal常见的方法
(1). add 加
(2). subtract
(3). multiple
(4). divide 
package chapter11.biginteger_;
import java.math.BigInteger;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class BigInteger_ {
    public static void main(String[] args) {
        BigInteger b1=new BigInteger("91234560000");
        BigInteger b2=new BigInteger("20000");
//        System.out.println(b1+b2);//错误,不允许使用+
        System.out.println(b1.add(b2));
        System.out.println(b1.subtract(b2));
        System.out.println(b1.multiply(b2));
        System.out.println(b1.divide(b2));
    }
}
/*
91234580000
91234540000
1824691200000000
4561728
 */
 
package chapter11.bigdecimal;
import java.math.BigDecimal;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class BigDecimal_ {
    public static void main(String[] args) {
        BigDecimal b1=new BigDecimal("1234567890.123");
        BigDecimal b2=new BigDecimal("10.123");
//        System.out.println(b1+b2);错误,不允许使用+
        System.out.println(b1.add(b2));
        System.out.println(b1.subtract(b2));
        System.out.println(b1.multiply(b2));
//        System.out.println(b1.divide(b2));//存在异常ArithmeticException,原因:就是除不进,无限小数。
        // 解决方法如下:保存的是分子的精度
        System.out.println(b1.divide(b2,BigDecimal.ROUND_CEILING));
    }
}
/*
1234567900.246
1234567880.000
12497530751.715129
121956721.340
 */
 
11.10 本章作业
- 编程题 Task01.java
(1). 将字符串中指定部分进行反转。比如将 “abcedf” “aedcbf”
(2). 编写方法public static String reverse(String str,int start,int end) 搞定 
package chapter11.task;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task01 {
    public static void main(String[] args) {
        String str = "abcdef";
        String reverse_str = null;
        try {
            reverse_str = reverse(str, 1, 4);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println(reverse_str);//aedcbf
    }
    public static String reverse(String str, int start, int end) {
        //对传入的参数做一个验证,一般:写出正确的情况,然后取反即可
        if (str == null || start < 0 || end >= str.length() || start > end) {
            throw new IllegalArgumentException("传入参数不正确");
        }
        char[] chars=str.toCharArray();
        for (int i=start,j=end; i < j; i++,j--) {
            char temp=chars[i];
            chars[i]=chars[j];
            chars[j]=temp;
        }
        return new String(chars);
    }
}
 
- 编程题 Task02.java
输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象,要求:
(1). 用户名长度为2-4
(2). 密码的长度为6,要求全是数字 isDigital
(3). 邮箱中包含@和.并且@在.的前面 
package chapter11.task;
import java.util.Scanner;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task02 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名(2-4个字符):");
        String username = scanner.next();
        System.out.print("请输入密码(6位数字):");
        String password = scanner.next();
        System.out.print("请输入邮箱:");
        String mailbox = scanner.next();
        try {
            // 调用userRegister方法进行用户注册验证
            userRegister(username, password, mailbox);
            System.out.println("恭喜你注册成功~");
        } catch (Exception e) {
            // 捕获并打印注册失败的异常信息
            System.out.println("注册失败:" + e.getMessage());
        } finally {
            // 关闭Scanner对象以释放资源
            scanner.close();
        }
    }
    /**
     * 验证用户输入的用户名、密码和邮箱是否符合要求
     *
     * @param username 用户名
     * @param password 密码
     * @param mailbox  邮箱
     * @throws IllegalArgumentException 如果输入的参数不合法,则抛出该异常
     */
    public static void userRegister(String username, String password, String mailbox) {
        // 检查输入参数是否为null
        if (username == null || password == null || mailbox == null) {
            throw new IllegalArgumentException("输入的参数不能为空");
        }
        // 验证用户名长度是否在2到4个字符之间
        int userLength = username.length();
        if (!(userLength >= 2 && userLength <= 4)) {
            throw new RuntimeException("用户名长度为2-4");
        }
        // 验证密码长度是否为6且全为数字
        if (!(password.length() == 6 && isDigital(password))) {
            throw new RuntimeException("密码长度为6,且全是数字");
        }
        // 验证邮箱中@和.的位置关系
        int front = mailbox.indexOf("@");
        int rear = mailbox.indexOf(".");
        if (!(front > 0 && rear > front)) {
            throw new RuntimeException("邮箱中包含@和.并且@在.的前面");
        }
    }
    /**
     * 判断密码是否全由数字组成
     *
     * @param password 密码
     * @return 如果密码全是数字,则返回true;否则返回false
     */
    public static boolean isDigital(String password) {
        char[] chars = password.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            // 检查每个字符是否在'0'到'9'范围内
            if (chars[i] < '0' || chars[i] > '9') {
                return false;
            }
        }
        return true;
    }
}
 
- 编程题
(1). 编写java程序,输入形式为:Han Shun Ping的人名,以Ping,Han .S的形式打印出来。其中.S是中间单词的首字母。
(2). 例如输入:Willian Jefferson Clinton,输出形式为:Clinton,Willian .J 
package chapter11.task;
import java.net.SocketTimeoutException;
import java.util.Scanner;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task03 {
    public static void main(String[] args) {
        String n1 = "Han Shun Ping";
        String n2 = "Willian Jefferson Clinton";
        printName(n1);// Han,Ping .S
    }
    public static void printName(String str) {
        if (str == null) {
            System.out.println("不能为空");
            return;
        }
        String[] strings = str.split(" ");
        if (strings.length != 3) {
            System.out.println("字符格式不对");
            return;
        }
        String name = "%s,%s .%c";
        String info = String.format(name, strings[0], strings[2], strings[1].toUpperCase().charAt(0));
        System.out.println(info);
    }
}
 
- 编程题
输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字 
package chapter11.task;
import java.util.Scanner;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task04 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        count(str);
    }
    public static void count(String str) {
        if (str == null) {
            System.out.println("字符串不能为空");
            return;
        }
        int upperCount = 0;
        int lowerCount = 0;
        int numberCount = 0;
        int otherCount = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
                upperCount++;
            } else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
                lowerCount++;
            } else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                numberCount++;
            } else {
                otherCount++;
            }
        }
        System.out.println("大写字母=" + upperCount + "小写字母=" + lowerCount + "数字=" + numberCount + "其他=" + otherCount);
    }
}
/*
输入:123你好helloHI
大写字母=2小写字母=5数字=3其他=2
 */
 
- 试写出以下代码的运行结果
已知Animal类有属性name,可以通过有参构造为属性赋值。 
package chapter11.task;
/**
 * @aim java基础学习
 * @note java笔记
 */
public class Task05 {
    public static void main(String[] args) {
        String s1 = "hello";
        Animal a = new Animal(s1);
        Animal b = new Animal(s1);
        System.out.println(a == b);//false,对比的是不是同一对象
        System.out.println(a.equals(b));//false,对比的是不是同一对象
        System.out.println(a.name == b.name);//true,对比的是地址
        String s2 = new String("hello");
        String s3 = "hello";
        System.out.println(s1 == s2);//false
        System.out.println(s2 == s3);//false
        String t1 = "hello" + s1;//实际是一个String对象在堆中
        String t2 = "hellohello";
        System.out.println(t1.intern() == t2);//true
    }
}
class Animal {
    String name;
    public Animal(String name) {
        this.name = name;
    }
}
                


















