常用类-day02
今日学习内容:
- String、StringBuilder、StringBuffer
- Math类
- Random类
- UUID类
- Date类
- SimpleDateFormat类
- Calendar类
- 正则表达式
今日学习目标:
- 熟悉查看API,熟悉方法调用
- 掌握StringBuilder的操作
- 掌握String、StringBuilder、StringBuffer三者的区别
- 掌握日期的转换操作(格式化和解析)
- 了解日历类获取年月日和增加天数操作
- 掌握Math类常用方法,随机数的生成和UUID的使用
- 了解正则表达式
1.4 String(掌握)
字符串(字符序列),表示把多个字符按照一定得顺序连成的字符序列。
字符串的分类(根据同一个对象,内容能不能改变而区分):
- 不可变的字符串——String:当String对象创建完毕之后,该对象的内容是不能改变的,一旦内容改变就变成了一个新的对象。
- 可变的字符串——StringBuilder/StringBuffer:当StringBuilder对象创建完毕之后,对象的内容可以发生改变,当内容发生改变的时候,对象保持不变。
1.4.1 String 本质概述(了解)
String 类型表示字符串,Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
String 在内存中是以字符数组的形式存在
// jdk1.8 and before
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
我们可以认为,String对字符数组的封装,并提供以只读的形式操作其封装的字符数组的方法。
String对象的创建的两种方式:
1、直接赋一个字面量: String str1 = "ABCD";//直接存储在方法区的常量池中,节约内存
2、通过构造器创建: String str2 = new String("ABCD");
字符串内存图
通过字面量创建的字符串分配在常量池中,所以字面量字符串是常量;它们的值在创建之后不能更改,因为 String 对象是不可变的,所以可以共享。
通过new 操作创建的字符串分配在堆区。
String类,表示不可变的字符串,当String对象创建完毕之后,该对象的内容是不能改变的,一旦内容改变就变成了一个新的对象,看下面代码。
String str = "龙哥";
str = str + "hello";
String对象的 "空" 值
表示引用为空(null)
String str1 = null; //没有初始化,没有分配内存空间.
内容为空字符串
String str2 = ""; // 已经初始化,分配内存空间,不过没有内容
1.4.3 字符串常用方法(掌握)
"ABCD" ['A','B','C,'D']
- int length() 返回此字符串的字符个数
- char charAt(int index) 返回指定索引位置的字符
- int indexOf(String str) 返回指定字符串在此字符串中从左向右第一次出现处的索引位置
- boolean equals(Object anObject) 比较内容是否相同
- boolean equalsIgnoreCase(String anotherString) 忽略虑大小写,比较内容是否相同
- String toUpperCase() 把当前字符串转换为大写
- String toLowerCase() 把当前字符串转换为小写
- String substring(int beginIndex):从指定位置开始截取字符串
- String substring(int beginIndex, int endIndex):截取指定区域的字符串
- boolean endWith(String suffix)
- boolean startWith(String prefix)
- replace(char oldChar, char newChar)
需求:判断字符串非空:字符串不为null并且字符内容不能为空字符串(“”)
判断一个字符串非空:
public static boolean hasLength(String str) {
return str != null && ! "".equals(str.trim());
}
总结:
【1】通过这些方法,你发现了什么?
1.4.4 字符串陷阱(了解)
思考一下问题:
"A" + "B" 在内存中创建了几个字符串?
"A" + "B" + "C" 呢?
实际开发过程中,一定要规避以下代码
String tmp = "";
for(int i=0;i<5;i++){
tmp += "hello";
}
以上代码存在什么问题?
1.1 StringBuffer和StringBuilder类(掌握)
1.1.1 可变字符串概述(了解)
String类型提供了对字符串的只读操作,也即调用字符串的部分方法都会返回一个新的字符串。
如果需要对包装的字符数组进行增、删、改、查时,就需要可变字符串。
java中提供了两类可变字符串的类型StringBuffer、StringBuilder。
1.1.2 StringBuffer(掌握)
StringBuffer封装了一个字符数组,并提供了对该字符数组进行增、删、改、查的方法。所以,我们完全可以把StringBuffer看成一个"字符的容器"!
可变字符串内存图
StringBuffer构造方法
- StringBuffer() : 初始化默认容量是16的可变字符串
- StringBuffer(int capacity) 初始化容量是capacity的可变字符串
StringBuffer常用方法
- append / insert / delete
- setCharAt / replace
public static void main(String[] args) {
// 创建一个可变字符串容器,默认容量是16个字符
StringBuffer sb = new StringBuffer();
// 创建一个可变字符串容器,容量是100个字符
// StringBuffer sb2 = new StringBuffer(100);
// 【1】追加
sb.append('A');
sb.append('B');
// 链式操作
sb.append("C").append("D");
System.out.println(sb.toString());
// 【2】添加 insert
sb.insert(0, 'E');
sb.insert(0, "hello").insert(0, "world");
System.out.println(sb);
// 返回容器的容量
System.out.println(sb.capacity());
// 返回容器中字符的个数
System.out.println(sb.length());
// 当空间不足时,能否继续添加?=> 自动拓容
sb.append(123);
System.out.println(sb.length());
System.out.println(sb.capacity());
// 【2】删除
// 删除指定位置index的字符
//sb.deleteCharAt(10);
// delete(start,end) 含头不含尾
sb.delete(0, 10);
System.out.println(sb);
// 【3】修改
sb.replace(0, 5, "eabcd");
System.out.println(sb);
sb.setCharAt(0, 'f');
System.out.println(sb);
}
总结 :
【1】 通过对可变字符串的API,你发现了什么?
【2】什么是链式操作?
1.1.4 StringBuilder(掌握)
StringBuffer在源代码级别上已经做到了线程安全,所以StringBuffer非常适合多线程环境。 如果在单线程条件下使用可变字符串序列时,一定优先考虑StringBuilder。
面试题: StringBuffer和StringBuilder的区别(了解+)
相同点:都是字符串可变缓冲区,api提供了相同的增删改查操作。 不同点: StringBuffer 线程安全,效率低;StringBuilder线程不安全,效率高。 StringBuffer jdk1.0; StringBuilder jdk1.5
1.2. Math(掌握)
Math 类包含用于执行简单的数学运算的方法,如随机数、最大值最小值、指数等,该类的方法都是static修饰的,在开发中其实运用并不是很多,里面有一个求随机数的方法,偶尔会用到。
Math类位于java.lang包中。
public static void main(String[] args) {
// [1]ceil/floor
float a = 9.2f;
// 比9.2大的最小整数:向上取整
System.out.println(Math.ceil(a));
// 比9.2小的最大整数:向下取整
System.out.println(Math.floor(a));
// [2]求最值
System.out.println(Math.max(10, 9));
System.out.println(Math.min(10, 9));
// [3]随机数 取值返回[0,1)
System.out.println(Math.random());
// 返回[m,n]区间的随机整数
// (int)(Math.random()*(n-m+1)) + m;
}
1.3. Random(掌握)
Random类用于生产一个伪随机数(通过相同的种子,产生的随机数是相同的),Math类的random方法底层使用的就是Random类的方式。
Random位于java.util包中。
常用方法
- nextInt(int n) : 产生范围在[0,n)的随机数
public static void main(String[] args) {
// 1> Random
Random r = new Random();
// val的范围[0,100)之间
int val = r.nextInt(100);
System.out.println(val);
}
需求:随机产生4位的小写英文字母的验证码
/**
* 分析:
* [1]. 产生一个a-z的随机字符c => 'a' + [0,25]
* [2]. 把产生的随机字符存入数组? 还是可变字符串?
*/
public static void main(String[] args) {
StringBuilder codes = new StringBuilder(4);
char c;
Random rand = new Random();
for(int i = 0;i < codes.capacity();i++){
// [0,25]
c = (char)('a' + rand.nextInt(26));
codes.append(c);
}
System.out.println("codes = " + codes);
}
1.4. UUID (掌握)
UUID表示通用唯一标识符 (Universally Unique Identifier) ,其算法通过电脑的网卡、当地时间、随机数等组合而成,优点是真实的唯一性,缺点是字符串太长了。
UUID位于java.util包中,jdk1.5 才出现的类
常用方法
- randomUUID() : 产生一个随机的唯一标识符,格式:678f9568-8967-4637-a48e-f0eae30faf43
public static void main(String[] args) {
// 获取UUID对象
UUID uuid = UUID.randomUUID();
String str = uuid.toString();
System.out.println("str = " + str);
// 获取UUID中的前5个字母作为验证码
String code = uuid.substring(0, 5);
System.out.println(code);
}
提示:
在java中不通过new构建一个对象的静态方法就称为静态工厂方法,类似地,Integer.valueOf()
1.5. 日期时间
1.5.1 日期时间概述
问题1:计算机如何表示时间?
因为日期时间是变化的,计算机不直接存储具体时间。
时间戳(time stamp) :具体时间(特定的瞬间)距离历元(1970年01月01日 00:00:00:000) 经过的毫秒数,用long类型存储。
计算机很容易存储long类型数据,所以计算机通过时间戳存储并表示时间。
问题2:为什么时间戳一样,时间却不同?
中国时间和国外时间的时间戳都一样,但时区不同。时区导致时间不同。
计算机以格林尼治所在地的标准时间作为时间统一协调时,这个时间在民间称为格林尼治时间(GMT),为了统一国际用法,也称世界协调时(UTC)
问题3:如何计算当地时间?
- 当地时间 = UTC + 时区偏移
- 中国位于东八区,时区偏移为(+8:00)
- 中国时间 = UTC + 8:00
- 日本时间 = UTC + 9:00
1.5.2 Date(掌握)
Date 位于java.util包中,表示特定的瞬间,内部包装了一个long类型的fastTime,通过运算可以把fastTime转换成年月日时分秒。
常用方法
- Date()
- getTime()
public class Test01 {
public static void main(String[] args) {
// 根据系统当前时区,当前日期时间构建一个Date对象
Date now = new Date();
// Wed Aug 11 10:52:20 CST(chinese standard time) 2021
System.out.println(now.toString());
// 获取date对象的时间戳
long ts = now.getTime();
System.out.println(ts);
}
}
15.2.1 SimpleDateFormat(掌握)
打印Date对象时,默认打印的是欧美人的日期时间风格,如果需要输出自定义的时间格式,比如2020年12月12日 12:12:12格式或者2020-12-12 12:12:12,此时可以使用SimpleDateFormat类。
SimpleDateFormat类,顾名思义是日期的格式化类,主要包括两个功能的方法:
- 格式化(format):Date类型转换为String类型:String format(Date date)
- 解析(parse):String类型转换为Date类型:Date parse(String source)
无论是格式化还是解析都需要设置日期时间的模式,所谓模式就是一种格式。
日期模式举例:
yyyy-MM-dd 如2020-12-12
HH:mm:ss 如20:12:12
yyyy-MM-dd HH:mm:ss 如2020-12-12 20:12:12
yyyy/MM/dd HH:mm:ss 如2020/12/12 20:12:12
yyyy年MM月dd日 HH时mm分ss秒 如2020年12月12日 20时12分12秒
格式化和解析代码如下:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatDemo {
public static void main(String[] args) throws ParseException {
Date date = new Date();
// 创建SimpleDateFormat对象
SimpleDateFormat df = new SimpleDateFormat();
String pattern = "yyyy-MM-dd HH:mm:ss";
// 设置日期时间转换模式
df.applyPattern(pattern);
// 格式化(format):Date类型转换为String类型:String format(Date date)
String dateStr = df.format(date);
System.out.println(dateStr);
// 解析(parse):String类型转换为Date类型:Date parse(String source)
Date date2 = df.parse(dateStr);
System.out.println(date2.toString());
}
}
1.6.Calendar(掌握)
Calendar 日历类,其内部封装了一个long time 表示时间戳,其内部提供了方法通过对time计算出年月日时分秒...等日历字段,这些字段都被存储到一个数组中,通过get(字段)可以去数组中提取对于字段的值。
Calendar本身是一个抽象类,通过getInstance方法获取对象,其底层创建的是Calendar的子类对象。
Calendar还提供了用来对日期做相加减,重新设置日期时间功能。
public class CalendarDemo1 {
public static void main(String[] args) throws Exception {
// 根据当前地区,当前语言环境,当前时间构造一个通用的日历对象
Calendar cal = Calendar.getInstance();
System.out.println(cal);
// 获取日历字段信息
// 获取日历中的年月日
System.out.println(cal.get(Calendar.YEAR));
// 月从0开始,0表示1月,1表示2月...
System.out.println(cal.get(Calendar.MONTH));
System.out.println(cal.get(Calendar.DATE));
// System.out.println(cal.get(Calendar.DAY_OF_MONTH));
System.out.println(cal.get(Calendar.HOUR));
System.out.println(cal.get(Calendar.MINUTE));
System.out.println(cal.get(Calendar.SECOND));
// 获取星期(周几)
// 一周的第一天是周日
System.out.println(cal.get(Calendar.DAY_OF_WEEK));
// 增加日历字段对于的值
cal.add(Calendar.YEAR, 100);//在当前年份上增加100
System.out.println(c.get(Calendar.YEAR));//2118
}
}
需求1:查询某个时间最近一周的信息,如何表示最近这一周的开始时间和结束时间
假如给出时间为:2018-05-18 15:05:30,那么最近一周的开始和结束时间分别为:
开始时间:2018-05-12 00:00:00
结束时间:2018-05-18 23:59:59
public class CalendarDemo2 {
public static void main(String[] args) throws Exception {
// [1] 通过字符串解析出时间对象
String input = "2018-05-18 15:05:30";// 输入时间
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern(pattern);
Date d = sdf.parse(input);
// [2] 调整日历时间
Calendar c = Calendar.getInstance();
c.setTime(d);// 把当前输入时间转换为Calendar对象
// [3] 计算结束时间
c.set(Calendar.HOUR_OF_DAY, 23);
c.set(Calendar.MINUTE, 59);
c.set(Calendar.SECOND, 59);
Date endDate = c.getTime();
System.out.println(endDate.toLocaleString());
// [4] 计算开始时间
c.add(Calendar.SECOND, 1);// 秒数增加1
c.add(Calendar.DAY_OF_MONTH, -7);// 天数减去7
Date beginDate = c.getTime();
System.out.println(beginDate.toLocaleString());
}
}
1.7. 正则表达式(了解)
正则表达式,简写为regex和RE/Re。
正则表达式用来判断某一个字符串是不是符合某一种规则,在开发中通常用于判断检测操作、替换操作、分割操作等。
19.1. 正则表达式规则
正则表达式匹配规则一:元字符 ( 正则表达式中已定义好的字符,这些字符有特定的含义 )
正则表达式匹配规则二:量词
19.2. 正则表达式练习
判断一个字符串是否全部有数字组成
判断一个字符串是否是手机号码
判断一个字符串是否是18位身份证号码
判断一个字符串是否6到16位,且第一个字必须为字母
public class REDemo {
public static void main(String[] args) throws Exception {
// 判断一个字符串是否全部有数字组成
System.out.println("12345678S".matches("\d"));// false
System.out.println("12345678".matches("\d"));// false
System.out.println("12345678".matches("\d*"));// true
System.out.println("1234".matches("\d{5,10}"));// false
System.out.println("12345678".matches("\d{5,10}"));// true
// 判断一个字符串是否是手机号码
String regex1 = "^1[3|4|5|7|8][0-9]{9}$";
System.out.println("12712345678".matches(regex1));// false
System.out.println("13712345678".matches(regex1));// true
// 判断一个字符串是否是18位身份证号码
String regex2 = "\d{17}[[0-9]X]";
System.out.println("511123200110101234".matches(regex2));// true
System.out.println("51112320011010123X".matches(regex2));// true
System.out.println("51112320011010123S".matches(regex2));// false
// 判断一个字符串是否6到16位,且第一个字必须为字母
String regex3 = "^[a-zA-Z]\w{5,15}$";
System.out.println("will".matches(regex3));// false
System.out.println("17will".matches(regex3));// false
System.out.println("will17willwillwill".matches(regex3));// false
System.out.println("will17".matches(regex3));// true
}
}
\