Java常用类

包装类

什么是包装类?

以前定义变量,经常使用基本数据类型,基本数据类型就是一个数,在这基础上加点属性、方法、构造器,就可以将基本数据类型封装成一个新的类——包装类。

包装类是引用数据类型,int,byte是基本数据类型

对应关系

基本数据类型 对应的包装类 继承关系
byte Byte Object-->Number
short Short Object-->Number
int Integer Object-->Number
long Long Object-->Number
float Float Object-->Number
double Double Object-->Number
char Character Object
boolean Boolean Object

为什么需要封装为包装类

  • Java是面向对象的语言,擅长操作各种各样的类。
  • 以前学习装数据的是数组,如int[],String[],Student[],以后学习装数据的是集合,它有一个特点就是只能装引用类型的数据

包装类常用属性、常用方法(重点)

【1】Integer类可以直接使用,无需导包:

API类.png

【2】类的继承关系:

类继承关系.png

【3】实现的接口:

已实现的接口.png

【4】这个类被 final修饰,说明这个类不能被子类继承,也就是说它没有子类:

声明格式.png

【5】包装类是对基本数据类型的封装

对 int类型封装生成 Integer类:

int封装成Integer.png

【6】类的历史:

Integer类从JDK1.0诞生

类历史版本.png

【7】属性:

package com.commonclass.demo01;

/*
    使用包装类 Integer的静态常量,模拟类型溢出
 */
public class Field {
    public static void main(String[] args) {
        //属性
        System.out.println(Integer.MAX_VALUE); //2147483647
        System.out.println(Integer.MIN_VALUE); //-2147483648

        //补数,物极必反
        System.out.println(Integer.MAX_VALUE+1); //-2147483648 类型溢出
        System.out.println(Integer.MIN_VALUE-1); //2147483647
    }
}
image-20211015205505726

【8】构造器,发现没有无参构造,但是有 有参构造

(1)int类型作为构造器的参数,返回对应的包装类

Integer i1 = new Integer(12);

构造器.png

(2)String类型作为构造器的参数:

        Integer i2 = new Integer("15"); //String的数字可以
//        Integer i3 = new Integer("ilil"); //异常,无法转成int类型

构造器1.png

【9】包装类特有的机制:自动装箱,自动拆箱(重点难点)

  • 自动装箱是从 JDK1.5 以后的新特性。
  • 自动装箱,自动拆箱是将基本数据类型和包装类进行快速转换
package com.commonclass.demo01.test;

/*
    自动装箱,自动拆箱
 */
public class AutoCast {
    public static void main(String[] args) {

        //自动装箱:int --> Integer
        Integer i = 2;
        System.out.println("基本类型已自动装箱为包装类!包装类为:" + i);

        //自动拆箱:Integer --> int
        Integer i2 = new Integer(5);
        int num = i2;
        System.out.println("包装类已转换为基本类型,基本类型为:" + num);

    }
}

验证:

1、采用反编译验证,发现自动装箱走的是 valueOf()方法!这个方法是静态方法!

2、发现自动拆箱走的是 intValue()方法!这个方法是普通方法

自动装箱1.png

可以自己打断点测试观察是否走入valueOf方法中:

自动装箱2.png

说明:

1)static final int low = -128;最小值是-128

2)static final int high 是127;最大值是127

3)if (i >= IntegerCache.low && i <= IntegerCache.high) if语句当作过滤器,判断传入的 i 是否在这个范围内?这个范围是 -128 ~ 127

4)return IntegerCache.cache[i + (-IntegerCache.low)]; 从 cache数组中取一个Integer值,这个值是int基本类型的包装类

5)如果传入的 i 在 -128 ~ 127 之间,直接从cache数组中取对应的包装类,如果不在范围,就交给 Integer() 方法,也会返回对应的包装类!

【10】常用方法:

学习方法:通过看源码和API帮助文档了解怎么使用和实现方法,不需要死记硬背。用到的时候看API文档就行。

valueOf()方法的底层:【重点】

valueOf方法的底层.png

Integer类常用方法

compareTo()、equals()、intValue()、parseInt()、toString()

package com.commonclass.demo01;

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

        //compareTo:比较包装类大小,只返回三个值:-1,0,1,表示小于,等于,大于
        Integer i1 = new Integer(6);
        Integer i2 = new Integer(12);
        //如果i1小于i2,返回-1;如果i1等于i2,返回0;如果i1大于i2,返回1
        System.out.println(i1.compareTo(i2)); //return (x < y) ? -1 : ((x == y) ? 0 : 1);

        //equals:比较两个对象的值,Integer类对Object中的equals方法进行了重写,比较的是底层封装的那个value的值
        //Integer对象是通过new关键字创建的对象:
        Integer i3 = new Integer(12);
        Integer i4 = new Integer(12);
        System.out.println(i3 == i4); //false,因为==比较的是两个对象的地址
        boolean flag = i3.equals(i4); //true,equals比较的是两个对象里面的内容
        System.out.println(flag);

        /*
        如果自动装箱的值在-128到127之间,那么==比较的是具体的数值
        否则,比较的是对象的地址
         */
        //Integer对象通过自动装箱实现:
        System.out.println("***************");
//        Integer i5 = 12;
//        Integer i6 = 12;
//      	System.out.println(i5 == i6); //true,比较值
        Integer i5 = 128;
        Integer i6 = 128;
        System.out.println(i5.equals(i6)); //true
        System.out.println(i5 == i6); //false,比较对象的内存地址
        System.out.println("***************");

        //intValue():将包装类转换为基本类型int,Integer-->int
        Integer i7 = 130;
        int i = i7.intValue();
        System.out.println(i);

        //parseInt(String s):把String类型解析成int类型,String-->int
        int i8 = Integer.parseInt("12");
        System.out.println(i8);

        //toString():把Integer包装类转换为String类型,Integer-->String
        Integer i9 = 130;
        System.out.println(i9.toString());

    }
}

日期类(重点难点)

java.util.Date【重点】

常用方法:toString()

package com.commonclass.demo02;

import java.util.Date;

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

        //java.util.Date:
        Date d = new Date();
        System.out.println(d); //隐式调用toString方法,Fri Oct 15 22:13:39 CST 2021
        System.out.println(d.toString()); //显式调用toString方法,Fri Oct 15 22:13:39 CST 2021
        System.out.println(d.toGMTString()); //过期方法,废弃方法
        System.out.println(d.toLocaleString());//废弃方法

        System.out.println(d.getYear()); //121,本质:121+1900=2021
        System.out.println(d.getMonth()); //6,返回的值在0~11之间,0表示1月

        //返回自1970年1月1日00:00:00 GMT 以来此Date对象表示的毫秒数
        System.out.println(d.getTime()); //1627709788328
        System.out.println(System.currentTimeMillis()); //1627709788328

        /*
        (1)问题:以后获取时间差用getTime()还是currentTimeMillis()?
        答案:使用currentTimeMillis(),因为这个方法是静态方法,可以使用 类名.方法名()直接调用,方便快捷
        (2)public static native long currentTimeMillis();
            native表示本地方法
            为什么没有方法体?
            因为这个方法的具体实现不是通过Java写的,是C/C++
        (3)这个方法的作用:
            应用场景:一般会用来衡量一些算法所用的时间!
         */
        long startTime = System.currentTimeMillis(); //开始计时
        for (int i = 1; i <= 100000; i++) { //跑10w遍
            System.out.println(i);
        }
        long endTime = System.currentTimeMillis(); //结束计时
        System.out.println("耗时:"+ (endTime - startTime) + "ms");

    }
}

java.sql.Date

java.sql.Date继承自 java.util.Date,所以java.sql.Date是子类,java.util.Date是父类。

1、java.sql.Date和java.util.Date的区别:

  • java.util.Date:年月日 时分秒
  • java.sql.Date:年月日

2、java.sql.Date和java.util.Date的联系:

  • java.util.Date(子类) extends java.util.Date(父类)
package com.commonclass.demo02;

import java.sql.Date;

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

        Date d = new Date(1627709788328L);
        System.out.println(d);
        /*
        (1)java.sql.Date和java.util.Date的区别:
        java.util.Date:年月日 时分秒
        java.sql.Date:年月日
        (2)java.sql.Date和java.util.Date的联系:
        java.util.Date(子类) extends java.util.Date(父类)
         */

        //java.sql.Date和java.util.Date相互转换:
        //【1】util --> sql
//        java.util.Date date = new java.util.Date(); //创建util.Date的对象
        java.util.Date date = new Date(1627709788328L); //根据指定秒数创建util.Date的对象
        //方式1:向下转型
        Date date1 = (Date)date;
        /*
        父类:Animal 子类:Dog
        Animal an = new Dog(); 父类引用指向子类对象
        Dog d = (Dog)an; 强转为子类
         */
        //方式2:利用构造器
        Date date2 = new Date(date.getTime()); //date2是java.sql.Date的对象

        //【2】sql --> util
        java.util.Date date3 = d;

        //【3】String --> sql.Date
        Date date4 = Date.valueOf("2021-6-1");
        System.out.println(date4);

    }
}

SimpleDateFormat【重点】

场景1:前台把数据传到后台,前台提交的是 String字符串格式,后台需要把 String类型转换成java.util.Date。

日期前后台.png

【1】String-->java.util.Date 类型转换:

分解步骤:

  1. String --> java.sql.Date
  2. java.sql.Date --> java.util.Date
package com.commonclass.demo02;

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

        //1、String --> java.sql.Date
        java.sql.Date date1 = java.sql.Date.valueOf("2020-1-1");
        //2、java.sql.Date -->  java.util.Date
        java.util.Date date2 = date1;
        System.out.println(date2.toString());
//        System.out.println(date2);
    }
}

上面的代码有局限性,字符串的格式只能是 年-月-日 拼接的形式,换成其他类型,就会出现异常:

java.lang.IllegalArgumentException:非法的参数异常

日期异常.png

【2】因为这样的原因,引入新的类:SimpleDateFormat

SimpleDateFormat主要有两个方法,parse()方法作用是把String解析成Date,format()方法作用是把Date格式化成String。

package com.commonclass.demo02;

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

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

        //日期转换
        //SimpleDateFormat(子类) extends DateFormat(父类是一个抽象类)
        //自定义转换格式:
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //String --> Date
        try {
            Date date = df.parse("2021-1-3 11:22:40"); //解析语句可能会报异常
//            System.out.println(date);
            System.out.println(date.toString());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //Date --> String
        String format = df.format(new Date());
        System.out.println(format);

        //其他的Date --> String,预设的转换格式
        Date date = new Date();
        System.out.println(date.toString());
        System.out.println(date.toGMTString());
        System.out.println(date.toLocaleString());

    }
}

【3】自定义日期格式:

这个就够用了,yyyy-MM-dd HH:mm:ss

SimpleFormat自定义日期格式.png

Calendar日期类

常用方法:get()、set()

package com.commonclass.demo02;

import java.util.Calendar;
import java.util.GregorianCalendar;

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

        //Calendar是一个抽象类,不可以直接创建对象,但我们可以创建它的实现类对象
        //GregorianCalendar(子类) extends Calendar(父类)
        Calendar cal = new GregorianCalendar();
        Calendar cal2 = Calendar.getInstance(); //静态方法getInstance返回一个Calendar对象
        System.out.println(cal);
      	System.out.println(cal2);

        //常用的方法:
        //get方法,传入参数:Calendar中定义的常量
        System.out.println(cal.get(Calendar.YEAR));
        System.out.println(cal.get(Calendar.MONTH));
        System.out.println(cal.get(Calendar.DATE));
        System.out.println(cal.get(Calendar.DAY_OF_WEEK));
        System.out.println(cal.getActualMaximum(Calendar.DATE)); //获取当月日期的最大天数
        System.out.println(cal.getActualMinimum(Calendar.DATE)); //获取当月日期的最小天数

        //set方法:可以改变Calendar中的内容
        cal.set(Calendar.YEAR, 2000);
        cal.set(Calendar.MONTH, 5);
        cal.set(Calendar.DATE, 20);
        System.out.println(cal);

        //String --> Calendar
        //分解步骤:
        //1、String --> java.sql.Date
        java.sql.Date date = java.sql.Date.valueOf("2020-8-20");
        //2、java.sql.Date --> Calendar
        cal.setTime(date);
        System.out.println(cal);
    }
}

Calendar练习:

需求:用户输入日期,程序返回输入日期当月的日期。

Calendar练习.png

package com.commonclass.demo02;

import java.util.Calendar;
import java.util.Scanner;

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

        //1.录入日期的字符串String:
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入你想要查看的日期:(提示:请按照例如2019-3-7的格式)");
        String strDate = sc.next();
        //String --> Calendar
        //分解:
        //(1)String --> java.sql.Date
        java.sql.Date date = java.sql.Date.valueOf(strDate);
        //(2)java.sql.Date --> Calendar
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        //2.后续操作:
        //星期提示:
        System.out.println("日\t一\t二\t三\t四\t五\t六\t");

        //获取本月的最大天数:
        int maxDay = cal.getActualMaximum(Calendar.DATE);
        //获取当前日期中的日:
        int nowDay = cal.get(Calendar.DATE);
        //将日期调为本月的1号:
        cal.set(Calendar.DATE,1);
        //获取这个1号是本周的第几天:
        int num = cal.get(Calendar.DAY_OF_WEEK);
        //前面要空出来的天数为:
        int day = num - 1;
        //引入一个计数器:
        int count = 0;
        //在日期开始之前把空出来的天数打印出来:
        for (int i = 1; i <= day; i++) {
            System.out.print("\t");
        }
        //空出来的天数也要放入计数器
        count += day;
        //遍历:从1号开始到maxDay号进行遍历:
        for (int i = 1; i <= maxDay; i++) {

            if (i == nowDay) { //如果遍历的i和当前日子一样的话,后面多加一个*
                System.out.print(i+"*"+"\t");
            } else {
                System.out.print(i+"\t");
            }
            count++; // 每在控制台输出一个数字,计数器+1
            if (count % 7 == 0) { //当计数器的个数是7的倍数的时候,进行换行
                System.out.println();
            }
        }

    }
}

JDK1.8新增日期时间API【重点】

JDK1.0中使用java.util.Date类 --》 第一批日期时间API

JDK1.1引入Calendar类 --》 第二批日期时间API

缺陷⚠️:

可变性:像日期和时间这样的类,应该是不可变的。

偏移性:Date 的年份是从1900年开始的,月份是从0开始的。

格式化:格式化只对Date有用,对Calendar无效。

所以:JDK1.8新增日期时间API类 --》 第三批日期时间API

新增LocalDate,LocalTime,LocalDateTime类。

now()是静态方法,now()--获取当前的日期,时间,日期+时间

of()是静态方法,of()--指定日期,时间,日期+时间

常用方法:now()、of()、get()、with()

代码实现:

package com.commonclass.demo02;

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

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

        //完成实例化
        //now()是静态方法
        //方法1:now()--获取当前的日期,时间,日期+时间
        LocalDate localDate = LocalDate.now();
        System.out.println(localDate); //2021-08-08
        LocalTime localTime = LocalTime.now();
        System.out.println(localTime); //12:28:20.986490700
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime); //2021-08-08T12:28:20.986490700

        //方法2:of()--设置指定的日期,时间,日期+时间
        LocalDate of1 = LocalDate.of(2018, 12, 15);
        System.out.println(of1);
        LocalTime of2 = LocalTime.of(11, 10, 30);
        System.out.println(of2);
        LocalDateTime of3 = LocalDateTime.of(2000, 1, 30, 10, 24, 30);
        System.out.println(of3);

        //LocalDate,LocalTime用的不如LocalDateTime多
        //一系列常用的get方法
        System.out.println(localDateTime.getYear()); //2021
        System.out.println(localDateTime.getMonth()); //JULY
        System.out.println(localDateTime.getMonthValue()); //7
        System.out.println(localDateTime.getDayOfMonth()); //31
        System.out.println(localDateTime.getDayOfWeek()); //SATURDAY,星期几
        System.out.println(localDateTime.getHour()); //17
        System.out.println(localDateTime.getMinute()); //11
        System.out.println(localDateTime.getSecond()); //57

        //一系列常用的with方法,这里不叫set方法,叫with
        //with方法的特点是不可变性,修改后返回一个新的日期对象,源对象不被改变
        LocalDateTime localDateTime1 = localDateTime.withMonth(10);
        System.out.println(localDateTime);
        System.out.println(localDateTime1);
        LocalDateTime localDateTime2 = localDateTime.withHour(13);
        System.out.println(localDateTime);
        System.out.println(localDateTime2);

        //提供了加减操作:
        //加 plus
        LocalDateTime localDateTime3 = localDateTime.plusMonths(2);
        System.out.println(localDateTime);
        System.out.println(localDateTime3);
        //减 minus
        LocalDateTime localDateTime4 = localDateTime.minusMonths(3);
        System.out.println(localDateTime);
        System.out.println(localDateTime4);

    }
}

DateTimeFormatter【重点】

使用预定义的标准格式。如:ISO_LOCAL_DATE_TIME,ISO_LOCAL_DATE,ISO_LOCAL_TIME

常用方法:format()、parse()、ofPattern()

代码实现:

package com.commonclass.demo02;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;

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

        //格式化类:DateTimeFormatter

        //方法一:使用预定义的标准格式。如:ISO_LOCAL_DATE_TIME,ISO_LOCAL_DATE,ISO_LOCAL_TIME
        DateTimeFormatter df1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        //df1可以帮我们完成LocalDateTime和String之间的相互转换
        //LocalDateTime --> String
        LocalDateTime now = LocalDateTime.now();
        String str = df1.format(now);
        System.out.println(str); //2021-07-31T17:37:49.1268028

        //String --> LocalDateTime
        TemporalAccessor parse = df1.parse("2021-07-31T17:37:49.1268028");
        System.out.println(parse);

        //方法二:本地化相关的格式。如:ofLocalizedDateTime()
        //参数:FormatStyle.LONG,FormatStyle.MEDIUM,FormatStyle.SHORT
        //FormatStyle.MEDIUM:2021年7月31日下午5:50:59
        //FormatStyle.SHORT:2021/7/31 下午5:51
        DateTimeFormatter df2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
        //LocalDateTime -- > String
        LocalDateTime now1 = LocalDateTime.now();
        String str2 = df2.format(now1);
        System.out.println(str2);

        //String --> LocalDateTime
        TemporalAccessor parse1 = df2.parse("2021/7/31 下午5:51");
        System.out.println(parse1);

        //方法三:自定义的格式:如:ofPattern("yyyy-MM-dd hh:mm:ss") 重点,以后常用
        DateTimeFormatter df3 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //LocalDateTime -- > String
        LocalDateTime now2 = LocalDateTime.now();
        String str3 = df3.format(now2);
        System.out.println(str3); //2021-07-31 06:00:02

        //String --> LocalDateTime
        TemporalAccessor parse2 = df3.parse("2021-07-31 06:00:02");
        System.out.println(parse2);
        
    }
}

Math类

【1】直接使用,无需导包:

Math导包.png

【2】final修饰这个类,表示这个类不能被继承,即这个类没有子类:

Math类final修饰.png

【3】构造器私有化,不能创建Math类的对象:

Math类构造器私有.png

无法创建Math类对象:

Math类无法创建对象.png

【4】Math类的所有属性和方法都被static修饰,通过 类名.属性名类名.方法名 可以直接调用,无需创建对象:

static修饰Math类.png

【5】常用方法:

random()、abs()、ceil()、floor()、round()、max()、min()

package com.commonclass.demo03;

public class Demo01 {
    public static void main(String[] args) {
        //常用属性
        System.out.println("圆周率:" + Math.PI);

        //常用方法
        System.out.println("随机数:" + Math.random()); //[0.0,1.0)
        System.out.println("绝对值:" + Math.abs(-10));
        System.out.println("向上取整:" + Math.ceil(9.1)); //10.0
        System.out.println("向下取整:" + Math.floor(9.9)); //9.0
        System.out.println("四舍五入:" + Math.round(4.4)); //4
        System.out.println("四舍五入:" + Math.round(4.5)); //5
        System.out.println("最大值:" + Math.max(4, 6));
        System.out.println("最小值:" + Math.min(4, 6));
    }
}

【6】静态导包(了解)

静态导包后,不用写 类名.方法名 ,直接写 方法名 就能调用静态方法。

静态导包平时不建议使用!!!

package com.commonclass.demo03;

//静态导包
import static java.lang.Math.*;

public class Demo01 {
    public static void main(String[] args) {
        //常用属性
        System.out.println(Math.PI);

        //常用方法
        System.out.println("随机数:"+random()); //[0.0,1.0)
        System.out.println("绝对值:"+abs(-10));
        System.out.println("向上取整:"+ceil(9.1));
        System.out.println("向下取整:"+ floor(9.9));
        System.out.println("四舍五入:"+round(4.4));
        System.out.println("四舍五入:"+round(4.5));
        System.out.println("最大值:"+max(4, 6));
        System.out.println("最小值:"+min(4, 6));
     }
  
    //如果跟Math类中的方法重复了,默认会先走本类中的方法(就近原则)
    public static int random() {
        return 100;
    }
}

String类(重点难点)

【1】直接使用,无需导包:

String类无需导包.png

【2】字符串详解:

这个String类代表一个字符串。

String类解释1.png

String字符串.png

【3】字符串对象

String类解释2.png

String str = "abc";

"abc"就是String类的一个具体的对象。

【4】字符串是不可变的

字符串存储在常量池中,String对象被创建后,这个对象中的字符序列是不可改变的,直到这个对象被销毁。

String类解释3.png

【5】这个String类被final修饰,不能被继承,没有子类:

String类static.png

【6】String底层是一个 char类型的数组

String底层.png

验证:

String底层验证.png

String类常用方法【重点】

【1】构造器:底层就是给对象底层的 value数组进行赋值操作。

//通过构造器来创建对象:
String s1 = new String();
String s2 = new String("abc");
String s3 = new String(new char[] {'a', 'b', 'c'});

【2】常用方法

length(),isEmpty(),charAt()

package com.commonclass.demo04;

public class Demo02 {
    public static void main(String[] args) {
        String s4 = "abc";
        System.out.println("字符串的长度为:" + s4.length());

        String s5 = new String("abc");
        System.out.println("字符串是否为空:" + s5.isEmpty());

        System.out.println("获取字符串下标对应的字符为:" + s5.charAt(1));
    }
}

【3】equals方法:

比较两个String对象的字符串内容是否一样。

String-equals源码.png

String s6 = new String("abc");
String s7 = new String("abc");
System.out.println(s6.equals(s7)); //true

【4】String类实现了Comparable接口,里面有一个抽象方法叫compareTo,所以String类一定要对这个方法进行重写:

//compareTo()比较包装类的大小
String s8 = new String("abc");
String s9 = new String("abc");
System.out.println(s8.compareTo(s9)); //0,表示两个相等

String类compareTo源码.png

【5】常用方法

substring()、concat()、replace()、split()、toUpperCase()、toLowerCase()、trim()、toString()、valueOf()

//字符串的截取
String s10 = "abdkmclcxz";
System.out.println(s10.substring(3)); //从下标3开始截取,到字符串末尾
System.out.println(s10.substring(3, 6)); //下标[3,6)

//字符串拼接
System.out.println(s10.concat("mmmm"));

//字符串替换字符
String s11 = "abdkmclcxm";
System.out.println(s11.replace('m', 'e')); //把m替换成e

//按照指定的字符串进行分隔为数组的元素
String s12 = "a-b-c-d-e-f";
String[] strs = s12.split("-"); //以-分割字符串为String数组
System.out.println(Arrays.toString(strs));

//转字母大小写的方法
String s13 = "abc";
System.out.println(s13.toUpperCase());
System.out.println(s13.toUpperCase().toLowerCase());

//去除首尾空格
String s14 = "   a m  j   ";
System.out.println(s14.trim());

//toString()
String s15 = "abc";
System.out.println(s15);
//System.out.println(s15.toString());

//其他类型转换为String类型
System.out.println(String.valueOf(false));
System.out.println(String.valueOf(123.43423f));

String的内存分析【重点难点】

【1】字符串拼接

package com.commonclass.demo04;

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

        String s1 = "a" + "b" + "c";
        String s2 = "ab" + "c";
        String s3 = "a" + "bc";
        String s4 = "abc";
        String s5 = "abc" + "";

    }
}

上面的字符串,编译器会进行优化,直接合并成完整的字符串。

使用反编译验证:

String字符串拼接反编译.png

字符串存储在常量池中,常量池的特点是第一次如果没有这个字符串,就放进去,如果有这个字符串,就直接从常量池中取。

//三个引用对象都指向字符串常量池中的一个String
String s1 = "abc";
String s2 = "abc";
String s3 = "abc";

内存分析

String字符串拼接内存分析.png

【2】通过new关键字创建 String对象

String s6 = new String("abc");

内存分析

开辟两个空间:

1、字符串常量池中的字符串 "abc"

2、堆中创建的对象 new String("abc")

3、堆中存储对象的引用地址 String s6

String字符串new内存分析.png

【3】有变量参与的字符串拼接:

package com.commonclass.demo04;

public class Demo04 {
    public static void main(String[] args) {
        String a = "abc";
        String b = a + "def";
        System.out.println(b);
    }
}

变量a在编译的时候不知道a是 “abc” 字符串,所以不会进行编译期优化,不会直接合并为 “abcdef” 。

反编译class字节码文件,反编译是为了更好的分析字节码文件是如何执行的。

利用IDEA的终端:

反编译字节码文件.png

字符串拼接反编译.png

StringBuilder【重点难点】

【1】字符串的分类:

不可变字符串:String

可变字符串:StringBuilder,StringBuffer

StringBuilder和 StringBuffer的区别

  • StringBuffer类是线程安全的,StringBuilder不是线程安全的
  • 都是被final修饰的类,不能被继承,就是没有子类

【2】StringBuilder底层:

StringBuilder底层是一个 char类型的数组。

非常重要的两个属性:

StringBuilder底层.png

【3】StringBuilder内存分析

package com.commonclass.demo04;

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

        //创建StringBuilder对象
        //表面上调用StringBuilder的空构造器,实际上底层是对value数组进行初始化,默认长度是16
        StringBuilder sb1 = new StringBuilder();
        //表面上调用StringBuilder的有参构造器,传入一个int类型的数,实际底层是对value数组进行初始化,长度为你传入的数
        StringBuilder sb2 = new StringBuilder(3);

        StringBuilder sb = new StringBuilder("abc");
        System.out.println(sb.append("def").append("aaaaaaaa").append("bbb").append("0000000").toString());
        
    }
}

StringBuilder内存分析.png

什么是可变?什么是不可变?

【1】String --> 不可变

可变和不可变.png

【2】StringBuilder --> 可变

在 StringBuilder这个对象地址不变的情况下,想把 “abc” 变成 “abcdef” 是可能的,StringBuilder允许直接在后面追加。

package com.commonclass.demo04;

public class Demo06 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        System.out.println(sb.append("abc") == sb.append("def")); //true,比较的是地址
    }
}

StringBuilder和StringBuffer常用方法

【1】StringBuilder常用方法

append()、delete()、insert()、replace()、setCharAt()、substring()

package com.commonclass.demo04;

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

        StringBuilder sb = new StringBuilder("qianqinawanwan");

        //增
        sb.append("这是一首歌");
        System.out.println(sb); //qianqinawanwan这是一首歌

        //删
        sb.delete(4, 7); //删除位置在[4,7)上的字符
        System.out.println(sb); //qianawanwan这是一首歌

        sb.deleteCharAt(13); //删除位置在13上的字符
        System.out.println(sb); //qianawanwan这是首歌

        //改 --> 插入
        StringBuilder sb1 = new StringBuilder("$342324252432");
        sb1.insert(3, ","); //在下标为3的位置上插入 ,
        System.out.println(sb1); //$34,2324252432
        //改 --> 替换
        StringBuilder sb2 = new StringBuilder("$2凉凉4512421");
        sb2.replace(2, 4, "晴天"); //在下标[2,4)位置上替换字符串
        System.out.println(sb2); //$2晴天4512421
        
        sb2.setCharAt(4, '!'); //把下标为4的字符替换成 !
        System.out.println(sb2); //$2晴天!512421

        //查
        StringBuilder sb3 = new StringBuilder("absdsd");
        for (int i = 0; i < sb3.length(); i++) {
            System.out.print(sb3.charAt(i)+"\t");
        }
        System.out.println();

        //截取
        String str = sb3.substring(2, 4); //截取[2,4)返回的是一个新的String,对StringBuilder没有影响
        System.out.println(str);
        System.out.println(sb3);
        
    }
}

【2】StringBuffer常用方法

append()、delete()、insert()、replace()、setCharAt()、substring()

package com.commonclass.demo04;

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

        StringBuffer sb = new StringBuffer("qianqinawanwan");

        //增
        sb.append("这是一首歌");
        System.out.println(sb); //qianqinawanwan这是一首歌

        //删
        sb.delete(4, 7); //删除位置在[4,7)上的字符
        System.out.println(sb); //qianawanwan这是一首歌

        sb.deleteCharAt(13); //删除位置在13上的字符
        System.out.println(sb); //qianawanwan这是首歌

        //改 --> 插入
        StringBuffer sb1 = new StringBuffer("$342324252432");
        sb1.insert(3, ","); //在下标为3的位置上插入 ,
        System.out.println(sb1); //$34,2324252432
        //改 --> 替换
        StringBuffer sb2 = new StringBuffer("$2凉凉4512421");
        sb2.replace(2, 4, "晴天"); //在下标[2,4)位置上替换字符串
        System.out.println(sb2); //$2晴天4512421
        sb2.setCharAt(4, '!'); //在下标4位置前插入 !
        System.out.println(sb2);

        //查
        StringBuffer sb3 = new StringBuffer("absdsd");
        for (int i = 0; i < sb3.length(); i++) {
            System.out.print(sb3.charAt(i)+"\t");
        }
        System.out.println();

        //截取
        String str = sb3.substring(2, 4); //截取[2,4)返回的是一个新的String,对StringBuffer没有影响
        System.out.println(str);
        System.out.println(sb3);

    }
}

String,StringBuilder,StringBuffer的区别

  1. String类是不可变类,一旦 String对象被创建后,在这个对象中的字符串是不可改变的,直到这个对象被销毁。
  2. StringBuffer类是字符序列可变的字符串,可以通过append、delete、insert、charAt等方法改变它的内容。一旦生成了最终的字符串,调用 toString方法将其从char数组转换成 String。
  3. JDK1.5新增了一个 StringBuilder类,与 StringBuffer相似,构造器和方法基本相同。不同的是 StringBuffer是线程安全的,而 StringBuilder是线程不安全的,所以StringBuilder性能略高。通常情况下,创建一个内容可变的字符串,优先考虑使用StringBuilder

总结:

StringBuilder:从 JDK1.5开始,效率高,线程不安全

StringBuffer:从 JDK1.0开始,效率低,线程安全

posted @ 2021-08-08 17:33  siming笨笨  阅读(134)  评论(0)    收藏  举报