JAVA高级–常用类
观看b站尚硅谷视频做的笔记
1、字符串相关的类
1.1 String 的使用
String 的特性:
String 类:代表字符串。Java 程序中的所有字符串字面值(如 “abc”)都作为此类的实例实现。
String 是一个 final 类,代表不可变的字符序列且不可以被继承。字符串是常量,用双引号引起来表示。他们的值在创建之后不可更改。
String 对象的字符内容是储存在一个字符数组 value[] 中.
凡是实现compare接口的对象\和类都可以比较大小
1.2 理解 String 的不可变性
String: 字符串,使用一对“ ”引起来表示。
1.String 声明为 final 的,不可被继承。
2.String 实现了 Serializable、 Comparable接口。
实现了 Serializable接口:表示字符串是支持序列化。 接口的作用是:io流会说,凡是实现接口的类都可以进行序列化(可以通过网络、或者本地流进行数据传输)
实现了Comparable 接口:表示 String 可以比较大小。接口相当于定义了规范,定义了相关功能。
3.String 内部定义了 final char[] value 用于存储字符串数据。表示数组不可被赋值,数组元素也不可被赋值。
4.String: 代表不可变的字符序列。简称:不可变性。体现:1)当对字符串重新赋值时,需要重新指定内存区域赋值, 不能使用原有的 value 进行赋值。 2)当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的 value 进行赋值。 3) 当调用 String 的 replace() 方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的 value进行赋值。
5. 通过字面量的方式(区别于 new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6. 字符串常量池中是不会存储相同内容的字符串的。
7. 例
package com.zhou.java;
public class StringTest {
public static void main(String[] args) {
String s1="abc";//字面量定义的方式
String s2="abc";
s1="hello";
System.out.println(s1==s2);//比较s1和s2的地址值
System.out.println(s1);
System.out.println(s2);
String s3="abc";
s3+="def";
System.out.println(s3);
String s4="abc";
String s5=s4.replace("a","m");
System.out.println(s4);
System.out.println(s5);
}
}
1.3 String 不同实例化方式的对比
1)String 对象的创建
给字符串赋值,本质就是给char型数组赋值,char型数组长度是0
2)String str1="abc"与String str2=new String(“abc”)的区别?
字符串常量存储在字符常量池中,目的是共享
字符串非常量对象存储在堆中
3)String 的实例化方式
方式一:通过字面量定义的方式
方式二:通过 new + 构造器的方式
例:
package com.zhou.java;
public class StrigTest02 {
public static void main(String[] args) {
//通过字面量定义的方式,此时的s1和s2的数据javaEE声明在方法区的字符串常量池中
String s1="javaEE";
String s2="javaEE";
//通过new+构造器的方式,此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后的地址值
String s3=new String("javaEE");
String s4=new String("javaEE");
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s1==s4);
System.out.println(s3==s4);
Person person1 = new Person("Tom",12);
Person person2 = new Person("Tom",12);
System.out.println(person1.name.equals(person2.name));
System.out.println(person1.name== person2.name);
person1.name="Jerry";
System.out.println(person2.name);
}
}
class Person {
String name ;
int age;
public Person(String name, int age) {
this.age=age;
this.name=name;
}
}
1.4 String 不同拼接操作的对比
结论:
1)常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2)只要其中有一个是变量,结果就在堆中。
3)如果拼接的结果调用 intern() 方法,返回值就在常量池中。
4)使用陷阱:
A.String s1 = “a”;说明:在字符串常量池中创建了一个字面量为 “a” 的字符串。
B、s1 = s1 + “b”;说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串 s1+“b”(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。
C、String s2 = “ab”;说明:直接在字符串常量池中创建一个字面量为 “ab” 的字符串。
D、String s3 = “a” + “b”;说明:s3 指向字符串常量池中已经创建的 “ab” 的字符串。
5、String s4 = s1.intern();说明:堆空间的 s1 对象在调用 intern() 之后,会将常量池中已经存在的 “ab” 字符串赋值给 s4
5)例
package com.zhou.java;
public class StringTest04 {
public static void main(String[] args) {
String s1="javaEE";
String s2="hello";
String s3="javaEEhello";
String s4="javaEE"+"hello";
String s5=s1+"hello";
String s6="javaEE"+s2;
String s7=s1+s2;
System.out.println(s3==s4);//true
System.out.println(s3==s5);//faulse
System.out.println(s3==s6);//faulse
System.out.println(s3==s7);//faulse
System.out.println(s5==s6);//true
System.out.println(s5==s7);//true
System.out.println(s6==s7);//true
String s8=s5.intern(); 返回值得到的 s8 使用的常量值中已经存在
System.out.println(s3==s8);//true
}
}
1.5 JVM 中涉及字符串的内存结构
1.7 String 的常用方法
int length():返回字符串的长度:return value.length
char charAt(intindex):返回某索引处的字符 return value[index] 。
boolean isEmpty():判断是否是空字符returnvalue.length==0
String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写。
String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写。
String trim():返回字符串的副本,忽略前导空白和尾部空白。
boolean equals(Object obj):比较字符串的内容是否相同。
boolean equals IgnoreCase(StringanotherString):与 equals 方法类似,忽略大小写。
String concat(Stringstr):将指定字符串连接到此字符串的结尾。等价于用“+”。
int compareTo(String anotherString):比较两个字符串的大小。
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从 beginIndex 开始截取到最后的一个子字符串。
String substring(int beginIndex,intendIndex):返回一个新字符串,它是此字符串从 beginIndex 开始截取到 endIndex( 不包含 ) 的一个子字符串。
boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束。
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始。
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。
int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引。
int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。注:indexOf 和 lastIndexOf 方法如果未找到都是返回 -1。
package com.zhou.java;
public class StringMethodTest {
public static void main(String[] args) {
String s1="helloWorld";
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.charAt(9));
// System.out.println(s1.charAt(10));
System.out.println(s1.isEmpty());
String s2=s1.toLowerCase();
System.out.println(s1);
System.out.println(s2);
String s3=" he llo world ";
String s4=s3.trim();
System.out.println("-----"+s3+"-----");
System.out.println("----"+s4+"-----");
}
}
package com.zhou.java;
public class StringTest02 {
public static void main(String[] args) {
String s1="helloWorld";
String s2="helloworld";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));
String s3="abc";
String s4= s3.concat("def");
System.out.println(s4);
String s5="abc";
String s6= new String("abe");
System.out.println(s5.compareTo(s6));
}
}
package com.zhou.java;
public class StringTest04 {
public static void main(String[] args) {
String s1="helloworld";
boolean ld = s1.endsWith("ld");
System.out.println(ld);
boolean b = s1.startsWith("he");
System.out.println(b);
boolean b1 = s1.startsWith("l",2);
System.out.println(b1);
String s2="wor";
System.out.println(s1.contains(s2));
System.out.println(s1.indexOf("lo"));
System.out.println(s1.indexOf("lo",5));
String s3="hellorworld";
System.out.println( s1.lastIndexOf("d"));
System.out.println(s3.lastIndexOf("or",5));
}
}
1.8 String 与基本数据类型包装类的转换
String --> 基本数据类型、包装类:调用包装类的静态方法parseXxx(str)
基本数据类型、包装类 --> String,调用 String 重载的 valueOf(xxx)
```java
```java
package com.zhou.java;
public class StringChangeTest {
public static void main(String[] args) {
String str1="123";
//int num= (int) str1;//错误,强转类型是父子关系才有强转
int i = Integer.parseInt(str1);
String s1 = String.valueOf(i);
//或者
String s2 = i+" ";//存储的数据在堆中
System.out.println(s1==s2);
}
}
1.9 String 与字符数组 char[] 之间的转换
String --> char[]: 调用 String 的 toCharArray()
char[] --> String: 调用 String 的构造器
package com.zhou.java;
public class StringCharTest {
public static void main(String[] args) {
String str1="abc123";//题目:a21cb3
char[] chars = str1.toCharArray();
for (int i = 0; i <chars.length ; i++) {
System.out.println(chars[i]);
}
char[] chars1 = {'h', 'e', 'l', 'l', 'o'};
String s = new String(chars1);
System.out.println(chars1);
}
}
1.10 String 与字节数组 byte[] 之间的转换
编码:String --> byte[]: 调用 String 的 getBytes()
解码:byte[] --> String: 调用 String 的构造器
编码:字符串 --> 字节 ( 看得懂 —> 看不懂的二进制数据 )
解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 —> 看得懂)
说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。
package com.zhou.java;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringByteTest {
public static void main(String[] args) throws UnsupportedEncodingException {
//使用默认的字符编码集,进行转换
String s1="abc中国";
byte[] bytes = s1.getBytes();
System.out.println(Arrays.toString(bytes));
//使用gbk字符集进行编码
byte[] gbks = s1.getBytes("gbk");
System.out.println(Arrays.toString(gbks));
//使用默认的字符编码集,进行解码
String s = new String(bytes);
System.out.println(s);
//使用gbk字符集进行解码
String s2 = new String(gbks);//出现乱码。原因:编码集和解码集不一致!
System.out.println(s2);
String s3 = new String(gbks,"gbk");// 没有出现乱码。原因:编码集和解码集一致!
System.out.println(s3);
}
}
1.11 StringBuffer 和 StringBuilder 的介绍
1)String、StringBuffer、StringBuilder 三者的异同?
String:不可变的字符序列;底层使用 char[] 存储
StringBuffer:可变的字符序列;线程安全的,效率低;底层使用 char[]存储
StringBuilder:可变的字符序列;jdk5.0 新增的,线程不安全的,效率高;底层使用 char[] 存储。
2)StringBuffer 的源码分析:
关于 StringBuffer 和 StringBuilder 的使用:
String str = new String(); //char[] value = new char[0];
String str1 = new String(“abc”);
//char[] value = new char[]{‘a’,‘b’,‘c’};
StringBuffer sb1 = new StringBuffer();
//char[] value = new char[16]; 底层创建了一个长度是 16 的数组。
System.out.println(sb1.length());
sb1.append(‘a’); //value[0] = ‘a’;
sb1.append(‘b’); //value[1] = ‘b’;
StringBuffer sb2 = new StringBuffer(“abc”);
//char[] value = new char[“abc”.length() + 16];
// 问题 1. System.out.println(sb2.length()); // 3
// 问题 2. 扩容问题 : 如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组.
默认情况下,扩容为原来容量的 2 倍 + 2,同时将原有数组中的元素复制到新的数组中。
意义:开发中建议大家使用:StringBuffer(int capacity) 或
StringBuilder(int capacity)
1.12StringBuffer 中的常用方法
StringBuffer append(xxx):提供了很多的 append() 方法,用于进行字符串拼接。
StringBuffer delete(int start,int end):删除指定位置的内容。
StringBuffer replace(int start,int end,String str):把[start,end)位置替换为 str
StringBuffer insert(int offset, xxx):在指定位置插入 xxx。
StringBuffer reverse() :把当前字符序列逆转。
public int indexOf(String str)。
public String substring(int start,int end): 返回一个从 start 开始到 end 索引结束的左闭右开区间的子字符串
public int length()。
public char charAt(int n )。
public void setCharAt(int n ,char ch)。
总结:
增:append(xxx)
删:delete(int start,int end)
改:setCharAt(int n ,char ch) / replace(int start, int end, String str)
查:charAt(int n )
插:insert(int offset, xxx)
长度:length();
遍历:for() + charAt() / toString()
package com.zhou.java;
public class StringBufferBuilderMethodTest {
public static void main(String[] args) {
StringBuffer s1= new StringBuffer("abc");
s1.append(1);
s1.append("1");
System.out.println(s1);
s1.replace(2,4,"hello");
System.out.println(s1);
s1.delete(2,4);
System.out.println(s1);
s1.insert(2,true);
System.out.println(s1);
System.out.println(s1.length());
s1.reverse();
System.out.println(s1);
String s2=s1.substring(1,3);
System.out.println(s2);
}
}
1.13String、StringBuffer、 StringBuilder 效率对比
对比 String、StringBuffer、StringBuilder 三者的效率:
从高到低排列:StringBuilder > StringBuffer > String
package com.zhou.java;
public class StringBufferBuilderTestEffict {
public static void main(String[] args) {
long startTime = 0L;
long endTime = 0L;
String text = "";
StringBuffer buffer = new StringBuffer("");
StringBuilder builder = new StringBuilder("");
// 开始对比
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer 的执行时间:" + (endTime
- startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder 的执行时间:" + (endTime
- startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String 的 执 行 时 间:" + (endTime -
startTime));
}
}
2、JDK 8 之前的日期时间 API
2.1System 类中获取时间戳的方法
System 类 提 供 的 public static long currentTimeMillis()
用来返回当前时间与 1970 年 1 月 1 日 0 时 0 分 0 秒之间
以毫秒为单位的时间差。
此方法适于计算时间差。
计算世界时间的主要标准有:
UTC(Coordinated Universal Time)
GMT(Greenwich Mean Time)
CST(Central Standard Time)
package com.zhou.java;
public class DateTimeTest {
public static void main(String[] args) {
long l = System.currentTimeMillis(); 返回当前时间与 1970 年 1 月 1 日 0 时 0 分 0 秒之间以毫秒为单位的时间差。
// 称为时间戳
System.out.println(l);
}
}
2.2Java 中两个 Date 类的使用
1)java.util.Date 类(父类) —> 表示特定的瞬间,精确到毫秒 。java.sql.Date 类(子类)
2)两个构造器的使用
构造器1:Date(),创建一个对应当前时间的Date对象
构造器2:创建指定毫秒数的Date对象
3)两个方法的使用
toString()显示当前的年月日时分秒
getTime()获取当前Date对象对应的毫秒数(时间戳)
如何将java.sql.Date 对象转换为java.util.Date 对象,直接赋值,多态
Date date4 = new java.sql.Date(2343243242323L);子类赋给父类,属于多态
java.sql.Date date5 = (java.sql.Date) date4;//强转,以前面向对象能做
package com.zhou.java;
import java.util.Date;
public class DateTest {
public static void main(String[] args) {
// 构造器1:创建一个对应当前时间的Date对象
Date date = new Date();
System.out.println(date.toString());
System.out.println(date.getTime());
// 构造器1:创建一个指定毫秒数的Date对象
Date date1 = new Date(16790581000L);
System.out.println(date1.toString());
//创建java.sql.Date对象
java.sql.Date date2 = new java.sql.Date(1679058100000L);
System.out.println(date2);
//如何将java.util.sql转换为java.sql.Date对象
// 情况1
Date date3 = new java.sql.Date(1679058100000L);
java.sql.Date date4=(java.sql.Date) date3;
//情况2:
Date date5= new Date();
//此处不能这么写java.sql.Date date6= (java.sql.Date)date5;编译不报错,
// 运行报错Exception in thread "main" java.lang.ClassCastException: java.util.Date cannot be cast to java.sql.Date
// 原因:因为new person()硬转成student,因为new 的是person(),怎么转成student
// 以前讲的强转是new的是student赋给person,再往下转,肯定没问题
java.sql.Date date7= new java.sql.Date(date5.getTime());
}
}
2.3SimpleDateFormat 的使用
Date 类的 API 不易于国际化,大部分被废弃了,java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
它允许进行
格式化:日期—> 文本
解析:文本—> 日期
jdk 8 之前的日期时间的 API 测试:
1)System 类中 currentTimeMillis();
2)java.util.Date 和字类 java.sql.Date;
3)SimpleDateFormat;
4)Calendar。
SimpleDateFormat 的使用:SimpleDateFormat 对日期 Date 类的格式化和解析
两个操作
1.1 格式化:日期 —》字符串
1.2 解析:格式化的逆过程,字符串 —》日期
SimpleDateFormat 的实例化
package com.zhou.java;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatTest{
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat();
// 实例化 SimpleDateFormat
//格式化:日期--字符串
Date date = new Date();
System.out.println(date);
String format = sdf.format(date);
System.out.println(format);
//解析:格式化的逆过程,字符串--日期
String str="23-3-20 上午8:38";
Date parse = sdf.parse(str);
System.out.println(parse);
//************* 按照指定的方式格式化和解析:调用带参的构造
// 器 *****************
//格式化
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy.MMMMM.dd GGG hh:mm aaa");
String format1 = sdf1.format(date);
System.out.println(format1);
//解析:要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现)
//否则抛异常
Date parse1 = sdf1.parse("2023.三月.20 公元 09:37 上午");
System.out.println(parse1);
}
}
2.4Calendar 日历类的使用
Calendar 是一个抽象基类,主要用于完成日期字段之间相互操作的功能。Calendar 是一个抽象类,不可以直接new(不可以实列化),就需要用到他的子类去造对象,
子类是 GregorianCalendar。
获取 Calendar 实例的方法:
使用 Calendar.getInstance() 方法。
调用它的子类 GregorianCalendar 的构造器。
一个 Calendar 的实例是系统时间的抽象表示,通过 get(intfield) 方法来取得
想要的时间信息。比如 YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_
DAY 、MINUTE、SECOND。
public void set(intfield,intvalue);
public void add(intfield,intamount);
public final Date getTime();
public final void setTime(Date date)。
注意 :
获取月份时:一月是 0,二月是 1,以此类推,12 月是 11。
获取星期时:周日是 1,周一是2,。。。。周六是 7。
方式二:调用其静态方法 getInstance() Calendar calendar = Calendar.getInstance();这里肯定不是calendar的构造器,抽象类
对象也只能是子类的对象,返回的类型是Calendar,看不到是哪个子类
System.out.println(calendar.getClass());看到对象是哪个类造的,还是//class java.util.GregorianCalendar他造的
package com.zhou.java;
import java.util.Calendar;
import java.util.Date;
public class CalendarTest {
public static void main(String[] args) {
// 1. 实例化
// 方式一:创建其子类(GregorianCalendar)的对象
// 方式二:调用其静态方法 getInstance()
Calendar calendar = Calendar.getInstance();//调用其静态方法 getInstance()
// Calendar calendar = Calendar.getInstance();这里肯定不是calendar的构造器,抽象类
//对象也只能是子类的对象,返回的类型是Calendar,看不到是哪个子类
System.out.println(calendar.getClass());//看对象是哪个类造的,还是//class java.util.GregorianCalendar造的
//2.常用方法
//get
int i = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(i);
int i1 = calendar.get(Calendar.DAY_OF_WEEK);
System.out.println(i1);
//set
//calendar 可变性
calendar.set(Calendar.DAY_OF_MONTH,22);// set方法是一个void,
// 相当于是将calendar本身信息修改了
i= calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(i);
//add
calendar.add(Calendar.DAY_OF_MONTH,-6);
i= calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(i);
//getTime():日历类--Date对象
Date time = calendar.getTime();// calendar.getTime();返回的是Date
System.out.println(time);
//setTime():Date--日历类
Date date = new Date();
calendar.setTime(date);
i= calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(i);
}
}
3、 JDK8 中日期时间 API 的介绍
新日期时间 API 出现的背景:如果我们可以跟别人说:“我们在 1502643933071 见面,别晚了!”
那么就再简单不过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。JDK 1.0 中包含了一个 java.util.Date 类,但是它的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用了。而 Calendar 并不比 Date 好多少。
它们面临的问题是:
可变性:像日期和时间这样的类应该是不可变的。(在calendar.set(Calendar.DAY_OF_MONTH, 22);
set方法是一个void,相当于是将calendar本身信息修改了改变了)
偏移性:Date 中的年份是从 1900 开始的,而月份都从 0 开始。
```java
package com.zhou.java;
import java.util.Date;
public class JDK8DateTimeTest {
public static void main(String[] args) {
Date date = new Date(2023,3,21);
System.out.println(date);
Date date1 = new Date(2023 - 1900, 3 - 1, 21);
System.out.println(date1);
}
}
格式化:格式化只对 Date 有用,Calendar 则不行。??
此外,它们也不是线程安全的;不能处理闰秒等。
第三次引入的 API 是成功的,并且 Java 8 中引入的 java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的
API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简
化了日期时间和本地化的管理。
java.time- 包含值对象的基础包:java.time.chrono- 提供对不同的日历系统的访问 java.time.format- 格式
化和解析时间和日期 java.time.temporal- 包括底层框架和扩展特性 java.time.zone- 包含时区支持的类.
说明:大多数开发者只会用到基础包和 format 包,也可能会用到temporal 包。因此,尽管有 68 个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
3.1 LocalDate、LocalTime、 LocalDateTime 的使用
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601 日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息.
LocalDate 代表 IOS 格式(yyyy-MM-dd)的日期 , 可以存储生日、纪念日等日期。
LocalTime 表示一个时间,而不是日期。
LocalDateTime 是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601 日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
LocalDateTime相对于LocalDate、LocalTime使用频率高一些,类似于Calendar
使用
如何实例化?
方式一:now(): 获取当前的日期、时间、日期 + 时间
方式二:of():设置指定的年、月、日、时、分、秒。没有偏移量
package com.zhou.java;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class LocalDateTimeTest {
public static void main(String[] args) {
// 如何实例化?
// 方式一:
LocalDateTime now = LocalDateTime.now();
LocalTime now1 = LocalTime.now();
LocalDate now2 = LocalDate.now();
System.out.println(now);
System.out.println(now1);
System.out.println(now2);
//方式二
LocalDateTime localDateTime = LocalDateTime.of(2023,3,21,16,27,53);
System.out.println(localDateTime);
}
}
相关方法
// getXxx():获取相关的属性
// withXxx(): 设置相关的属性。 也体现了不可变性
package com.zhou.java;
import java.time.LocalDateTime;
public class LocalDateTimeTest {
public static void main(String[] args) {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getMonth());
System.out.println(localDateTime.getMonthValue());
LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(22);
System.out.println(localDateTime);
System.out.println(localDateTime1);
LocalDateTime localDateTime2 = localDateTime.withHour(4);
System.out.println(localDateTime);
System.out.println(localDateTime2);
}
}
3.2 Instant 类的使用
Instant:时间线上的一个瞬时点。这可能被用来记录应用程序中的事件时间戳。
在处理时间和日期的时候,我们通常会想到年 , 月 , 日 , 时 , 分 , 秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在 UNIX 中,这个数从 1970 年开始,以秒为的单位;同样的,
在 Java 中,也是从 1970 年开始,但以毫秒为单位。
j
ava.time 包通过值类型 Instant 提供机器视图,不提供处理人类意义上的时间单位。Instant 表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC)开始的秒数。因为 java.time 包是基于纳秒计算的,所以 Instant 的精度可以达到纳秒级。类似于java.util.Date类
获取Instant的实例
如何实例化
// now(): 获取本初子午线对应的标准时间
// ofEpochMilli(): 通 过 给 定 的 毫 秒 数, 获 取 Instant 实 例 -->Date(long millis)
package com.zhou.java;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
public class InstantTest {
public static void main(String[] args) {
// now(): 获取本初子午线对应的标准时间
Instant instant = Instant.now();
System.out.println(instant);
// 添加时间的偏移量
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));//东八区
System.out.println(offsetDateTime);
// toEpochMilli(): 获取自 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC)开始的毫秒数 ---> Date 类的 getTime()
long l = instant.toEpochMilli();
System.out.println(l);
// ofEpochMilli(): 通 过 给 定 的 毫 秒 数, 获 取 Instant 实 例-->Date(long millis)
Instant instant1 = Instant.ofEpochMilli(1679390851177L);
System.out.println(instant1);
}
}
3.3 DateTimeFormatter 的使用
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
DateTimeFormatter :格式化或解析日期、时间,类似于SimleDateFormat
如何实例化:三种方式。
方式一:预定义的标准格式。
TemporalAccessor parse = formatter.parse(“2020-05-
10T18:26:40.234”);//以接口方式呈现
方式二:本地化相关的格式。如:ofLocalizedDateTime()
// FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.
SHORT : 适用于 LocalDateTime
方式三:自定义的格式。如:ofPattern(“yyyy-MMdd hh:mm:ss”)
package com.zhou.java;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
public class DateTimeFormatterTest {
public static void main(String[] args) {
//方式一:预定义的标准格式。
// 如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化:日期--字符串
LocalDateTime now = LocalDateTime.now();
String format = isoLocalDateTime.format(now);
System.out.println(now);
System.out.println(format);
//解析:字符串-日期
TemporalAccessor parse = isoLocalDateTime.parse("2023-03-21T17:38:56.607");
System.out.println(parse);
//方式二本地化相关的格式。如:ofLocalizedDateTime()
// FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于 LocalDateTime
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
String format1 = dateTimeFormatter.format(now );
System.out.println(format1);
//方式三自定义格式::ofPattern(“yyyy-MMdd hh:mm:ss”)
DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String format2 = dateTimeFormatter1.format(LocalDateTime.now());
System.out.println(format2);
TemporalAccessor parse1 = dateTimeFormatter1.parse("2023-03-22 08:32:12");
System.out.println(parse1);
}
}
3.4 其它日期时间相关 API 的使用
ZoneId:该类中包含了所有的时区信息,一个时区的 ID,如 Europe/Paris。
ZonedDateTime:一个在 ISO-8601 日历系统时区的日期时间,
如 2007-12-03T10:15:30+01:00Europe/Paris。
其中每个时区都对应着 ID,地区 ID 都为“{ 区域 }/{ 城市 }”的格式,
例如:Asia/Shanghai 等
4、Java 比较器
Java 中的对象,正常情况下,只能进行比较:==或 != 。不能使用 >
或 < 的,但是在开发场景中,我们需要对多个对象进行排序,言外之意,就
需要比较对象的大小。 如何实现?使用两个接口中的任何一个:Comparable
或 Comparator。
4.1Java 实现对象排序的方式有两种:
1)自然排序:java.lang.Comparable
2) 定制排序:java.util.Comparator
比较大小
运算符:
比较运算符(关系运算符):== ,!= > < >= <= instanceof 使用在基本数据类型上没问题
== ,!= 使用于引用数据类型上可以的
对普通的java对象也可以比较大小
Comparable、 Comparator定义了一种规范:比较大小的一种规范。
重写 compareTo(obj) 的规则:equals讲过,equals自己重写过,后来开发中自己都不会自己写,会自动生成
equals自己重写意义:比较两个对象大小跟equals像,所以重写equals
比较对象大小也是用属性去比较的,equals也是属性相比较
4.1 Comparable 自然排序举例
Comparable 接口的使用举例:自然排序
1)像 String、包装类等实现了 Comparable 接口,重写了 compareTo(obj) 方法,给出了比较两个对象大小的方式。
2)String、包装类重写 compareTo() 方法以后,进行了从小到大的排列。
3)重写 compareTo(obj) 的规则:
如果当前对象 this 大于形参对象 obj,则返回正整数,
如果当前对象 this 小于形参对象 obj,则返回负整数,
如果当前对象 this 等于形参对象 obj,则返回零。
4)对应自定义类来说,如果需要排序,我们可以让自定义类实现Comparable
接口,重写 compareTo(obj) 方法。在 compareTo(obj) 方法中指明如何排序。
String实现了Comparable接口,String就实现了 Comparable接口的功能
String[] arr = new String[] { “AA”, “CC”, “KK”, “MM”, “GG”,
“JJ”, “DD” };
Arrays.sort(arr);//String型的数组也是作为Object类型数组的子类
String型是为Object类的子类 这里也是属于多态的形式
4.2 自定义类实现 Comparable 自然排序
对商品对象进行排序
商品对象创建的是数组Goods[] arr = new Goods[5];
Arrays.sort(arr); 对象能放进去,调方法的参数为Object类 编译没报错,运行报错类型转换异常
public class Goods implements Comparable {实现接口,自然而然就需要重写compareTo方法
Goods goods = (Goods) o;强转
当前对象和形参对象就是两个对象了
(o instanceof Goods)这是针对一个商品的时候
实现接口,自然而然就需要重写compareTo方法,与equals像,判断equals时,是好几个属性一起参与,此处按照价格比
万一这个类两个对象价格一样,又得考虑谁上谁下了
再按照产品名称从低到高排序
return this.name.compareTo(goods.name);
return -this.name.compareTo(goods.name);再按照产品名称从高到低排序
package com.zhou.java;
import java.util.Arrays;
public class CompableTest01 {
public static void main(String[] args) {
Goods[] arr = new Goods[5];
arr[0] = new Goods("lenovoMouse", 34);
arr[1] = new Goods("dellMouse", 43);
arr[2] = new Goods("xiaomiMouse", 12);
arr[3] = new Goods("huaweiMouse", 65);
arr[4] = new Goods("microsoftMouse", 43);
Arrays.sort(arr);//商品对象创建的是数组Goods[] arr = new Goods[5];对象能放进去,
// 调方法的参数为Object类 编译没报错,运行报错类型转换异常ClassCastException
System.out.println(arr);
System.out.println(Arrays.toString(arr));
}
static class Goods implements Comparable {
private String name;
private double price;
public Goods(){
}
public Goods(String name,double price){
this.name=name;
this.price=price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
//指明商品比较大小的的方式,按照价格从低到高排序,再按照产品名称从高到低排序
@Override
public int compareTo(Object o) {
if(o instanceof Goods){
Goods goods=(Goods) o;
//方式一:
if(this.price>goods.price){
return 1;
}else if(this.price<goods.price){
return -1;
}else {
// return 0;
return -this.name.compareTo(goods.name);
}
}
// return 0;
throw new RuntimeException("传入的数据类型不一致");
}
}
}
4.3 使用 Comparator 实现定制排序
Comparable 接口与 Comparator 的使用的对比:Comparable 接口的方式一旦一定,保证 Comparable 接口实现类的对象在任何位置都可以比较大小。Comparator 接口属于临时性的比较。
Comparator 接口的使用:定制排序
- 背景:
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现java.lang.Comparable 接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序
重写 compare(Object o1,Object o2) 方法,比较 o1 和 o2 的大小:
如果方法返回正整数,则表示 o1 大于 o2;如果返回 0,表示相等;返
回负整数,表示 o1 小于 o2。
Comparator 是接口,里面就会有抽象方法
Arrays.sort(arr, new Comparator()后面再传一个参数,接口,创建一个接口实现类的对象,实现类就只用一次(匿名)
静态方法也不能重写
o1, o2字符串
package com.zhou.java;
import java.util.Arrays;
import java.util.Comparator;
public class CompatorTest {
public static void main(String[] args) {
String[] arr= new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
Arrays.sort(arr, new Comparator(){
// 按照字符串从大到小的顺序排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String &&o2 instanceof String){
String s1= (String) o1;
String s2= (String) o2;
return -s1.compareTo(s2);
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
}
}
package com.zhou.java;
import java.util.Arrays;
import java.util.Comparator;
public class CompartorTest01 {
public static void main(String[] args) {
Goods[] arr = new Goods[6];
arr[0] = new Goods("lenovoMouse", 34);
arr[0] = new Goods("lenovoMouse", 34);
arr[1] = new Goods("dellMouse", 43);
arr[2] = new Goods("xiaomiMouse", 12);
arr[3] = new Goods("huaweiMouse", 65);
arr[4] = new Goods("huaweiMouse", 224);
arr[5] = new Goods("microsoftMouse", 43);
Arrays.sort(arr, new Comparator(){
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Goods && o2 instanceof Goods){
Goods s1=(Goods)o1;
Goods s2=(Goods)o2;
if(s1.getName().equals(s2.getName())){
return Double.compare(s1.getPrice(),s2.getPrice());
}else {
return s1.getName().compareTo(s2.getName());
}
}
throw new RuntimeException("输入的数据不一致");
}
});
System.out.println(Arrays.toString(arr));
}
static class Goods{
private int price;
private String name;
public Goods() {
}
public Goods(String name,int price) {
this.price = price;
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Goods{" +
"price=" + price +
", name='" + name + '\'' +
'}';
}
}
}
5、System 类、Math 类、 BigInteger 与 BigDecimal
都是 static 的,所以也可以很
方便的进行调用。直接通过类就可以调用
Math 类,用不着造对象,直接调方法完成这个事儿就行,
int四个字节
4*8=32位
6、面试题
6.1 String
1)String 的一道面试题(字符串的值传递问题)
package com.exer.java;
public class StringExer {
String str=new String("good");//内存中此地方也有1处变量
char[] ch={'t','e','s','t'};//数组,把地址赋给新的变量char ch[],指向堆中同一个数据
public void change(String str,char ch[]){//2处,str两个变量。1处变量,2处变量,第一处变量的地址给第二处的变量地址,第二处的地址也指向第一处的地址,后面str指定了新的内容( str="test ok";)String的不可变性,依旧是good
基本数据类型传的是存储的数据,引用数据类型传的是地址值
str="test ok";
ch[0]='b';//数组,把地址赋给新的变量char ch[],指向堆中同一个数据,通过此地址改成了b,数组不是不可变,,相当于将同一地址中以前数据t改成了b,即为best
}
public static void main(String[] args) {
StringExer stringExer = new StringExer();
stringExer.change(stringExer.str,stringExer.ch);
System.out.println(stringExer.str);
System.out.println(stringExer.ch);
}
}
2)面试中 String 算法考察
a.模拟一个trim方法,去除字符串两端的空格
package com.exer.java;
public class StringMathTrimTest {
//核心:先将 String 型的 变量 转换为字符数组, 通过遍历的手段,
public static void main(String[] args) {
String s1=" hello world ";
//s1="0000 ";
String s=myTrim(s1);
System.out.println("输出11是"+s1.trim()+"结果");
System.out.println("输出"+s+"结果");
}
public static String myTrim(String str) {
if (str == " ") {
return str;
}
char[] chars = str.toCharArray();
int startIndex = 0;
int endIndex = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] != ' ') {
startIndex = i;
break;
}
}
for (int i=chars.length-1 ; i>=0 ; i--) {
if (chars[i]!=' ') {
endIndex=i;
break;
}
}
return str.substring(startIndex, endIndex + 1);
}
}
b.将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为”abfedcg”
方式一:转换为char[]
package com.zhou.java;
public class StringReverseTest {
public static void main(String[] args) {
String str="abcdefg";
String reverse=myReverse(str,2,5);
System.out.println(reverse);
}
public static String myReverse(String str, int startIndex, int endIndex) {
if (str!=null) {
char[] chars = str.toCharArray();
for (int x=startIndex,y=endIndex ;x<y ; x++,y--) {
char temp=chars[x];
chars[x]=chars[y];
chars[y]=temp;
}
return new String(chars);
}
return null;
}
}
方式二:使用String的拼接
package com.zhou.java;
public class ReverseTest02 {
public static void main(String[] args) {
String str="abcdefg";
String string= subString(str,2,5);
System.out.println(string);
}
public static String subString(String str, int startIndex, int endIndex) {
if (str!=null){
//第一部分
String substring = str.substring(0, startIndex);
//第二部分
for (int i= endIndex ; i>= startIndex ; i--) {
substring+= str.charAt(i);
}
//第三部分
substring+= str.substring(endIndex + 1);
return substring;
}
return null;
}
}
方式三:
package com.zhou.java;
public class StringBufferTest {
public static void main(String[] args) {
String str = "abcdefg";
String s = mystringBuffer(str,2,5);
System.out.println(s);
}
public static String mystringBuffer(String str, int startIndex, int endIndex) {
if(str!=null){
StringBuilder stringBuilder = new StringBuilder(str.length());
stringBuilder.append(str.substring(0, startIndex));
for (int i = endIndex; i >=startIndex ; i--) {
stringBuilder.append(str.charAt(i));
}
stringBuilder.append(str.substring(endIndex+1));
return stringBuilder.toString();
}
return null;
}
}
c.获取一个字符串在另一个字符串中出现的次数。比如:获取“ ab”在“abkkcadkabkebfkabkskab”中出现的次数。
方法一:
package com.zhou.java;
public class StringIndexTest {
public static void main(String[] args) {
String s1 = "abkkcadkabkebfkabkskab";
String s2 = "ab";
int count = myIndex(s1,s2);
System.out.println(count);
}
public static int myIndex(String s1, String s2) {
int length1 = s1.length();
int length2 = s2.length();
int count=0;
int index=0;
if(length1>=length2){
while ((index=s1.indexOf(s2,index))!=-1){
count++;
index+=length2;
}
return count;
}
return 0;
}
}
d.获取两个字符串中最大相同子串。比如:
str1 = "abcwerthelloyuiodef“;str2 = “cvhellobnm”提示:将短的那个串进行长度依次递减的子串与较长的串比较。
e.对字符串中字符进行自然顺序排序。
提示:
字符串变成字符数组。
对数组排序,选择,冒泡,Arrays.sort();将排序后的数组变成字符串。
3)String s=new String(“abc”),方式创建对象,在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char【】对应的常量池中的数据“abc”
4)String、StringBuffer、StringBuilder 三者的异同?
5)idea中如何debug调试
考虑sb.append(atr)操作会不会出现空指针问题
考虑1sb.length()操作出现空指针,长度0
2没有抛异常,长度为4,就是null的四个字符长度
System.out.println(sb);打印出来是带引号的null,
此处是把null作为append方法添加,添加过程中没有抛异常,把null当成是字符串的null,打印出来是带引号的null
构造器方式将str作为参数放入构造器中与上面的方式不一样
StringBuffer sb1=new StringBuffer(str);抛异常,代码未执行,后面的就执行不到
抛异常后关心append怎么做的,点进去看
6)“三天打鱼两天晒网” 1999-01-01 某年某月某日是在打鱼还是晒网?
5天一个周期
某年某月某日是1999-01-01的多少天
2020-09-08是在打鱼还是在晒网
总天数已知
总天数%5=1,2,3 打鱼
总天数%5=4,0晒网
总天数的计算
方式一:转成毫秒数 ,将1999-01-01转成Date()util下的Date()
(date2.gateTime()-date1.gateTime())/(10006060*24)+1
方式2:
7、练习题
1)什么情况下,indexOf(str) 和 lastIndexOf(str) 返回值相同?
情况一:存在唯一的一个 str。情况二:不存在 str
2)
3)如何理解String类的不可变性
4)String类是否可以被继承?为什么?String s=new String(“helllo”);在内存中创建了几个对象,请说明
5)String,StringBuffer,StringBuilder三者的对比
6)String常用的方法有哪些?(至少7个)
7)将字符串 “2020-09-08” 转换为 java.sql.Date类的对象(使用JDK8之前或JDK8中的API皆可)
SimpleDateFormat
DateTimeFormatter
8)解释何为编码?解码?何为日期时间的格式化?解析?
9)自定义Person类如下,如何实现自然排序(按姓名从小到大排序)
代码说明
class Person{
private String name;
private int age;
}