Java-Day-16
常用类
包装类
( Wrapper )
-
针对八种基本数据类型定义相应的引用类型 —— 包装类,有了类的特点,就可以调用类中的方法
-
基本数据类型 包装类 boolean Boolean char Character byte Byte short Short int Integer long Long float Float double Double -
Byte、Integer、Long、Float、Double、Short 父类都为 Number,Number 父类为 Object
-
Boolean 和 Character 父类为 Object
-
-
包装类和基本数据类型的转换新旧方式
-
jdk5 前是手动装箱和拆箱方式
-
装箱:基本类型 —> 包装类型,反之为拆箱
int n1 = 100; // 手动装箱 int——>Integer Integer integer = new Integer(n1); Integer integer1 = Integer.valueOf(n1); // 手动拆箱 Integer——>int int n2 = integer.intValue();
-
-
jdk5 及其以后是自动装箱和拆箱方式
-
表面直接用,实则在源码仍是手动时的语句
int n3 = 200; // 自动装箱 int——>Integer Integer integer2 = n3; // 底层使用的仍是 Integer.valueOf(n2) // 自动拆箱 Integer——>int int n4 = integer2; // 底层使用的仍是 intValue()
-
-
自动装箱底层调用的是 valueOf 方法
-
其他类型类似
-
-
包装类型和 String 类型的相互转换举例
-
包装类 ( Integer ) —> String
Integer i = 100; // F1 String str1 = i + ""; // F2 (包装类都有toString方法) String str2 = i.toString(); // F3 String str3 = String.valueOf(i);
-
String —> 包装类 ( Integer )
String n1 = "123"; // F1:使用到自动装箱 Integer n2 = Integer.parseInt(n1); // F2:构造器 Integer n3 = new Integer(n1);
-
-
包装类中 Integer 类和 Character 类的常用方法
System.out.println(Integer.MIN_VALUE); // 返回最小值 System.out.println(Integer.MAX_VALUE); // 返回最大值 System.out.println(Character.isDigit('a')); // 判断是不是数字 Digit System.out.println(Character.isLetter('a')); // 判断是不是字母 Letter System.out.println(Character.isUpperCase('a')); // 判断是不是大写 Upper System.out.println(Character.isLowerCase('a')); // 判断是不是小写 Lower System.out.println(Character.isWhitespace('a')); // 判断是不是空格 System.out.println(Character.toUpperCase('a')); // 转成大写 System.out.println(Character.toLowerCase('A')); // 转成小写
-
可以在类图中点击粉色方法图标显示
-
-
练习
-
注:三元运算符是一个整体,前 int 和后 double 类型整体统一化为最大的 double 类型 ( 因为接收类型为 Object )
Object obj1 = true ? new Integer(1) : new Double(2.0); System.out.println(obj1); // 输出一 Object obj2; if (true) obj2 = new Integer(1); else obj2 = new Double(2.0); System.out.println(obj2); // 输出二
-
输出一为:1.0
输出二为:1
-
-
查看输出结果
// T1 Integer i = new Integer(1); Integer j = new Integer(1); System.out.println(i == j); // T2 Integer m = 1; Integer n = 1; System.out.println(m == n); // T3 Integer x = 128; Integer y = 128; System.out.println(x == y); // T4 Integer n1 = new Integer(128); Integer n2 = 128; System.out.println(n1 == n2); // T5 Integer n3 = 127; int n4 = 127; System.out.println(n3 == n4); // T6 Integer n5 = 128; int n6 = 128; System.out.println(n5 == n6);
- 1:判断是不是一个对象,两个都是 new 的,所以 false
- 2:底层是 Integer.valueOf(),看不出,所以要看源码得知,如果范围在 -128 ~ 127 就直接返回,若是超出范围就在源码 new Integer(i),所以是 true
- 3:超出范围,是 false
- 4:两个都是 new,所以仍为 false
- 5、6:只要有基本数据类型,判断的就是值是否相等,所以为 true
-
String 类
-
String 对象用于保存字符串,也就是一组字符序列
- 进入 String 源码,打开类图可以看到实现了Serializable、Comparable、CharSequence 三个接口
- 其中 Serializable 说明 String 可以串行化 ( 就可以在网络传输了 )
- Comparable 说明 String 对象可以相互比较
- CharSequence 字符序列
- 进入 String 源码,打开类图可以看到实现了Serializable、Comparable、CharSequence 三个接口
-
字符串常量对象是用双引号括起的字符序列
-
字符串的字符使用 Unicode 字符编码,一个字符 ( 不区分字母还是汉字 ) 占两个字节
-
String 是 final 类,不可以继承
-
源码可知:private final char value[] ——> 用于存放字符串内容,即字符串 String 本质还是 char 数组,
-
且 final 类型表示赋值后就不能再修改 ( 地址不能修改 ):即 value 不能指向新的地址,但是单个字符内容是可以变化的
final char[] value = {'a','b','c'}; value[0] = 'A'; // 不会报错 char[] v2 = {'A','B','C'}; value = v2; // 报错,不能直接整分配,不能直接指向一个新的数据空间
-
-
String 类较常用构造方法
String s1 = new String(); String s2 = new String(String original); String s3 = new String(char[] a); String s4 = new String(char[] a, int startIndex, int count);
-
创建方式 ( 在 JVM 中 )
-
直接赋值:
String s1 = "zhuyazhu"; // ( 栈中 s1 指向一个常量池地址 )
- 直接从常量池中查看是否有 "zhuyazhu" 的数据空间
- 如果有,直接同地址指向;如果没有则创建,然后指向
- 最终 s1 指向的是常量池的空间地址
-
调用构造器:
String s2 = new String("zhuyazhu"); // ( 栈中 s2 指向堆里的一个地址,堆中地址指向着常量池的 "zhuyazhu" 地址 )
- 先在堆中创建空间,里面维护了 value ( 来自源码 ) 属性,指向常量池中的 “zhuyazhu” 空间
- 如果常量池没有 "zhuyazhu" 就重新创建,有的话就直接通过 value 指向
- 最终 s2 指向的是堆中的空间地址
-
练习
String a = "abc"; // 先在常量池建 String b = "abc"; // 直接在常量池找到了 System.out.println(a.equals(b)); // equals方法比较的是串里每一个字符,是比较内容 System.out.println(a == b) // 同地址,看栈里的地址
- 输出:true true
String a = "zhuyazhu"; // 指向常量池的 String b = new String("zhuyazhu"); // 指向堆中对象 System.out.println(a.equals(b)); System.out.println(a == b); System.out.println(a == b.intern()); System.out.println(b == b.intern()); System.out.println(a == "zhuyazhu");
- intern 方法:如果池已经包含一个等于此 String 对象的字符串 ( 用 equals(Object) 方法确定 ),则返回池中的字符串的地址;否则,将此 String 对象添加到池中,并返回此 String 对象的引用 ——> 最终返回的是常量池的地址
- 1:比较的是内容
- 2:栈中地址,一个堆的,一个常量池的
- 3:b.intern:看 b 前述语句知在常量池有没有,有的话直接返回常量池地址 ( 没有就建 )
- 4:b 指向堆 ( 含有指向常量池地址为值的 value ) 地址,而 b.intern 指向的是常量池地址
- 5:"zhuyazhu" 本身就是在常量池里,== 比较的还是地址
- 输出:true false true false true
-
-
字符串特性
-
final 类,代表不可变的字符序列
-
一个字符串对象一旦被分配,其内容是不可变的
String n = "hello"; n = "hi";
- 新建了 "hello" 后,又找有没有 "hi",没有就新建,然后重新指向 "hi"
- 一共建立两个对象
String a = "hello" + "hi";
- 注意:编译器不傻,单独创建 hello 和 hi 的话又没有用的,所以会等价优化成 String a = "hellohi"
- 先右后左,一共创建了一个对象
-
重要规则:String c = "a" + "b" 是常量相加,看的是池;String c = a + b 是变量相加,是在堆中的
String a = "hello"; String b = "hi"; String c = a + b; //与上面的代码不同
-
可以 debug 看看,step into、step out 循环
//1.into,sb是new在堆中的 StringBuilder sb = new StringBuilder() //2.out、into sb.append("hello"); //3.out、into sb.append("hi"); //4.out、into String c = sb.toString() // 从 0 开始取 7 个值 String c = a + b; // 结束
-
实际上是 c 指向堆中的对象 ( String ) value[] —> 池中的 "hellohi"
-
即:a 指向 hello,b 指向 hi,c 指向堆,堆里 value 指向池中的 hellohi
String d = "hellohi"; String e = "hello" + "hi"; System.out.println(d == e); // true,都是常量池
-
-
注意 intern() 返回的是地址
String n = "zhu"; String m = "ya"; String s1 = "zhuya"; String s2 = (n + m).intern(); System.out.println(s1 == s2);
- s1 和 s2 都指向池中的 "zhuya",true
-
学会画 JVM 图分析
public class test1 { public static void main(String[] args) { Test ex = new Test(); // new堆中一个对象,内含的str指向同在堆中的value(new String的), // 内含的数组对象char也指向堆存”java“数组处(默认放堆里) ex.change(ex.str,ex.ch); // 调用方法就产生新栈,此栈中str也指向堆中的value,ch也指向堆中的存”java“数组处 System.out.print(ex.str + " and "); // 方法调用完成,临时的方法栈销毁了,ex.str还是通过堆中对象、指向堆中value的那个, // 指向常量池里的”zhu“,并不是已销毁的临时栈指向的”java“,所以为”zhuand“ System.out.println(ex.ch); // zava } } class Test { String str = new String("zhu"); // 堆中 final char[] ch = {'j','a','v','a'}; public void change(String str, char ch[]) { str = "java"; // 堆中value指向常量池”java“地址(×)str是final的,此处是栈新开辟的方法栈里的str断value线,重新指向常量池的”java“ ch[0] = 'z'; // 把堆中数组的j换成z,{'z','a','v','a'} } }
- 输出:zhu and zava
-
-
String 类的常见方法
- String 每次更新都要重新开辟新空间,效率低
- equals:区分大小写,判断内容是否相等
- equalslgnoreCase:忽略大小写,判断内容是否相等
- length:获取字符个数,字符串长度
- indexOf:获取字符 / 字符串 在字符串中第一次出现的索引,索引从零开始,如果找不到就返回负一
- lastIndexOf:获取字符 / 字符串在字符串中最后一次出现的索引,索引从零开始,如果找不到就返回负一
- substring:截取指定范围的子串,左闭右开 [ )
- substring(6):从索引 6 开始截取后面的所以内容
- substring(0, 5):从索引 0 开始截取到第 5 个字符,即 5 - 1 = 4 位
- trim:去先后空格
- charAt:获取某索引处的字符,注意不能使用 str[index] 这种数组的方式
- 转大写 ( toUpperCase )、转小写 ( toLowerCase )、拼接 ( concat )、字符串全替换 ( replace,但不会影响本身,要接收返回的结果 )、分割字符串 ( split,考虑转义,数组接收 )、比较两个字符串大小 ( 长度同比较的是对应的不同的字符编码值前减后的差,长度不同比较的是长度差 )、字符串转换成数组 ( toCharArray )、格式字符串 ( format,%s、%d、%.2f、%c 占位符 )
StringBuffer 类
-
java.lang.StringBuffer 代表可变的字符序列,可以对字符串内容进行增删
-
很多方法与 String 相同,但 StringBuffer 是可变长度的
-
StringBuffer 是一个容器
- StringBuffer 的直接父类是 AbstractStringBuilder
- StringBuffer 实现了 Serializable,即 StringBuffer 的对象可以串行化
- 即对象可以实现网络传输,也可以保存到文件
- 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final ( 存放于堆而非常量池 ),该 value 数组存放字符串的内容
- StringBuffer 是一个 final 类,不能被继承
-
String VS StringBuffer
- String 保存的是字符串常量,里面的值不能修改,每次 String 类的更新实际上就是更改地址,效率较低
- private final char value[]; // 堆中 value 指向常量池
- StringBuffer 保存的是字符串常量,里面的值可以更改,每次 StringBuffer 的更新实际上可以更新内容,不用每次更新地址,效率较高
- char value[]; // 堆中 value 指向堆中数组值
- String 保存的是字符串常量,里面的值不能修改,每次 String 类的更新实际上就是更改地址,效率较低
-
StringBuffer 构造器
-
StringBuffer():构造一个其中不带字符的字符串缓冲池,其初始容量为 16 个字符
StringBuffer f1 = new StringBuffer();
-
StringBuffer(CharSecuence seq):构造一个字符串缓冲区,它包含与指定的 CgarSequence 相同的字符
-
StringBuffer(int capacity):
StringBuffer f2 = new StringBuffer(50);
-
StringBuffer(String str):通过一个 String 来创建,char[] 大小就是 str.length() + 16
StringBuffer f3 = new StringBuffer("hi"); // 长18
-
-
String 与 StringBuffer
-
String 转 StringBuffer
-
F1:使用构造器,对 str 本身没有影响
String str = "hello"; StringBuffer strb1 = new StringBuffer(str);
-
F2:使用 append 方法,改变
StringBuffer strb2 = new StringBuffer(); strb2.append(str); // StringBuffer strb3 = strb2.append(str);
-
-
StringBuffer 转 String
-
F1:使用 StringBuffer 提供的 toString 方法
StringBuffer strb = new StringBuffer("HELLO"); String str1 = strb.toString();
-
F2:使用构造器方式
StringBuffer strb = new StringBuffer("HELLO"); String str2 = new String(strb);
-
-
-
StringBuffer 常用方法 ( 皆从下标零开始,方法使用不仅限于下面示例 )
-
增 ( 追加 ) append
- append.(xxx).append.(yyy);
-
删 ( 删除 ) delete
- delete(1, 3):删除 >= 1,< 3 的字符 [1, 3)
-
改 ( 替换 ) replace
- replace(3, 5, "daung"):把 [3, 5) 的字符更改为 " duang "
-
查 ( int ) indexOf
- indexOf("xx"):查找 xx 所在序列下标
-
插 ( 指定 ) insert
- insert(2, "dada"):在第二个位置处插入 dada
-
返回长度 length
-
-
练习
-
查看输出
// 1. String str = null; StringBuffer strb = new StringBuffer(); strb.append(str); System.out.println(strb); // 2. StringBuffer strb2 = new StringBuffer(str); System.out.println(strb2);
- 1:调用 append() 时,看源码得知,底层调用的是父类 AbstractStringBuilder 的 appendNull() 方法,返回的是 null 字符串
- 2:直接用构造器方法,源码可知,是先看长度,所以,此方法会报错空指针异常
-
输入某物品价格,把价格小数点前面的数字每三位加一个逗号
-
例:1235.52 ——> 1,235.52
String str = "12121235.52"; StringBuffer strb1 = new StringBuffer(str); // int i = strb1.lastIndexOf("."); // strb1.insert(i - 3, ","); // for (int i = strb1.lastIndexOf("."); i > 0; i -= 3) { // strb1 = strb1.insert(i - 3, ","); // } // 小数点前面的数不能整减3时,报错: insert里的 i - 3 有可能先减到负数 // (for里的i-3是为了换位置,inert里的是为了插入逗号) for (int i = strb1.lastIndexOf(".") - 3; i > 0; i -= 3) { strb1 = strb1.insert(i, ","); } // 所以改善为先找到位置,再insert,再i-3循环 System.out.println(strb1);
-
-
StringBuilder 类
-
简介
-
一个可变的字符序列,此类提供一个与 StringBuffer 兼容的 API,但不保证同类 ( StringBuilder 不是线程安全,存在多线程问题 )。
-
该类被设计用作 StringBuffer 的一个简易替换
- 同 StringBuffer 一样的接口 ( ... 对象可以串行化 ) 和父类 ( AbstractStringBuilder )
-
用在字符串缓冲区被单个线程使用的时候 ( 即单线程时优先考虑此类 ),大多数实现中要比 StringBuffer 要快。
-
StringBuilder 的所有方法都没有做互斥处理,即都没 synchronized ( 同步,线程时细讲 ) 关键字,因此推荐单线程情况下使用 StringBuilder,如果是多线程的话会有风险
-
StringBuffer 才是用在多线程
-
-
在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据
-
final 类,不能被继承
-
对象字符序列仍然是存放在其父类
- AbstractStringBuilder 的 char[] value,存放堆中
-
-
String、StringBuffer、StringBuilder 比较
-
String:不可变字符序列,效率低,但是复用率高
- 在常量池里的存放地址可以不限量被指向
-
StringBuffer:可变字符序列,效率较高 ( 尤其是增删 ),线程安全
-
StringBuilder :可变字符序列,效率最高,线程不安全 ( 如幻读脏读 ... )
-
如果对 String 做大量修改 ( 如循环多次的更改、拼接 ),不要使用 String
-
而是多线程的时候用 StringBuffer ( 安全 )
-
单线程的话考虑 StringBuilder ( 最快 )
-
字符串修改很少,被多个对象引用时使用 String,比如配置信息等
-
-
效率:StringBuilder > StringBuffer > String
- 可以在自设循环,开头和结尾都 System.currentTimeMillis() 获取时间,最后计算执行时间
-
Math 类
-
常用方法 Math.xxx
-
abs(n):取 n 的绝对值
-
pow(n, m):求幂,n 的 m 次方
-
ceil(n):向上取整,返回大于等于 n 的最小整数
-
floor(n):向下取整,返回小于等于 n 的最大整数
-
round(n):四舍五入,可看成:n + 0.5 化
-
sqrt(n):对 n 开平方 ( n 是负数的话输出就是 NaN:表示非数值 )
-
random():随机返回 [ 0, 1 ) 范围内的小数
-
求返回一个 [ 2, 7 ] 范围内的整数
-
2 <= x <= 7 ( 取整要加 (int) )
-
设为取 [a, b]
-
范围:a <= x <= (a + ( b - a ))
-
x 取值代码化:(a + Math.random() * ( b - a ))
-
化右 [a, b) 为 [a, b+1) — 为了取整:
(a + Math.random() * ( b - a + 1 ))
-
取整,区间化开为闭 [a, b]:
(int)(a + Math.random() * ( b - a + 1 ))
-
因此得出获取 [a, b] 随机整数公式
-
-
即 [2, 7] 取整就是:
(int)(2 + Math.random() * 6)
=> (int)( 2 + [0, 6) )
=> (int)[2, 8)
=> [2, 7]
-
-
Math.min(n, m):返回 n 和 m 里的最小值
-
Math.max(n, m):返回 n 和 m 里的最大值
-
Arrays 类
-
一系列用于管理或操作数组的静态方法
-
toString:返回数组的字符串形式
- Arrays.toString(数组名)
- 输出样式:[-1, 5, 9]
-
sort:数组排序,引用类型会影响到实参
-
Arrays.sort(数组名); 默认正序排序
-
自定制:Arrays.sort(数组名, new Comparator() {} );
接口编程 + 动态绑定 + 匿名内部类
// 定制——倒序integer数组 Arrays.sort(integer, new Comparator() { @Override public int compare(Object o1, Object o2) { Integer i1 = (Integer) o1; Integer i2 = (Integer) o2; return i2 - i1; } }); // 用到匿名内部类,要求实现 compare 接口(源码最终到 TimSort 类的 binarySort 方法,动态绑定返回匿名内部类的计算差值),若是返回正数就是正序了
- 推演:( 把核心的判断条件换成了接口,这样就可以自定义判断逻辑,从而决定排序规则了 —— 本来的排序就是比大小 )
public class test1 { public static void main(String[] args) { int[] arr = {1, -1, 8, 0, 20}; // bubble(arr); bubble1(arr, new Comparator() { @Override public int compare(Object o1, Object o2) { int i1 = (Integer) o1; int i2 = (Integer) o2; return i2 - i1; } }); System.out.println(Arrays.toString(arr)); } // 冒泡排序 public static void bubble(int[] arr) { int temp = 0; 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]){ temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } // 冒泡 + 定制排序 public static void bubble1(int[] arr, Comparator c) { int temp = 0; for (int i = 0; i < arr.length - 1; i++){ for (int j = 0; j < arr.length - i - 1; j++){ // 数组排序由 c.compare(arr[j], arr[j + 1])返回值决定 if (c.compare(arr[j], arr[j + 1]) > 0){ temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } }
-
-
binarySearch:通过二分搜索法进行查找,要求必须排好序
- 要求是排好序的数组,例如在 arr 中查找 n 所在的下标:
- int index = Arrays.binarySearch(arr, n);
- 数组中不存在该元素就返回:- ( 应该存在的位置下标 + 1 )
-
copyOf:数组元素的复制
-
从 arr 数组中拷贝 length 个元素到 newArr 数组中
Integer[] newArr = Arrays.copyOf(arr, length);
-
如果拷贝长度 > arr.length 就在新数组的后面加 null ( int 数组的话加 0 )
-
-
fill:数组元素的填充
-
fill(num, n):把 num 中的所有数值都换成 n
Integer[] num = new Integer[]{9, 2, 3, 8}; Arrays.fill(num, 99);
-
-
equals:比较两个数组元素内容是否完全一致
-
两个数组的元素、顺序等都得一样
boolean equals = Arrays.equals(arr, arr2);
-
-
asList:将一组值转换成list
-
转换成一个 List 集合
List<Integer> asList = Arrays.asList(1, 2, 3, 4, 5); System.out.println(asList); // [1, 2, 3, 4, 5]
-
-
-
练习
-
已给图书,根据图书的价格排序
Arrays.sort(books, new Comparator() { public int compare(Object o1, Object o2) { Book book1 = (book) o1; Book book2 = (book) o2; double priceVal = book2.getPrice() - book1.getPrice(); // 强转的话损失精度,有可能差别小的价格强转后返回了零 if(priceVal > 0){ return -1; } else if(priceVal < 0){ return 1; } else { return 0; } } });
-
System 类
- 常见方法
- exit:退出程序
- System.exit(0):0 表示正常状态退出
- arraycopy:复制数组元素,比较适合底层调用
- 一般还是用 Arrays.copyOf 完成复制数组
- System.arraycopy( 原数组,从原数组的哪个索引位置开始拷贝,拷贝到的目标数组,原数组的数据拷贝到目标数组的哪个位置,要拷贝多少个数据到目标数组 ),索引都是从零开始
- currentTimeMillis:返回当前时间距离 1970-1-1 的毫秒数
- gc:运行垃圾回收机制
- exit:退出程序
BigInteger 和 BigDecimal 类
-
BigInteger 适合保存比较大的整型
// 整数最大的 long long l = 2222222222222222222; // 报错:number too large BigInteger bigInteger = new BigInteger("2222222222222222222"); System.out.println(bigInteger); // 先化成字符串存,但输出的话仍是整数形式
-
要想使用算术运算,就要将两个数都要为 BigInteger,用 BigInteger 的方法
BigInteger bigInteger = new BigInteger("2222222222222222222"); BigInteger bigInteger2 = new BigInteger("222");
-
加法:add
BigInteger add = bigInteger.add(bigInteger2);
-
减法:subtract
BigInteger subtract = bigInteger.subtract(bigInteger2);
-
乘法:multiply
BigInteger multiply = bigInteger.multiply(bigInteger2);
-
除法:divide
BigInteger divide = bigInteger.divide(bigInteger2);
-
-
BigDecimal 适合保存精度更高的浮点型 ( 小数 )
// 小数最大的double double d = 20.31415926141592604159; // 只保留小数点后15位 BigDecimal bigDecimal = new BigDecimal("20.31415926141592604159");
-
进行计算的话仍旧要将操作数与被操作数化为 BigDecimal 类型,使用其方法
-
加、减、乘都同上
-
但除法可能会抛出 ArithmeticException 异常,结果产生了非有限的小数
System.out.println(bigDecimal.divide(bigDecimal1, BigDecimal.ROUND_CEILING));
- 添加 BigDecimal.ROUND_CEILING 的话,就可以保留除数已有的小数位数,即 bigDecimal 多少位小数,结果就保留多少位小数
-
日期类
-
第一代日期类
-
Date:精确到毫秒,代表特定的瞬间
- 接口:Serializable ( 可序列化 ),Cloneable ( 克隆 ),Comparable ( 可比较 )
-
SimpleDateFormat:格式和解析日期的类
-
允许进行格式化 ( 日期 —> 文本 ) 和规范化 ( 文本 —> 日期 )
-
常见模式字母
字母 元素 示例 y 年 1996;96 M 年中月份 July;07 w 年中周数 27 D 年中天数 190 d 月中天数 10 H 一天中小时 ( 0 - 23 ) 0 h 半天中的小时 ( 1 - 12 ) 1 m 小时中的分钟数 30 s 分钟中的秒数 50 E 星期中天数 Tuesday;Tue;星期二
-
-
代码编写
// 获取当前系统时间:date, Date date = new Date(); // 但输出的话默认国外格式 // 自设格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E"); String format = sdf.format(date); System.out.println(format); // format 输出即为自设格式后的当前时间 // 通过输入的毫秒数得到过了此毫秒后的时间 Date date2 = new Date(9234567); System.out.println(date2); // date2就是1970年过了9234567毫秒后的时间 // 把一个格式化后的 String 转回对应的 Date 默认格式 String s = "2023年04月26日 05:31:50 星期三"; Date parse = sdf.parse(s); System.out.println(parse); // 但要根据要求于所在方法 throws ParseException 抛出异常 // 想指定格式还是要format转换,前提是自设 sdf 的格式必须符合字符串 s 的格式一致,否则会抛出转换异常
-
-
第二代日期类:主要就是 Calendar 类 ( 日历 )
-
public abstract class Calendar extends Object implements Serializable, Cloneable, Comparable< Calendar >
-
Calendar 类是一个抽象类,并且构造器是 private,可以通过 getInstance() 来获取实例,提供了大量方法和字段
- 即获取实例无法 new,要用 Calendar.getInstance() 获取
- 字段里存放了年月日等等信息
Calendar c = Calendar.getInstance(); System.out.println("年:" + c.get(Calendar.YEAR)); // 月份要加一,因为返回月的时候是按照零开始编号的,加括号,否则就是字符串拼接了 System.out.println("月:" + (c.get(Calendar.MONTH) + 1)); System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH)); System.out.println("小时:" + c.get(Calendar.HOUR_OF_DAY)); System.out.println("分钟:" + c.get(Calendar.MINUTE)); System.out.println("秒:" + c.get(Calendar.SECOND));
- 此类没有提供对应的格式化的类,因此需要程序员自己组合来输出 ( 灵活显示 )
-
-
第三代日期类
-
前两代不足之处
- JDK 1.0 中包含了一个 java.util.Date 类,但是它的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用了。而且 Calendar 也存在问题:
- 可变性:像日期和时间这样的类应该是不可变的
- 偏移性:Date 中的年份是从 1900 开始的,而月份都从 0 开始
- 格式化:格式化只对 Date 有用,Calendar 则只能 get 获取
- 不是线程安全的,不能处理闰秒等 ( 每隔两天,多出一秒 ) 问题
- JDK 1.0 中包含了一个 java.util.Date 类,但是它的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用了。而且 Calendar 也存在问题:
-
第三代日期类常见方法
-
LocalDate:只包含日期 ( 年月日 )
-
LocalTime:时间 ( 时分秒 )
-
LocalDateTime:日期 + 时间 ( 年月日时分秒 )
// 使用 now() 返回表示当前日期的对象 // LocalDate.now(),LocalTime.now() LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); System.out.println(ldt.getYear()); System.out.println(ldt.getMonth()); // 英文显示 System.out.println(ldt.getMonthValue()); // 数字 // ...... 要会查方法
-
plusDays:增加天数后的日期
// 20 天后的日期获取 LocalDateTime localdatetime2 = ldt.plusDays(20);
-
minusMinutes:某某分钟前的日期是多少
// 660 分钟前的日期获取 LocalDateTime localdatetime3 = ldt.minusMinutes(660); // 可以用下面的格式化再输出查验
-
等等 JDK 8 后的 API 帮助文档查看方法
-
-
DateTimeFormatter 格式日期类
LocalDateTime ldt =LocalDateTime.now(); DateTimeFormatter datetimeformatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒"); String format = datetimeformatter.format(ldt); System.out.println(format);
-
Instant 时间戳
-
类似于 Date,提供了一系列和 Date 类转换的方式
// 通过静态方法 now() 获取表示当前时间戳的对象 Instant now = Instant.now(); System.out.println(now);
-
Instant ——> Date
// 通过 form 把 Instant 转换成 Date Date date = Date.from(now); System.out.println(date);
-
Date ——> Instant
// 通过 date 的 toInstant() 把 date 转换成 Instant Instant instant = date.toInstant(); System.out.println(instant);
-
-
练习
-
将字符串中指定的部分进行反转
-
如:“123456” 反转成 “154326”
public class test1 { public static void main(String[] args) throws ParseException { String str = "123456"; try { str = method(str, 6, 4); } catch (Exception e) { System.out.println(e.getMessage()); return; } System.out.println(str); } public static String method(String str, int start, int end) { // 重要编程技巧思想 之 对范围限定判断 // 写出正确情况 // 然后反转正确情况 (因为正确情况易找,但错误情况难找全) if (!(str != null && start >= 0 && end > start && end < str.length())) { throw new RuntimeException("所填参数不正确"); } char[] chars = str.toCharArray(); char temp = ' '; for (int n = start, m = end; n < m; n++, m--) { temp = chars[n]; chars[n] = chars[m]; chars[m] = temp; } // return chars.toString(); return new String(chars); } }
- 取反正确情况即为所有的错误情况
-
-
判断设计,要求输入用户名大于 2 位,小于 4 位,密码六位且都为数字,邮箱有 @ 和 . 并且 @ 在前 . 在后
public class test1 { public static void main(String[] args) throws ParseException { try { userRegister("2424", "242424", "24@.com"); System.out.println("输入格式都正确~"); } catch (Exception e) { System.out.println(e.getMessage()); } } public static void userRegister(String name, String pwd, String email) { int length = name.length(); if (!(length >= 2 && length <=4)) { throw new RuntimeException("用户名格式不正确~"); } if (!(pwd.length() == 6 && isDigital(pwd))) { throw new RuntimeException("输入密码格式不正确~"); } int n1 = email.indexOf('@'); int n2 = email.indexOf('.'); if (!(n1 > 0 && n2 > n1)){ throw new RuntimeException("邮箱格式不正确~"); } } public static boolean isDigital(String pwd) { char[] chars = pwd.toCharArray(); for (int i = 0; i < chars.length; i++) { if (chars[i] < '0' || chars[i] > '9'){ return false; } } return true; } }
-
完成输出格式要求的字符串
-
例如:输入人名字符串 “Zhu Ya Zhuwa”,以 "Zhuwa,Zhu .Y" 形式输出
public class test1 { public static void main(String[] args) throws ParseException { String name = "Zhu Ya Zhuwa"; printName(name); } public static void printName(String str){ if (str == null) { System.out.println("str 不能为空"); return; } String[] names = str.split(" "); if (names.length != 3){ System.out.println("名称输入不正确,对不起,我们只转化三位的名称"); return; } String format = String.format("%s,%s .%c",names[2], names[0], names[1].toUpperCase().charAt(0)); System.out.println(format); } }
-
-
true false 判断
class Animal { String name; public Animal(String name) { this.name = name; } } //main 中 String s1 = "zhu"; Animal a = new Animal(s1); Animal b = new Animal(s1); System.out.println(a == b); // 1 System.out.println(a.equals(b)); // 2 System.out.println(a.name == b.name); // 3 String s2 = new String("zhu"); String s3 = "zhu"; System.out.println(s1 == s2); // 4 System.out.println(s1 == s3); // 5 System.out.println(s2 == s3); // 6 String s4 = "hello" + s1; String s5 = "hellozhu"; System.out.println(s4.intern() == s5); // 7
- a、b 非一个对象 —— F
- 注意 Animal 类并没有重写 equals 方法,所以底层还是看地址:return (this == obj); —— F
- 地址指向相同 —— T
- new 的是在堆中存放于 value 数组里的,指向的就是堆中地址,另一个是直接指向常量池 —— F
- 都是直接指向常量池地址 —— T
- 同 4 —— F
- 拼接时有变量就是也指向一个堆,但 intern 是直接指向常量池地址 —— T