可变字符串

String字符串对象是一个常量,在定义后,值不可改变。

如果使用String类的对象,对其频繁更新时,就会不停地创建新的对象,不停引用给同一个变量。

如果要执行10000次循环重新赋值的过程,就要创建10000个对象,执行效率低,这时就可用可变字符串对象

package day2.com.hqyj.StringBuilder;

public class Test1 {
    public static void main(String[] args) {
        System.out.println("程序开始执行");
        //System.currentTimeMillis();用于获取当前时间对应的毫秒数
        //从1970 1 1 0:0:0这一刻开始,到这句话执行时间的间隔秒数
        long startTime = System.currentTimeMillis();

        /*
        //循环“更新”字符串,实际不停创建新的字符串
        String str = "";
        for (int i = 0; i < 10000; i++) {
            str+=i;
        }*/

        //使用可变的字符串StringBuilder对象,真正的更新字符串
        //因为全程只有一个对象StringBuilder,每次循环只是在不停操作该对象,不会创建新对象,所以效率很高
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append(i);
        }

        long endTime = System.currentTimeMillis();

        System.out.println("程序执行结束,用时"+(endTime-startTime)+"毫秒");
    }
}

StringBuilder类

用于表示可变字符串的一个类,是非线程安全的,建议在单线程环境下使用。

StringBuffer类

用于表示可变字符串的一个类,是线程安全的,建议在多线程环境下使用。

StringBuilder和StringBuffer中的方法都一直,只不过StringBuffer中的方法使用了synchronized关键字修饰,表示是一个同步方法。在多线程环境下不会出现问题。

这里以StringBuilder为例

构造方法

常用构造方法

作用

StringBuilder()

创建一个大小为16的字符数组,表示一个空白字符。类似于String str = “”;

StringBuilder(String str)

创建一个str长度+16的字符数组,将str添加到其中。类似于String str = “初始值”;

普通方法

常用方法

作用

append(Object obj)

将任意类型的参数添加到原可变字符串末尾

delete(int atsrt,int end)

删除[start,end)区间的字符

deleteCharAt(int index)

删除index上的索引

insert(int index,Object obg)

在索引index上插入obg

replace(int start,int end,String str)

将[start,end)区间内的字符替换为str

reverse()

反转字符串

注意

  • 以上表格中的方法都是在直接操作同一个字符串对象,每次调用方法后,原字符串都会发生变化
  • StringBuilder和StringBuffer中并没有重写equals方法,所以判断可变字符串的值是否相同时,调用的是equals中原始的==判断。如果要判断两个可变字符串的值是否相同时,需要将其转换为String后调用equals判断。

可变字符串与String之间的转换

String转换为可变字符串

String str = "hello";
//通过构造方法将String“包装”为可变字符串对象
StringBuilder sb= new StringBuilder(str);

可变字符串转String(任意类型对象转换为String)

方法一:String.valueOf(Object obj)方法

StringBuilder sb= new StringBuilder("你好");
//调用静态方法
String str = String.valueOf(sb);

方法二:对象toString();

StringBuilder sb= new StringBuilder("你好");
//调用toString()
String str = String.toString(sb);

方法三:

StringBuilder sb= new StringBuilder("你好");
//拼接一个空字符串
String str = sb + "";

比较String、StringBuilder和StringBuffer的区别

相同点:

  • 这三个类都可以表示字符串。都提供了一些操作字符串的方法
  • 这三个类中有相同的方法,如charAt()、indefOf()等
  • 这三个类都是被final修饰的类,不能被继承

不同点:

  • String定义的字符串是一个常量。StringBuilder和StringBuffer定义的字符串是一个变量
  • String类中的方法调用后不会改变原字符串的值,可变字符串的方法调用后,会改变原字符串的值
  • StringBuilder是非线程安全的可变字符串类,StringBuffer是线程安全的可变字符串类,其中的方法被synchronized修饰

总结

在频繁操作统一字符串是,一定要使用可变字符串StringBuilder或StringBuffer类的对象,不能使用String类的对象。

System类

这个类中包含了一些系统相关的信息和一些方法。其中的属性和方法都是静态的。

该类不能创建对象,不是因为它是一个抽象类,而是因为它的构造方法是私有的

常用属性和方法

System.out

获取系统打印的输出流PrintStream对象。用于控制台打印信息

System.in

获取输入流InputStream对象。用于获取输入信息

System.err

获取系统打印的输出流PrintStream对象。用于控制台打印异常信息

System.exit(int statues)

终止虚拟机的运行,参数0表示正常终止

System.currentTimeMillis()

获取从1970.1.1 0:0:0至今经过了多少毫秒。中国是UTC(+8)所以是从1970.1.1 8:0:0至今经过了多少毫秒。返回long类型。

System.arraycopy(原数组,原数组起始位置,目标数组,目标数组起始位置,要复制原数组的元素数量)

复制数组中的元素到新数组中

RunTime类

RunTime类的对象,表示程序运行时的对象(程序运行时的环境对象)

包含了程序运行环境相关的信息。常用于获取运行环境信息(如虚拟机内存)或执行某个命令。

特点

这个类不是一个抽象类,但不能创建对象,因为它的构造方法是私有的。

通过Runtime类的静态方法getRuntime()获取唯一的Runtime类的实例

这是java中的已有的设计模式–单例模式(一个类只能有一个创建对象)

public class Runtime {
    //定义了一个静态成员:当前类对象
    //由于静态成员只在类加载时执行一次,所以这里会创建唯一一个当前类对象
    private static Runtime currentRuntime = new Runtime();
    
    //定义了一个公共的静态方法,用于获取创建唯一的当前类对象
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    //构造方法是私有的,不能在当前类之外创建对象
    private Runtime() {}
}

使用

package day2.com.hqyj.test;

import java.io.IOException;

public class RunTimeTest {
    public static void main(String[] args) throws IOException, InterruptedException {
        //通过Runtime类的静态方法getRuntime()获取唯一的Runtime类的实例
        Runtime runtime = Runtime.getRuntime();

        System.out.println("当前虚拟机空闲内存"+runtime.freeMemory()/1024/1024+"MB");
        System.out.println("当前虚拟机实际最大内存"+runtime.totalMemory()/1024/1024+"MB");
        System.out.println("当前虚拟机支持的最大内存"+runtime.maxMemory()/1024/1024+"MB");

        //exec(String 指令名)运行某个指令,返回运行的进程对象
        //指定秒后关机
        // Process process = runtime.exec("shutdown -s -t 300");
        //取消关机任务
        // Process process = runtime.exec("shutdown -a");
        //打开画板mspaint
        Process process = runtime.exec("shutdown -a");
        //打开计算器calc
        // Process process = runtime.exec("shutdown -a");
        //打开记事本notepad
        // Process process = runtime.exec("shutdown -a");
        Thread.sleep(2000);
        //通过进程对象调用销毁功能,从而关闭
        // process.destroy();
    }
}

方法在调用时的传值问题

package day2.com.hqyj.test2;

public class Test {
    /*
    * 当方法的参数为原始类型时,方法中对该参数做修改,不会影响实际参数
    * */
    public static void fun1(int i){
        i=123;
        System.out.println(i);
    }
    /*
    * 当方法的参数为字符串时,方法中对字符串“重新赋值”,实际是创建了一个新的字符串对象,不会影响实际参数
    * */
    public static void fun2(String str){
        str = "new";
        System.out.println(str);
    }
    /*
    * 如果参数为引用类型,方法中对该参数直接操作,操作的就是实际参数的内存地址,会影响实际参数
    * */
    public static void fun3(Person p){
        p.setName("胡歌");
        System.out.println(p.getName());
    }
    /*
    *如果参数为引用类型,方法中创建了一个新对象对其赋值,操作的是创建的新对象,不会影响实际参数
    * */
    public static void fun4(Person p){
        p = new Person();
        p.setName("梅长苏");
        System.out.println(p.getName());
    }
    /*
    *如果参数为数组,也属于引用类型,方法中直接操作数组,操作的是实际参数,会影响
    * */
    public static void fun5(int[] list){
        // list = new int[11];
        list[0]=123;
        System.out.println(list[0]);
    }

    public static void main(String[] args) {
        int i = 0;
        fun1(i);//123
        System.out.println(i);

        String str = "old";
        fun2(str);
        System.out.println(str);

        Person p = new Person();
        p.setName("霍建华");
        fun3(p);
        System.out.println(p.getName());

        Person p1 = new Person();
        p1.setName("白豆腐");
        fun4(p);
        System.out.println(p1.getName());

        int list[] = {1,23,45};
        fun5(list);
        System.out.println(list[0]);
    }
}

总结

参数只有是引用类型(类、数组、接口),并且方法中在直接操作该参数时,才会对实际参数造成影响。**

fun3(Person p)参数为Person对象,方法中直接调用参数p的xxx方法,是在操作实际参数。

fun5(int[] list)参数为数组,方法中直接操作数组某个索引的对应元素,是在操作实际参数。

fun2(String str)和fun4(Person p)都在方法中创建了一个新的对象,是在操作方法中的参数,不影响实际参数。

public static void fun(char[] list,Person p){
    list[0] = 'm';//这里直接操作实际参数,会影响实参
    p = new Person();//这里创建了一个新的对象,操作的是方法中的对象,不会影响实参
    p.setName("刘莹");
}
public static void main(String[] args){
    char[] list={'a','b','c'};
    Person p = new Person();
    fun(list,p);
    System.out.println(list[0]);//m
    System.out.println(p.getName());//null
}

Date类

用于表示日期时间的类,位于java.util包下

构造方法

常用构造方法

说明

Date()

创建当前瞬间对应的日期对象

Date(long l)

创建指定瞬间对应的日期对象

Date(int year,int month,int day)

该构造方法已过时。创建指定年月日的日期对象(年是1900年起经过的年数,月用0-11表示1-12月)

常用方法

常用方法

说明

getTime()

得到对应Date对象表示的毫秒数

setTime(long l)

设置Date对象的毫秒数

after(Date when)

判断调用日期对象是否在when之后

before(Date when)

判断调用日期对象是否在when之前

SimpleDateFormat类

用于格式化日期的一个类

构造方法

常用构造方法

作用

SimpleDateFormat(String pattern)

创建一个日期模板的格式化日期对象

日期模板

特殊字符

作用

yyyy

年份

MM

月份

dd

日期

HH

小时

mm

分钟

ss


E

星期

以上两个字母都可以写成一个

M : 5,MM :05

yyyy/MM/dd HH:mm:ss E

2022/11/24 16:34:26 星期四

常用方法

常用方法

返回值

作用

format()

String

将Date对象按日期模板转换为字符串

parse()

Date

将满足日期模板的字符串转换为Date对象

package day2.com.hqyj.test3;

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

public class Test {
    public static void main(String[] args) throws ParseException {
        //输入两个日期,计算这两个日期相隔多少天
        String patten1 = "yyyy/MM/dd";
        SimpleDateFormat s1 = new SimpleDateFormat(patten1);
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个日期:(如2022/11/06");
        String input1 = sc.next();
        System.out.println("请输入第二个日期:(如2022/11/06");
        String input2 = sc.next();
        //按日期模板转换
        Date d1 = s1.parse(input1);
        Date d2 = s1.parse(input2);
        long l = d1.getTime()-d2.getTime();
        long day = Math.abs(l)/1000/3600/24;
        System.out.println(input1+"与"+input2+"相隔"+day+"天");
    }
}

Calender类

日历字段

在Calendar类中,定义了很多被final和static修饰的常量,称为日历字段,实际一个数字,用于获取指定信息。


作用

Calenser.YEAR

年份

Calendar.MONTH

月份(0-11表示1-12)

Calendar.DATE

日期

Calendar.DAY_OF_WEEK

星期(1-7表示周天到周六)

Calendar.HOUR

12小时进制

Calendar.HOUR_OF_DAY

24小时进制

Calendar.MINUTE

分钟

Calendar.SECOND


Calendar.DAY_OF_MONTH

本月第几天

Calendar.DAY_OF_YEAR

本年第几天

Calendar.WEEK_OF_MONTH

本月第几周

Calendar.WEEK_OF_YEAR

本年第几周

常用方法

常用方法

作用

get(int filed)

根据日历字段获取对应的值

getTime()

获取对应的Date对象

getMaximum(int filed)

获取指定日历字段支持的最大值,如:Calendar.DATE最大为31

getActualMaximum(int filed)

获取指定日历字段在当前日期下的实际最大值,如11月,最大30

set(int filed,int value)

将指定的日历字段设置为指定值

set(int year,int month,int date)

设置年月日

setTime(Date date)

将Date对象作为参数设置日历对象的信息

练习

  • 输入年月,输出该月所有的工作日和周末
  • 如输入2022年11月
// 输出工作日:1 2 3 4 7 8 9 10 11 14 15 16 17 18 21 22 23 24 25 28 29 30
// 输出周末:5 6 12 13 19 20 26 27
package day2.com.hqyj.test4;

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

public class Test2 {
    public static void main(String[] args) throws ParseException {
        //输入年份和月份,输出这个月的所有工作日和周末
        //如输入2022年11月
        //输出工作日:1 2 3 4 7 8 9 10 11 14 15 16 17 18 21 22 23 24 25 28 29 30
        //输出周末:5 6 12 13 19 20 26 27

        //获取一个日历对象
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入年份");
        int year = sc.nextInt();
        System.out.println("请输入年月份");
        int month = sc.nextInt();
        cal.set(Calendar.YEAR,year);
        cal.set(Calendar.MONTH,month-1);
        // cal.set(Calendar.DATE,1);

        //定义可变字符串对象
        StringBuilder weekday = new StringBuilder("周末:");
        StringBuilder workday = new StringBuilder("工作日:");
        // System.out.print("工作日:");
        //循环当月的每一天,从1到最大值
        for (int i = 1; i <= cal.getActualMaximum(Calendar.DATE); i++) {
            //将日历设为每一天
            cal.set(Calendar.DATE,i);
            //得到的日期对应的星期(本周第几天)
            int week = cal.get(Calendar.DAY_OF_WEEK);
            // System.out.println(week);
            if(week>1 && week<7){
                workday.append(i+"\t");
                // System.out.print(i+"\t");
            }else{
                weekday.append(i+"\t");
                // System.out.print(i+"\t");
            }
        }
        System.out.println(weekday);
        System.out.println(workday);

    }
}
  • 假设2022年12月1日起,开始执行"三天打鱼两天晒网"计划。输入一个新的日期,输出这天该打鱼
    还是晒网
package day2.com.hqyj.test4;

import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;

public class Test3 {
    public static void main(String[] args) throws ParseException {
        /*
        * 假设2022年12月1日起,开始执行"三天打鱼两天晒网"计划。
        * 输入一个新的日期,输出这天该打鱼还是晒网
        * */
        //创建一个日历对象
        Calendar cal = Calendar.getInstance();
        //设置起始日期
        cal.set(2022,11,1);
        //转换为Date类型,后续用于计算两个日期的时间差
        Date start = cal.getTime();

        //接收指定日期
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入年月日");
        int year = sc.nextInt();
        int month = sc.nextInt();
        int date = sc.nextInt();

        //设置指定日期
        cal.set(year,month-1,date);
        //转Date类型
        Date end = cal.getTime();
        System.out.println(start);
        System.out.println(end);
        //计算两个日期时间差
        long l = Math.abs(end.getTime()-start.getTime());
        long days = l/1000/3600/24;

        //判断
        if(days%5==4 || days%5==0){
            System.out.println(year+"年"+month+"月"+date+"日,在晒网");
        }else{
            System.out.println(year+"年"+month+"月"+date+"日,在打鱼");
        }
    }
}
  • 实现“员工入职记录”
  • 添加员工时输入姓名、性别、部门、职位,自动记录入职时间
  • 输出员工信息时,输出所有
    Employee
package day2.com.hqyj.test4;

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

/*
* 定义员工类
* 属性:姓名、性别、部门、职位、入职日期
* */
public class Employee {
    private String name;
    private String sex;
    private String dept;
    private String job;
    private String joinDate;

    public Employee(String name, String sex, String dept, String job) {
        this.name = name;
        this.sex = sex;
        this.dept = dept;
        this.job = job;
        SimpleDateFormat sdf= new SimpleDateFormat("yyyy/MM/dd");
        //创建员工对象时,只需要输入日期之外的属性,日期自动赋值
        this.joinDate = sdf.format(new Date());
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", dept='" + dept + '\'' +
                ", job='" + job + '\'' +
                ", joinDate=" + joinDate +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public String getJoinDate() {
        return joinDate;
    }

    public void setJoinDate(String joinDate) {
        this.joinDate = joinDate;
    }
}

HR

package day2.com.hqyj.test4;

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

public class HR {
    private Employee[] list;

    public HR(){
        this.list = new Employee[10];
    }

    public void inaert(Employee emp){
        for (int i = 0; i < list.length; i++) {
            if(list[i] == null){
                list[i] = emp;
                break;
            }
        }
    }

    public void showAll(){
        for (Employee employee : list) {
            if(employee != null){
                System.out.println(employee);
            }
        }
    }

    public Employee findByName(String name){
        for (int i = 0; i < list.length; i++) {
            if(list[i] !=null && list[i].getName().equals(name)){
                return list[i];
            }
        }
        return null;
    }

    public static void main(String[] args) throws ParseException, InterruptedException {
        HR hr = new HR();
        Employee emp1 = new Employee("胡歌","男","演艺部","拍戏");
        Thread.sleep(3000);
        Employee emp2 = new Employee("霍建华","男","演艺部","拍戏");
        hr.inaert(emp1);
        hr.inaert(emp2);
        hr.showAll();
        System.out.println("请输入要查找的姓名");
        Scanner sc = new Scanner(System.in);
        Employee byName = hr.findByName(sc.next());
        System.out.println(byName);
    }
}