可变字符串
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);
}
}