这篇文章为本人学习javaSE时的一些见解,一些晦涩难懂的地方,我用一些比较正常的白话来给大家进行讲解 此外本篇文章不适合一点基础都没有的小伙伴,更加适合有基础的小伙伴 有的小伙伴可能看不懂,在java这条学习道路上需要慢慢学慢慢地体会,才会发现面向对象编程到底是什么意思 我本人也是这么过来的
目录
1.2静态内部类(后面会单出一个文章讲一下静态有什么用,比较重要)
总结:格式化和解析日期,并且能够以制定格式输出日期,没有增删
说起JavaSE,我们就不得不先说一下Java的特性
1.Java特点
-
面向对象
-
安全性(四个层面 语言级安全性 Java的数据结构是放在类里面的 编译时安全性 编译时进行Java语言和语义的检查,保证变量对应一个相应的值,编译后生成Java类 运行时安全性 Java类需要类加载器载入并经由字节码校验器校验之后运行 可执行代码安全性 Java在网络中使用,对他的权限进行了设置,保证了被访问用户的安全性)
-
多线程
-
简单易用
-
跨平台性
2.环境搭建
-
下载JDK
-
在系统变量中新建JAVA_HOME 添加jdk路径
-
在系统变量path中 添加%JAVA_HOME%\BIN和%JAVA_HOME%\BIN\jre(大小写均可)
-
检测是否安装成功java -version
3.IDEA开发工具
介绍:IDEA,全称 IntelliJ IDEA,是 Java 语言的集成开发环境
4.Java基础语法
1.数据类型
-
基本数据类型 int char boolean等等
-
引用数据类型包括类,接口和数组(常用的String也是引用类型,他们的值是对象引用)
-
类型转换
自动类型转换(隐式转换)和强制类型转换(显式转换)
2.流程控制
2.1流程控制简介
-
顺序结构
-
循环结构
-
分支结构
2.2分支流程
-
if,else,else if
-
switch case default
2.3循环流程控制
-
for 适合知道循环次数的场景
-
while 适合不知道循环次数,但是知道循环条件的场景
-
do while(至少执行一次) 适合先执行循环再判断
3.数组
可以看做相同类型元素的集合,在内存中是连续的
5.面向对象
1.重载
参数的类型,数量,顺序不同
应用场景:方法名相同,参数不同
2.封装
-
提高程序的安全性,保护数据(在类中设置private修饰,外面无法访问这些被private修饰的属性)
-
隐藏代码的实现细节(不在一个类中)
-
统一接口
-
增强系统的可维护性
3.继承
子类中所有的构造方法默认都会访问父类中无参的构造方法
-
因为子类会继承父类中的数据,可能还会使用父类中的数据 所以子类初始化之前,一定要完成父类的数据的初始化
-
每一个子类构造方法的第一条语句默认是super()
public class Zi extends Fu {
public Zi() {
// super();
System.out.println("Zi中无参构造方法被调用");
}
public Zi(int age) {
// super();
System.out.println("Zi中带参构造方法被调用");
}
}
-
如果父类中没有无参构造方法,只有带参构造方法应该:通过使用super()关键字去显示调用父类有参构造或者在父类中提供一个无参构造方法
-
通过子类对象访问一个方法:先子类成员范围找,如果找不到再去父类找
-
子类重写的方法的访问修饰符的权限不能低于父类中被重写方法的访问修饰符权限
-
重写的方法不能抛出比父类中被重写的方法更多或更宽泛的[异常]
一个对象被向上转型后,他的具体信息会丢失,只保留了父类类型的信息 如果我们需要访问子类中特有的成员和或调用子类重写的方法,就需要使用向下转型(在进行向下转型之前,一定要确保对象实际上是子类的实例,否则会导致 ClassCastException
异常 应该使用instanceof运算符进行类型检验)
instanceof方法
public class Test {
public static void main(String[] args) {
Father f = new Son();//通过多态,引用父类创建子类实例,多态在后面会提到看不懂没关系
if(f instanceof Son)//判断f是否是son父类
Son s=(Son) f;//将father引用强转为son引用
}
}
}
class Father{
}
class Son extends Father{
}
用尽量简单的方式使对象进入可工作状态,尽量不要在构造器中调用方法(如果这个方法被子类重写,就会触发动态绑定,但是此时子类对象还没构造完成),可能会出现一些隐藏的但是又极难发现的问题
public class Test {
public static void main(String[] args) {
new Son();//new一个son对象,创建son时,会有一个看不见的无参构造方法访问父类无参构造方法
//由于父类无参中有fun()方法会被调用,又因为在子类中重写过,所以会调用子类son中的son方法
//此时son还没有被初始化(因为没创建实例),所以i=0,打印结果为0
Father f=new Son();//创建了实例会打印10
f.fun();
}
}
class Father{
public Father(){
fun();
}
void fun(){
System.out.println("fff");
}
}
class Son extends Father{
int i=10;
@Override
void fun() {
System.out.println(i);
}
}
4.多态
-
方法名称,参数列表和返回类型必须和父类中被重写的方法相同
-
子类重写的方法的访问修饰权限不能低于父类中被重写方法的访问修饰符权限
-
重写的方法不能抛出比父类中被重写方法更多或更宽泛的异常
-
子类中重写的方法可以调用父类中被重写的方法,使用
super
关键字 -
重写的方法必须具有相同的方法体,或者可以进行方法体的拓展
方法的访问修饰符和异常:重载方法可以具有相同的访问修饰符(如
public
、private
、protected
)和抛出的异常。
重载方法用于在同一个类中实现相似功能但具有不同参数的方法。重写方法用于子类重新定义父类方法的行为,以适应子类的特定需求
子类对象中重写的方法,在通过父类引用变量调用时,会调用子类中的实现(动态绑定)
class Animal {
public void eat() {
System.out.println("Animal is eating.");
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("Dog is eating.");
}
public void bark() {
System.out.println("Dog is barking.");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
animal.eat(); // 调用的是 Dog 类中的 eat() 方法
// animal.bark(); // 错误:无法访问 Dog 类中独有的方法
Dog dog = (Dog) animal; // 向下转型
dog.bark(); // 调用 Dog 类中的 bark() 方法
}
}
6.抽象类
一个抽象类没有包含任何抽象方法,它仍然可以被声明为抽象类,以限制其不能被直接实例化
抽象类允许我们在父类中定义通用接口(方法),并在子类中提供具体实现
abstract关键字修饰的方法不需要在抽象类中实现,必须在具体的子类中重写和实现,除非子类也是抽象类
抽象类不能直接实例化,不能使用new关键字创建对象。只能通过其子类的实例化来实现多态行为。如果子类也是抽象类,那么它也不能被实例化
final
关键字的限制:abstract和final不能同时使用,因为final类不能被继承,而abstract类必须被继承。此外,final方法也不能被重写,这与抽象方法的目的相违背
private
关键字的限制:抽象方法不能使用private修饰符,因为private方法只能在类内部使用,而抽象方法需要在子类中被重写
抽象类的构造器
尽管抽象类不能被直接实例化,但它们可以拥有构造器。抽象类的构造器通常用于初始化抽象类的字段,为子类的构造器提供基础
static
关键字的限制:抽象方法不能用static修饰,因为static方法属于类而非实例,而抽象方法必须在对象的上下文中被实现。
我们只定义静态static方法完全OK,因为静态方法是属于类的,所以静态方法必须满足给类调用,如果通过类无法调用,那么这种静态方法肯定是不对的。为了达到这一要求,static方法就必须有方法体,即已经实现了,也就不是抽象方法了。所以静态(static)方法不能是抽象方法,即abstract不能与static同时修饰方法。即没有类抽象方法
Java中的实例是由类创建的对象
7.接口
类和接口之间不再是继承关系,而是实现关系,用implements关键字表示
接口中没有成员变量,只有公有静态常量 即默认情况下属性前都会有 public static final 这三个关键字修饰
final修饰的属性必须进行初始化,而对于公有静态常量(public static final),初始化的途径只有两条——①定义时显式初始化;②在静态代码块中初始化。但是很遗憾,接口中不允许存在代码块,而且接口没有构造方法。因此,这就要求我们在接口中定义公有静态常量时,必须在定义时就赋初值。否则IDEA报错。
Δ事实上,接口中的方法默认就是公有抽象方法,因此在接口中定义抽象方法时,可以省略掉abstract关键字
需要注意的是,想定义默认方法必须在前面添加*default关键字*,因为接口中的方法如果你什么都不写,默认是公有的抽象的方法
default关键字只能在接口中使用,就算实现类要重写默认方法,实现类中重写后的方法也不能添加default修饰符
public interface Demo2 {
//①在JDK7.0版本之前,接口中仅支持公有的抽象方法:
public abstract void hello_world();
//②从JDK8.0开始,接口中可以由默认方法和静态方法:
//默认方法
public default void what_time() {
System.out.println("姥姥——姥姥——几点啦?");
}
//静态方法
public static double Sum(double x, double y) {
return x + y;
}
//③JDK9.0以后,接口中可以有私有方法 :
private void own() {
System.out.println("这是👴的私有方法。");
}
public default void invoke_own() {
this.own();
}
}
class Imple implements Demo2{
@Override
public void hello_world() {
System.out.println("你好,世界!");
}
}
class Test2 {
public static void main(String[] args) {
Demo2 d2 = new Imple();
d2.hello_world();
System.out.println("---------------------------------");
d2.what_time();
System.out.println("传入的x与y的和 = " + Demo2.Sum(141, 135));
System.out.println("---------------------------------");
d2.invoke_own();
}
}
接口存在的目的是为了规范类,因此接口也不可以被实例化。接口中不允许存在代码块,也没有需要初始化的成员,因此接口没有构造方法(构造器)
在上文中我们提到,接口不能被实例化,而是通过多态的方法实例化子类对象。意思就是说,接口引用指向子类对象也是多态的体现
8.枚举
枚举方法
枚举类型可以定义方法,这些方法可以在枚举常量上调用。例如,可以在 Weekday
枚举类型中定义一个 isWeekend
方法来判断当前枚举常量是否为周末:
public class Test <T> {
public static void main(String[] args) {
boolean w = Weekday.Sunday.isWeekends();
System.out.println(w);
}
}
enum Weekday{
Monday,Tuesday,Wednesday,Thurday,Friday,Saturday,Sunday;
public boolean isWeekends(){
return this==Saturday || this==Sunday;
}
}
枚举构造器
枚举类型也可以定义构造器,这些构造器只能在枚举常量的定义中被调用,并且只能用来初始化枚举常量的值。例如,可以在 Weekday
枚举类型中定义一个带参数的构造器来设置枚举常量的值
enum Weekday {
Monday("星期一"), Tuesday("星期二"), Wednesday("星期三"), Thursday("星期四"), Friday("星期五"), Saturday("星期六"), Sunday("星期日");
private String value;
private Weekday(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
枚举实现接口
枚举类型也可以实现接口,这样每个枚举常量都会自动实现接口中的方法。例如,可以在 Weekday
枚举类型中定义一个接口,并让枚举类型实现这个接口
interface Printable {
void print();
}
enum Weekday implements Printable {
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;
@Override
public void print() {
System.out.println("Today is " + this.name());
}
}
6.常用类
1.内部类
-
编译之后可生成独立的字节码文件
-
内部类可直接访问外部类的私有成员,而不破坏包装
1.1成员内部类
-
与实例变量,实例方法同级别的类
-
外部类的一个实例部分,创建内部类时,必须依赖外部类
-
重名时优先访问内部类属性
-
(JDK16后可以)成员内部类里不能定义静态成员,可以包含静态常量
简单来说就是在一个类中创建了另一个类
1.2静态内部类(后面会单出一个文章讲一下静态有什么用,比较重要)
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员
static class..
1.3局部内部类
(1)局部内部类定义在方法中/代码块 (2) 作用域在方法体或者代码块中 (3)本质仍然是一个类!!!
不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。 但是可以使用final 修饰,因为局部变量也可以使用final.
-
外部类—访问---->局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】
外部其他类—不能访问----->局部内部类【因为 局部内部类地位是一个局部变量】
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.say();//只能在这个方法中创建并使用Inner类,方法失效,Inner类销毁
}
}
class Student{
public void say() {
class Inner{
public Inner(){
System.out.println("1122");
}
}
new Inner();
}
}
我学了这么多,这个用到的不多
1.4匿名内部类(比较重点)
-
最本质的还是一个类
-
是一个内部类(有关内部类的内容不在这里讲述了)
-
该类没有名字(但是系统会分配一个代号在内存中)
public class Test {
public static void main(String[] args) {
new A() {
@Override
public void eat() {
System.out.println("正在调用eat方法");
}
}.eat();
}
}
interface A {
public void eat();
}
有很多小伙伴可能会看不懂,因为这里new了一个接口,大家可以把他看着左边是一个引用,而这个引用实现了接口 只不过因为可能这个类使用一次,不需要创建实例所以使用了这种方式,而创建了接口实现的类,肯定要实现接口,所以里面是实现接口的方法
1、使用匿名内部类时,我们必须是继承一个类或者实现接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口(可以通过一个类实现多个接口,进而继承这个类可以到达实现多个接口)。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现接口的所有抽象方法
如下,使用了f方法,f中的参数要求传一个A的对象,而A是一个接口,就可以使用上文使用一次的匿名内部类来创建
public class Interface01 {
public static void main(String[] args) {
f(new A() {
@Override
public void eat() {
System.out.println("没有创建对象便成功的调用了f方法,不需要实现接口");
}
});
}
public static void f(A a){
a.eat();
}
}
interface A{
public void eat();
}
public class Interface01 {
public static void main(String[] args) {
A a = new A(){
@Override
public void eat() {
System.out.println("正在调用eat方法");
}
public void drink(){
System.out.println("正在调用drink方法");
}
};
a.eat();
a.drink();
System.out.println(a.getClass()); //获取类名
}
}
interface A{
public void eat();
public void drink();
}
本质上没有什么太大的用,主要还是节省代码量,看着更简洁
主要用途那种一个类只用一次,可以避免创建对象
2.1String
*String 是引用类型,内部并不存储字符串本身*
StringBuilder 和 StringBuffer
2.2日期和时间
1.传统时间与日期类
如今仍有部分公司在使用这些时间与日期类部分内容,所以我们也有必要去了解一下。有的完全过时的内容这里就不在讲解。
1.1 Date类
Java中的Date
类是一个用于表示特定瞬间(精确到毫秒)的日期和时间的类
public class Test {
public static void main(String[] args) {
//1.Date():创建一个表示当前日期和时间的Date对象(使用系统默认的时区和毫秒计时器)。
Date date = new Date();
System.out.println("当前时间为"+date.toString());
//有参构造方法 Date(long date):根据指定的毫秒数(自1970年1月1日00:00:00 GMT以来的毫秒数)创建一个Date对象。
Date date2 = new Date(1000);//1秒等于1000毫秒
System.out.println(date2.toString());
//2.获取日期和时间的方法
Date date3=new Date();
long time=date3.getTime();//返回至1970年1月1日的毫秒数(即时间戳)
System.out.println(time);
Date date4=new Date();
long newTime=1000l;//设置毫秒数
date4.setTime(newTime);
System.out.println(date4.toString());
}
}
总结:主要用于表示时间,没有增减
1.2Calendar类
由于Calendar
是抽象类,因此你不能直接实例化它。相反,你需要使用Calendar
类的一个子类实例,通常是通过调用Calendar
类的getInstance()
静态方法获得的,该方法会返回一个Calendar
对象,该对象是根据默认时区和语言环境初始化的。
public class Test {
public static void main(String[] args) {
//获取当前日期对象
Calendar calendar1=Calendar.getInstance();//多态获取Calendar的子类
System.out.println(calendar1.toString());
//获取某个信息
int year=calendar1.get(Calendar.YEAR);
//获取日期对象
Date time = calendar1.getTime();
System.out.println("当前时间为"+time);
//获取当前时间毫秒值
long timeInMillis = calendar1.getTimeInMillis();
System.out.println(timeInMillis);
//修改日期
calendar1.set(Calendar.YEAR,2020);
System.out.println(calendar1.get(Calendar.YEAR));
//给某个信息增加时间,减少
calendar1.add(Calendar.DAY_OF_MONTH,-1);
System.out.println(calendar1.get(Calendar.DAY_OF_MONTH));
}
}
总结:能给date表示时间没有增减
1.3SimpleDateFormat类
SimpleDateFormat
类是 Java 中用于格式化和解析日期的一个非常强大的类。它允许你进行用户自定义的日期-时间格式。这个类继承自 DateFormat
抽象类,并实现了 Serializable
接口,这意呀着它可以被序列化以便在网络中传输或存储到文件系统中。
主要用途
-
格式化日期:将
Date
对象转换成符合特定模式的字符串。 -
解析日期:将符合特定模式的字符串转换成
Date
对象。
import java.util.Date;
public class Test {
public static void main(String[] args) throws ParseException {
//将日期格式化成日期与字符串
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date = new Date();
System.out.println(date);
System.out.println(simpleDateFormat.format(date));//使用format方法将date格式化成指定字符串
//将时间毫秒值格式化成字符串
long l = System.currentTimeMillis();
date.setTime(l);
String format = simpleDateFormat.format(date);
System.out.println(format);
//解析日期
String time="2023年2月4日 18:20:20";
Date parse = simpleDateFormat.parse(time);
System.out.println(parse);
}
}
总结:格式化和解析日期,并且能够以制定格式输出日期,没有增删
2.新旧替换
2.1新增的类
-
LocalDate ①替代Calendar处理日期功能,更加简洁②表示一个具体的日期,如'2024-07-27'不包含时间信息③加减天数,月份等等
-
LocalTime ①替代Calendar处理时间功能②表示一个具体时间,如'10:29:18'③加减小时分钟
-
LocalDateTime ①整合了LocalDate和LocalTime的功能,如"2024-07-27T10:29:18" ②加减日期,时间以及比较等等
-
Instant ①替代了Date中时间戳的功能,但更加精确(到纳秒)②表示一个具体的时间点,即时间线上的一个瞬时
-
ZonedDateTime ①替代了Calendar处理带时区日期时间②表示一个具体带时区的日期时间如'2024-07-27T10:29:18+08:00[Asia/Shanghai]'
-
DateTimeFormatter ①替代SimpleDateFormat提供了更加强大和灵活的日期时间格式化功能②可以通过模式字符串来自定义日期时间的格式,也可以解析符合特定格式的字符串为日期对象
-
Duration和Period ①两个类提供了新的时间间隔表示方式②Durtion用于表示时间间隔如“PT1H30M”(1小时30分钟)③
Period
用于表示日期间隔,如“P2Y6M”(2年6个月)总结:
线程安全性:新类都是不可变的,因此它们是线程安全的。 不可变性:一旦创建,新类的对象就不能被修改,这有助于防止意外的修改和并发问题。 更清晰的API设计:新类提供了更直观、更易于理解的API,使得日期时间的处理更加简单和方便。 更好的国际化支持:新类支持时区处理,并且遵循ISO 8601标准,使得日期时间的表示更加国际化。 更精确的时间表示:Instant类提供了纳秒级的时间精度,比旧的java.util.Date类更加精确。
3.JDK8之后的时间类
3.1LocalDate
LocalDate
代表没有时区的日期,如年月日
public class Test{
public static void main(String[] args) throws ParseException {
//获取当前日期
LocalDate now = LocalDate.now();
System.out.println(now);
//通过年月日创建LocalDate实例
LocalDate localDate = LocalDate.of(2000, 1, 1);
System.out.println(localDate);
//加上天数
LocalDate localDate1 = localDate.plusDays(10);//还给一个新的对象
System.out.println(localDate1);
//获取单个年月日等
int year=localDate1.getYear();
System.out.println(year);
//格式化日期
String format = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));//不按照 标准格式会报错
System.out.println(format);
}
}
3.2LocalTime
LocalTime
代表没有日期的时间,如时分秒
public class Test{
public static void main(String[] args) throws ParseException {
//获取当前时间
LocalTime now = LocalTime.now();
System.out.println(now);
//通过时分秒创建实例
LocalTime localTime = LocalTime.of(12, 25, 10);//不按照指定就会报错
System.out.println(localTime);
//加减
LocalTime localTime1 = now.plusHours(1);
System.out.println(localTime1);
//获取
int hour = localTime1.getHour();
System.out.println(hour);
//格式化
String format = now.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
System.out.println(format);
}
}
3.3LocalDateTime
LocalDateTime
代表没有时区的日期和时间
public class Test{
public static void main(String[] args) {
//获取当前日期和时间
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
LocalDate localDate = LocalDate.of(2021, 12, 22);
LocalTime localTime = LocalTime.of(13, 24, 12);
//构造创键localdatetime
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
System.out.println(localDateTime);
int hour = now.getHour();
}
}
3.4Zoneld
oneId
是时区的标识符,它可以是诸如"Europe/Paris"的地理区域标识符,或者是像"UTC"这样的固定偏移量
public class Test{
public static void main(String[] args) {
//获得系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);
// 从字符串创建一个ZoneId
ZoneId zoneId2 = ZoneId.of("Europe/Paris");
System.out.println("ZoneId of Europe/Paris: " + zoneId2);
// 获取时区规则
ZoneRules rules = zoneId.getRules();
System.out.println("Zone Rules: " + rules);
// 返回规范化形式的ZoneId
ZoneId normalizedZoneId = zoneId.normalized();
System.out.println("Normalized ZoneId: " + normalizedZoneId);
}
}
3.5ZoneldDateTime
ZonedDateTime
是一个包含日期和时间的类,同时关联了时区信息
public class Test{
public static void main(String[] args) {
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
//获取指定地区的时间
ZonedDateTime now1 = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
System.out.println(now1);
}
}
3.6Instant
Instant
类在 Java 中表示一个时间线上的一个瞬时点,它是以 Unix 时间戳(即自1970年1月1日UTC以来的秒数)为基础的,但精度更高,可以达到纳秒级别。Instant
是不带时区的,它表示的是全球统一的时间线上的一个点。
public class Test{
public static void main(String[] args) {
// 获取当前时间的 Instant 实例
Instant now = Instant.now();
System.out.println("Current instant: " + now);
// 将 Instant 转换为自1970年1月1日UTC以来的毫秒数
long epochMilli = now.toEpochMilli();
System.out.println("Epoch milli: " + epochMilli);
// 加上10秒
Instant tenSecondsLater = now.plusSeconds(10);
System.out.println("Ten seconds later: " + tenSecondsLater);
// 将 Instant 转换为特定时区的 ZonedDateTime
ZonedDateTime zdt = now.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println("Shanghai time: " + zdt);
}
}
3.7DateTimeFormatter
可以定义几乎任何所需的日期时间格式DateTimeFormatter
是处理日期时间文本表示的强大工具,它支持灵活的格式定义和本地化,相比于SimpleDateFormat,它的线程更安全。
public class Test{
public static void main(String[] args) {
// 定义自定义的日期时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//不按照格式可能会报错
// 使用 LocalDateTime 和 formatter 格式化日期时间
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = now.format(formatter);
System.out.println("Formatted DateTime: " + formattedDateTime);
// 解析字符串为 LocalDateTime
String dateTimeStr = "2023-10-01 15:30:45";
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeStr, formatter);
System.out.println("Parsed DateTime: " + parsedDateTime);
// 使用预定义的 ISO 格式
DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
String isoDateTimeStr = now.format(isoFormatter);
System.out.println("ISO Formatted DateTime: " + isoDateTimeStr);
// 解析 ISO 格式的字符串
LocalDateTime parsedIsoDateTime = LocalDateTime.parse(isoDateTimeStr, isoFormatter);
System.out.println("Parsed ISO DateTime: " + parsedIsoDateTime);
}
}
3.8Period
Period
类用于表示基于日历的日期(年、月、日)之间的间隔。它主要用于处理那些与时间无关,仅与日期相关的间隔,比如两个生日之间的年数差异。Period
的字段包括年(years)、月(months)和日(days)。
public class Test{
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2020, 1, 15);
LocalDate endDate = LocalDate.of(2023, 4, 20);
// 计算两个日期之间的Period
Period period = Period.between(startDate, endDate);
// 输出结果
System.out.println("Years: " + period.getYears());
System.out.println("Months: " + period.getMonths());
System.out.println("Days: " + period.getDays());
// 也可以通过toTotalMonths()获取总月份数
long totalMonths = period.toTotalMonths();
System.out.println("Total Months: " + totalMonths);
}
}
3.9Duration
Duration
类用于表示基于时间的持续时间,精确到纳秒。它主要用于处理那些与时间相关的间隔,比如两个时间点之间的时长。Duration
的内部实现是基于秒和纳秒的,但它提供了方便的方法来以天、小时、分钟、秒等为单位进行操作
Instant startTime = Instant.now();
// 模拟一些操作...
try {
Thread.sleep(5000); // 休眠5秒
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant endTime = Instant.now();
// 计算两个时间点之间的Duration
Duration duration = Duration.between(startTime, endTime);
// 输出结果
System.out.println("Seconds: " + duration.getSeconds());
// 获取剩余的纳秒部分
long nano = duration.getNano();
System.out.println("Nano seconds: " + nano);
// 也可以以其他单位输出
System.out.println("Duration in millis: " + duration.toMillis());
// 转换为以天为单位的近似值(注意:这只是一个近似值,因为天的小数部分被忽略了)
long days = duration.toDays();
System.out.println("Approximate days: " + days);