javaSE学习笔记

jdk

JAVA_HOME:用来配置java jdk 所在的目录,便于其他需要使用java的程序找到jdk

classPath:用来配置jdk类库所在位置

path:配置jdk的命令所处位置。位置为java安装目录的bin目录里面

​ cmd window系统中执行命令(系统命令,.bat文件,.exe文件)

java简介

1995年发布java第一个版本

最新版本 jdk15

常用的jdk版本1.8 或者11

每个版本的发布会增加一些功能,但是也会兼容以前的版本的内容。

java的三个平台技术

1.javase:java平台标准版,是java开发的基础,其包含了java语言所需要的基础库类和环境 第一个阶段主要学习java的语法,常用的api

/*javaEE:java平台企业版,在javase基础之上,用来开发企业级的应用。第二阶段学习内容,常用的javaWeb开发,java主要应用场景jdbc servlet jdbc

3.javame (java平台微型版,之前主要用于移动设备,机顶盒等,现在主要被安卓替换)

jdk jre jvm

jdk:java开发开发工具包,包含jre和jvm以及常用的java命令(java程序 开发必须要有jdk)

jre:java运行环境 java程序或者java项目运行时,必须依赖的环境 (jre包含jvm)

jvm:java虚拟机,最终用来加载class并且解释执行的工具,是实现java语言跨平台的关键,其会将java编译之后的字节码文件翻译成对应的机器代码。

java语言的特点

面向对象:将事务抽象成对象,通过对象与对象之间的关系来组成系统。更符合人的思维方式,适合大型项目的开发和维护

跨平台:java语言只需要编译一次便可以任意不同的平台上面运行。

​ java源代码编译==》java字节码==》不同平台jvm==》解释==》机器语言

安全健壮稳定:具有自动垃圾回收策略。避免指针操作导致的安全问题

多线程:语言本身支持多线程任务处理。

高并发处理能力强:

java的应用

web开发:淘宝,京东

企业管理软件:OA系统 CRM系统 在线考试系统 教务管理系统

安卓开发:

游戏开发:

大数据:

idea

JAVA最流行的集成开发工具

相关概念:project(项目)java代码,依赖库,环境的集合

包:用来存放java源代码的文件夹,不同包用来存放不同功能代码

java源代码:我们自己写的java文件代码

类:java程序的基本组成单位,一个.java文件通常对应的一个.class文件

方法:类似于js里面的function()方法

字节码:.java文件可以生成一个或者多个.class文件(包含内部类)

java命令

javac:用来编译java源代码文件,将java源代码文件编译成.class文件

javac java源代码.java

java:运行java程序(.clas文件 .jar包)

javap:反编译java程序,.class文件反编译成.java文件

jar :将class打包成一个jar包

jar -cvf jar包名称 类文件

javadoc:用来生成帮助文档基本不用

java注释

文档注释 /**

*生成文档注释,通常使用文档注释对类或者方法进行说明

*/

单行注释://单行注释通常用来对单行代码进行说明

多行注释:/*

**/

java中数据类型

JAVA中数据类型可以分为两类:一个是基本数据类型,一个是引用数据类型

基本数据类型有八种:

1整数类型、

byte 占1字节8位取值范围:-128–127

short:占2字节占16位取值范围:-32768-32767

int:占4字节占32位

long 占8位 占64位

2.浮点类型

float 单精度 占32位 4个字节,1符号位+8位指数位+23位位数位

double 双精度 占64位8个字节。1个符号位+11个指数位+52位尾数位

3.字符类型

char:占两个字节采用unicode编码

4.布尔类型

boolean

占用一个字节,取值表示真假

变量的定义

变量就是给数据取名字。

java是强类型语言:定义的变量的数据类型与给定的值的数据类型必须一直或者兼容。

变量如果没有初始化,就会编译报错。

java中的标识符(命名规范)

标识符由数字字母下划线美元符号组成,长度不受限制 不能以数字开头 不能是java的关键字 不能是 null false true

变量分类

根据变量定义的位置和前面的修饰符可以分为:

1.局部变量 定义在方法里面或者代码块内的变量,作用域位从变量定义的位置开始代码块结束。必须初始化才能执行

2.成员变量:变量定义在类中,方法外面。且变量前没有加static关键字称为成员变量,成员变量作用域在这个类中

约束:成员变量不能在静态方法中直接访问

3.类变量:定义在类中,并且由static修饰。

相同作用域里面不能有相同的局部变量名 通过类名.变量名直接调用,变量归类所有,一个类的不同对象共享一个

全局变量的默认值

全局变量的默认值默认0值,全局变量不需要初始化便可以使用

整型:0

浮点类型:0.0

char类型:空字符

boolean:false

引用数据类型:null

基本数据类型之间的转换

自动类型转换:小的数据类型转化成大的数据类型

byte>short>int>long

float>double

强制类型转化:大的数据转小的数据类型,需要进行强制转换,会存在精度丢失

int i=(int) long 类型变量

java中整数默认采用int类型,而小数默认采用boolean类型

二进制原码 反码 补码

原码:第一个符号位 0表示正数 1表示负数

反码:符号位不变,其他取反 解决正负相加不为0的问题

补码:在反码的基础上加1

正数的反码补码原码都一样

java运算符(优先级)单目乘除位运算 关系 逻辑三目后赋值

算数运算:+ - * / ++ –

正数除法会舍去小数位

比较运算 > < <= >= ==

逻辑运算 ! && & | ||

赋值运算 += -= =

位运算:<< 左移 >>右移 >>> 无符号右移 &位与 位或| 位异或 ^ 位非

与(&)运算

与运算进行的是这样的算法:

0&0=0,0&1=0,1&0=0,1&1=1
1

在与运算中两个开关是串联的,如果我们要开灯,需要两个开关都打开灯才会打开。
理解为A与B都打开,则开灯,所以是1&1=1
任意一个开关没打开,都不开灯,所以其他运算都是0

通俗理解为A(与)&B都开则开,否则关

非(~)运算

非运算即取反运算,在二进制中1变0,0变1
110101进行非运算后为
001010即1010

或(|)运算

或运算进行的是这样的算法:

0|0=0,0|1=1,1|0=1,1|1=1
1

在或运算中两个开关是并联的,即一个开关开,则灯开。
如果任意一个开关开了,灯都会亮。
只有当两个开关都是关的,灯才不开。

理解为A(或)|B任意开则开

异或(^)运算

异或运算通俗地讲就是一句话
同为假,异为真
所以它是这样的算法:

0^0=0,0^1=1,1^0=1,1^1=0

java控制台输入输出

转义子符:

\n \t空格

流程控制

switch

语法:

Switch(变量){

case:语句;break;

case:语句;break;

default:break;

}

每个switch语句的case后面必须跟break否则会穿透

变量可以传值

byte short int char String enum

break:中断循环

continue:跳出循环,执行下一次循环

java数组

数组是同一数据类型的集合,可以通过下标进行访问,下标从0开始访问,访问速度非常快,数组一旦定义,数组的大小固定的,会在内存中分配一个连续的内存空间,是引用数据类型

如何定义数组

1.声明数组类型变量

数据类型[] 变量名;

例:int[] nums;

2.数组的初始化

a.静态初始化

nums={1,2,3,4,5};

//静态初始化
//int[] scores={1,2,3};
 //[]放在变量名前面或者后面都可以
 int scores[]={1,3,4};
//java引用数据类类型默认打印的是其地址值
 System.out.println(scores[0]);
 //数组的下标范围应该是0-数组长度-1,如果超出这个范围会报ArrayIndexOutOfBoundsException
 //null值可以赋值给任意的引用数据类型,表示空的没有任何数据,当对null使用 . 操作符会抛出NullPointerException
 int[] nums=null;
 System.out.println(nums.length);

b.创建指定大小的指定数组的大小(动态初始化)

nums=new int[10]

/*
* 数组的默认值
* 数组在创建之后,没有赋值的情况下会存在默认值
* 默认值为具体的数据类型的零值
* 整型 0
* 浮点 0.0
* boolean false
* char \u0000 空字符
* 引用数据类型 null
* */

c.通过new创建数组并赋值(也是静态初始化)

数组变量=new 数据类型[]{}

nums=new int[]{1,2,3,4,5};

栈:存放局部变量,以及八大基本数据类型的值

堆:引用数据类型的数据存放在堆中

堆和栈的区别

1、堆是线程共享的,而栈内存是线程独占的

2、堆存储java的对象。栈用来存储方法执行时的变量和基本数据类型的值

3、栈的内存小,访问速度快,而堆内存大,访问速度慢

4、垃圾回收的方式不一样。栈中数据方法执行完出栈则会被回收。而堆里面的对象需要等待java自动GC回收

对象什么时候会被gc回收

当对象不可达(1、没有被任何变量引用时 2、当超出作用域),便可以被回收,而具体什么时候被回收,需要看具体的java自动垃圾回收的时间

二维数组

当数组中存放的是二维数组时,我们称之为二维数组

数据类型 [] [] 变量名=new 数据类型[ 外层数组大小] [内层数组大小]

注意 外层数组大小必须要指定,内层数组大小可以不指定

package com.sc.day05;

/**
 * @author 阿彪
 * @create 2021-02-22-15:08
 */
public class Array7 {
    public static void main(String[] args) {
        //内层数组的长度可以不相同
        int [][] nums={{1,2,3,4},{2,3,4,5},{2,3,3}};
        for (int i = 0; i <3 ; i++) {
            for (int j=0;j<nums[i].length;j++){
                System.out.print(nums[i][j]+" ");
            }
            System.out.println();
        }

        //定义二维数组外层数组必须指定
        //指定了内层相当于初始化了内层数组,默认值为0
        int [][] scores1=new int[3][2];
        scores1[0]=new int[]{1,2,3};
        System.out.println(scores1[1]);//输出一个地址
        System.out.println(scores1[1][0]);//0
        
        //定义二维数组外层数组必须指定
        //未指定内层数组没有初始化内层数组,默认值为null
        int [][] scores=new int[3][];
        scores[0]=new int[]{1,2,3};
        System.out.println(scores[1]);//null
        System.out.println(scores[1][0]);//NullPointerException空指针异常



    }
}

数组的工具类

java api 中提供了Arrays工具类用于对数组进行常见操作

常见方法

1、toString(数组): 将数组转化成字符串进行打印

2、sort(数组):对数组进行排序,一般为升序

3、copyOf(数组,新的长度):复制数组内容,返回一个新的长度的数组

4.binarySearch(数组,需要查找的值) 在数组中查询是否存在某个值,如果有返回正数,则为对应数组所在下标,如果返回值为负数则表示不存在

5、fill(数组,值):用指定的值将数组填满

面向对象

面向对象编程简介

面向:关注

对象:简单的理解对象就是某一事务,对象,世界本质是由一个个对象组成。万物皆可对象

面向对象编程:(oop)在编程的过程中把关注点放在一件事或者一个活动中涉及到的对象

面向过程编程:(pop) 在编程过程中把关注点放在事件的执行步骤和过程上

举例

五子棋

面向过程分析

1.开始游戏 2.黑子先走 3.绘制棋盘 4.判断输赢,5.白子下 重复2,3,4,5步骤

面向对象

分析对象:

1.棋子:

黑白属性

方法:落子

2.棋盘:

属性:尺寸大小

方法:绘制棋盘

3.裁判:

方法:判断输赢 下的位置是否符合规范

创建对象

通过不同的对象调用事件

创建两个玩家 白子 黑子

裁判: 判断落子是否合法 判断输赢

通过棋盘对象 绘制棋盘

面向对象编程特征

1.抽象:对现实生活中的事务进行抽象化,提取我们程序中需要的属性和行为特征。用代码来表示,形成一个类(class)。

2.封装

面向对象的一些概念

1.类:用来表示一类事物,对现实生活中的事物进行抽象提取需要的属性和行为形成类。类通常有属性和方法,类是java代码的载体,所有属性和方法必须写在类中。(描述一类事物共有特征)

关键字Class

2.对象:是类的一个具体实例。(具体到某一个)

3.方法:实现特定功能的代码,用来描述事物的行为

形参:在方法定义的时候写在()里面的参数

实参:调用方法时实际传的参数

4.成员变量(属性):类的属性,用来描述一类事物共有的特征

static

static为一个静态修饰符,可以用来修饰变量,方法,内部类。

标识修饰的对象归类所有吗,只有一份,可以直接通过类名.属性名|方法直接访问。

随类的加载而加载,与类一起保存在方法区中。

静态变量和成员变量区别

静态变量随着类的加载而加载,随类的卸载而卸载。而成员变量随着类的创建而加载,随着对象的销毁而销毁,静态变量的生命周期更长

存放位置:静态变量随类一起存在方法区中,而成员变量跟着对象存放在堆中

归属:静态变量归类所有,只有一份,成员变量归对象所有,每个方法都有一份

调用方法:静态变量可以通过类名访问,而成员变量需要通过对象去访问

类与对象的区别

类:相当于是一个模板,加载之后存储在方法区,只有一份

对象:是根据类的模板做出来的具体对象。需要通过new关键字创建,创建之后存储在堆中

一个类可以创建多个对象

This关键字

this表示当前对象,通常用在局部变量与成员变量同名的情况下来调用成员变量

如:构造方法:get set方法中

this(参数,参数):表示调用本类的构造方法

要求:只能在构造方法中使用,且必须放在第一行

方法的重载

在同一个类中,多个方法,其方法名相同,方法签名不同,参数列表不同,则我们称之为重载

方法签名:方法名+参数列表类型

重载主要是方法名的一种复用,为一种行为提供不同的传参方式

构造器可以重载

封装

封装就是将数据和功能代码封装起来,对外隐藏其具体的实现细节。对外提供操作的接口

java中的封装

方法的封装:将复杂的实现特定功能的代码封装到方法中,以方法的形式对外提供服务。调用者并不需要知道方法内部的具体细节实现

类的封装:将有特定属性和方法的事物,封装成一个类,对其他类隐藏实现细节。

权限的封装:给 类 属性 方法 添加访问权限修饰符,用来设置其他类对其的访问权限

封装的好处

1.提高代码的复用性

2.可以提高安全性

Java中的四种访问权限修饰符

private:私有的,只能在本类中访问

default:不用写 同包下面可以访问

protected:相同包下面的类以及子类可以访问

public:所有的类都能访问。

继承

通过扩展一个类(父类,基类)来建立另外一个类的过程

继承关键字

特点:

子类可以继承父类所有非私有的属性和方法’

创建子类对象,会先调用父类构造方法创建父类对象、

java中只支持单继承(一个类的直接父类只能有一个父类,但是支持多重继承)

Super和super()

super():必须写在子类的构造器中,写在第一行,用于调用父类的构造方法来创建父类的对象

super:表示父类对象

方法的重写:重写发生在子类的关系中,子类重写父类的方法,要求返回值类型,方法名,参数列表要与父类方法一直

静态方法不能被重写 (子类中能有与父类相同的方法,但不构成重写)静态方法能被继承

final关键字

final可以用来修饰 变量 方法 类 表示最终的 不可变的意思

修饰类,类不可以被继承

修饰方法:表示方法不能被重写

修饰变量的时候表示变量的值不能被改变(如果是基本数据类型表示值不可改变,如果是引用数据类型指地址值但是值能够被改变)

常量的定义:使用public static final :表示唯一一份,且不可变。

变量名通常所有的字符都大写,单词与单词之间使用下划线连接。

类中代码执行顺序:

父类静态代码块
子类静态代码块
父类的代码块
父类的构造方法
子类的代码块
子类的构造方法

抽象类

java中类如果其确定具有某些行为,但是行为的具体实现不能明确定义的。通常我们将类定义成抽象类,并将其行为定义成抽象方法

抽象方法:

方法的实现不确定,无法描述时使用抽象方法定义

抽象方法的声明:没有方法体(方法的具体实现)

有abstract 关键字修饰

抽象方法只能在抽象类中

抽象方法的子类必须实现父类的抽象方法,除非子类也是抽象类

特点:

a.抽象类不能被实例化,(不能创建对象)

b.抽象类中可以没有抽象方法,但是有抽象方法的类,必须声明成抽象类

c.抽象象类中允许有属性,成员方法,构造方法。

抽象方法:

由abstract修饰,只有方法声明,没有方法体的方法。抽象方法主要的作用在于约定子类必须实现父类共同的行为。

特点:

a.必须定义在抽象方法中

b.没有方法体

c.抽象方法不能使用private static final修饰

多态

同一类的对象调用相同的方法可以表现出不同的行为,我们称之为多态

多态的三个必要条件

1.继承

2.重写

3.父类的引用指向子类的对象

作用:

可以提高程序的拓展性和可维护性
父类的引用不能调用子类特有的属性和方法

多态的调用特点

编译时(有没有这个方法,属性)看左侧(看变量类型)

运行时,看右侧(实际的对象类型)

如果是静态的则只看左边

常见的多态形式 重写 重载 可变参数

可变参数

可变参数简单的来说就是参数的个数是可变的。使用…表示 类似于一个数组

public void f(参数1 参数2 …)

当你的参数不确定的情况下要将可变参数放在最后

动态绑定和静态绑定:

静态绑定(前期绑定):在程序执行之前就能够确定所在的类。通常由编译器实现。比如:static private final

后期绑定:程序在运行时,虚拟机根据具体的类型进行绑定(多态)

Object类

Object类时所有类的父类(基类)

Object常用的方法

1.equals():比较两个对象是否相等 默认==比较 可以比较基本数据类型和引用数据类型是否相等,如果比较的是基本数据类型,比较的是

字面的值。如果是引用数据类型,比较的是地址

2.toString():将对象转换成字符串 默认打印的是类名+@+十六进制hashcode值

3.hashCode():用于计算对象的hash值(用来描述对象的存储位置)

4.clone():用于创建一个相同的对象

5.wait():让线程等待

6.notify():随机唤醒因wait()等待的线程

7.notifyAll():唤醒所有的因wait()等待的线程

8.finalize():垃圾回收时调用该方法 确认对象被垃圾回收(GC自动回收)

接口(Interface)

java接口是一个完全抽象类,里面所有的方法都是抽象方法。其只用来定义行为规范,而不指定其具体的实现,具体的实现交由子类去实现。

特点:

接口中的方法都是抽象方法,不写也默认是 public abstract 修饰

接口中的所有属性默认都是常量,不写默认public static final修饰

接口不能实例化

接口没有构造方法

接口允许多继承(extends Person,Run)

子类可以同时实现多个接口

子类实现接口必须实现接口中的所有方法,或者将子类指定为抽象类或接口

抽象类和接口的区别

语法层面:

1.抽象类:可以有成员变量,构造方法,非抽象方法,而接口中只能有常量,没有构造方法,且所有的方法都是抽象的且只能是public abstract

2.抽象类只能是单继承,而接口与接口之间能实现多继承,且一个类可以实现多个接口。

3.抽象类继承自object,而接口不是。

4.jdk 1.8之后可以定义默认方法和静态方法。

使用层面:

子类实现接口之后,子类具有接口中的指定功能 (有一个的关系)

子类继承某一个类的时候,我们说子类是父类的一种(是一个的关系)

通常一类事物拥有共同的属性和行为,这个时候我们用抽象类来描述这一类事物

如果说只是定义某些行为,此时我们使用接口。

枚举

用来定义有限个对象的类型

//对象定义区:在该区域定义有限个对象,对象与对象之间用逗号隔开
//Color RED=new Color();

RED,YELLOW;
//类的内容定义区


private String name;

/*
* 枚举可以有构造方法,但是构造方法是私有的
* */
Color(){

}

单例模式:一个类只有一个对象。

单例模式可以通过枚举实现

java方法调用的是值传递还是引用传递

​ java中基本数据传递的是字面量的值,而引用数据类型传递的是地址值

包装类

java基本数据类型是没有属性和方法的,只有字面值。不具有面向对象的特征,为了解决这个问题,提出了包装类

包装类即对基本数据类型进行了包装,在类中定义了属性和方法。

基本数据类型与包装类的关系

byte ==>Byte

short==>Short

int==>Integer

long==>Long

char ==>Character

boolean==>Boolean

double==>Double

常见的方法和属性

1.MAX_VALUE:最大值

2.MIN_VALUE:最小值

3.构造方法

4…xxxxValue:

5.ValueOf():

6.parseInt():

一般在成员变量中使用包装类代替基本数据类型

public static void main(String[] args) {
    int i=10;
    change(i);
    System.out.println(i);
    int [] arr={1,2,3};
    change(arr);
    System.out.println(Arrays.toString(arr));
    change1(arr);
    System.out.println(Arrays.toString(arr));
    Integer integer=new Integer(11);
    Integer integer1=new Integer("22");
    System.out.println(integer+" "+integer1);
    byte b = integer.byteValue();
    System.out.println(b);

    Integer integer2 = Integer.valueOf("123");//将字符串装化成数字返回包装类
    int i1 = Integer.parseInt("123");//将字符串转换成数字返回成基本数据类型
    System.out.println(integer2+" "+i1);

    //自动装箱:将基本数据类型转化成包装类
    // 拆箱:将包装类转化成基本数据类型
        Integer i2=100;//自动装箱 会调用Integer.ValueOf(100)
        int i3=i2;//自动拆箱 会自动调用 包装类对象.intValue()     i2.intValue();


        int x=100;
    Integer integer3 = new Integer(100);
    Integer integer4 = new Integer(100);
    int i4=integer3;
    System.out.println(i4==integer4);
    //在-128与127之间返回的是true
    Integer integer5 = Integer.valueOf("11");
    Integer integer6 = Integer.valueOf("11");
    System.out.println(integer5==integer6);

    Integer m1=500;
    Integer m2=500;
    System.out.println(m1==m2);


}
public static void change(int i){
    //int i=实参
    i=100;
}
public static void change(int [] arr){
    arr=new int[]{100,200,300};
}
public static void change1(int[] arr){
    arr[0]=122;
}

Java常用Api

String用来表示字符串,java中所有的文本,文字内容都可以String来表示,字符串本质上是字符数组

对象创建

String 变量=“aaa”

String 变量=new String(“aaa”);

String和StringBuilder StringBuffer的区别

String是不可变的字符串,存储在方法区的字符串常量池中。

StringBuilder和StringBuffer是可变的字符串。存储在堆中

String重写了euqals,hashcode方法而StringBuilder和StringBuffer没有重写。

StringBuffer是线程安全的

StringBuilder的效率会比StringBuffer更高

StringBuffer和StringBuilder的toString实现方式不一样

String是如何实现不可变的

String 是final类,不允许被继承

String使用final char[]来存储内容

String内部没有提供修改内部char[]的方法

String为什么设计成不可变的

为了实现字符串常量池,达到字符串的共享

可以缓存字符串的hash值

不可变使得字符串更加安全

StringBuffer和StringBuilder的扩容机制

内部char[]的默认大小是16,每次扩容为原来长度的2倍加2 或者实际需要存储的大小

字符串转日期,日期转字符串

//MM表示月份 mm表示分钟 HH24小时制   hh表示小写12小时制
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = simpleDateFormat.format(date);
System.out.println(format);
try {
    //parse()里面的格式需要与SimpleDateFormat()指定的格式一样
    //字符串转日期
    Date d = simpleDateFormat.parse("2018年01月01日 08:00:00");
    System.out.println(d.toLocaleString());
} catch (ParseException e) {
    e.printStackTrace();
}

java异常

6.Java中的异常是程序运行过程中的一些错误。java中所有的异常继承自Throwable(表示可以往外抛出的)类,主要分为Error(错误)和Exception(异常)两大类,Error通常指程序无法处理的错误问题,比如 内存溢出等,而Exception 表示可以处理的异常。

Exception异常:java中根据其检测的时机又分为两种,分别是检查性异常和运行时异常。

a.检查性异常:是直接继承自Exception类,在编译期间便要对异常进行处理,否则编译不通过。处理的方式有两种,一种是try Catch 进行捕获(自己·处理),一种在方法上声明throws 抛出异常。(让调用者去处理)。

b.运行时异常:继承RuntimeException 类。编译期间不会报错,当程序运行时才会抛出异常。运行时异常通常是程序编写错误导致的。不强制要求进行try catch或Throws。

-c.两种处理方式

1)Try catch()语法:

try

{可能出现异常的代码

}catch( 异常类型 异常变量名)

{捕获异常之后的执行逻辑

}catch( 异常类型2 异常变量名2){捕获异常之后的执行逻辑…

}finally{不管是是否发生异常都会执行的代码块

}注意 :a. catch块表示一种精确匹配,一个catch块可以捕获其指定的类型及其子类。b. catch块可以有多个,但是顺序必须从小到大。

throws和throw的区别

throws:方法定义时声明异常

throw:方法执行时抛出异常

java集合

1.java集合的概念

可以用来存储多个引用数据类型对象的一种数据类型。

数组是定长的,操作长度不确定的数据类型时,非常不方便,而集合可以自动扩容,没有固定长度限制,且提供了丰富的API对集合中的数据进行操作

2.java集合分类

java集合都在java.util包下,集合顶层的接口有Collection(集合),Map(基于key value),interable(迭代器)

Collection接口下有三个常见的子接口List(有序,可重复的集合),Set(无序,不可重复的集合),Queen(队列,先进先出)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wla2TZko-1628130236150)(C:\Users\asus\Desktop\ssm学习笔记\img\java集合结构.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLtKxtet-1628130236153)(C:\Users\asus\Desktop\ssm学习笔记\img\Map.jpg)]

List集合

list是一个有序可重复的集合,所谓有序是指会保留元素的插入顺序,可以通过下标对数据进行获取

可重复是指:集合中可以存在内容相同的数据。(equals()相等)

ArrayList:基于数组实现,支持下标的随机访问,数据的修改和查询非常快,默认的初始容量为10,当数组长度不够时,会自动扩容,扩容为原来的1.5倍

LinkedList:基于双向链表,不支持随机访问,新增和删除元素速度快,查询速度慢(必须从头到尾或从尾到头访问)

Vector:基于数组实现,初始容量为10,与ArrayList类似,Vector是线程安全的,但是效率非常低,已基本弃用;Vector扩容为原来的2倍。

ArrayList集合特点

1.自动扩容 默认大小10 自动扩容为1.5倍

2.基于数组实现。可以随机访问,查询和修改速度快

3.有序可重复

4.线程不安全

java泛型

泛型的本质是参数化类型,将数据的类型当作一个参数进行设定,可以在运行时进行动态的指定传入数据的类型,使得程序更加灵活。泛型常用于类,接口,方法的定义。

public class 类名<泛型>{

}

内部类

匿名内部类

使用匿名内部类 new 接口名(){具体实现}

使得内聚性更高,如果比较器只在本类内部使用推荐使用这种方法

Comparator和Comparable区别

Comparable:为可比较的接口,接口中有一个CompareTo方法。需要在比较的类中实现Comparable接口,使得该类的对象之间可以进行比较。Comparable与类耦合在一起,适用于比较规则固定的场景

Comparator:为比较器接口。接口中有compare()方法。该方法需要传入两个可比较的对象。Comparator为单独定义,不需要定义在需要比较的类中。相对更加灵活,可以指定不同的比较规则

Map集合

Map是基于key value存储的数据结构,key值不可重复,value值可以重复

常见的子类

hashMap:底层结构基于key-value存储,key值唯一不可重复,底层是基于散列表实现,即数组加单向链表的形式。jdk1.8之后还引入了红黑树结构。当链表长度大于8时,会转化成红黑树

数据存储时无序的

数组的默认长度为16,加载因子是0.75(当容量达到现有容量的0.75时进行扩容)。每次扩容为原来的两倍。

hashTable:线程安全的集合,效率较低,一般不推荐使用。底层实现原理与Map类似。key和value值都不允许为null

linkedHashMap:是hashMap的一个子类,在hashMap基础之上增加了一个双向链表,用来保存对象的插入顺序,是有序的。

TreeMap:基于红黑树存在的map。map会根据指定的比较规则对数据进行自动的排序。TreeMap的key值必须实现Comparable接口,或者创建TreeMap的时候指定key的比较器,判断key是否重复,是判断key值的大小是否相等

ConcurrentHashMap:与hashMap类似,但是是线程安全,但是效率比HashTable更高,在并发情况下建议使用concurrentHashMap

hashMap put存储数据的过程:

1.根据key值得hashCode值计算存储的数组下标位置。

2.如果该位置没有值,则直接将node节点存入

3.如果该位置有值,发生hash冲突,则遍历该位置的链表,则与链表中的元素key值逐个进行equals比较

4.如果不存在equals相等的,则链接到链表的最下面,否则替换对应key原来value的值。

equals和hashCode的关系

要求equals相等时,hashCode值必须相等==》hashCode值相等,equals一定不相等

hashCode值相等时,equals不一定相等(hash冲突的情况)

equals不相等时,hashCode值可能相等

所以要求重写equals()方法时必须重写hashCode方法。

hashMap()的遍历
 //先获取到entrySet(节点集合),再根据entrySet进行遍历
        //返回所有节点的集合
        Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey()+" "+entry.getValue());
        }
//        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
//        while(iterator.hasNext()){
//
//        }
        //拿到keySet(所有的key集合),根据key去遍历所有的value
        Set<String> strings = hashMap.keySet();
        for (String string : strings) {
            System.out.println(string+":"+hashMap.get(string));
        }

        Collection<Integer> values = hashMap.values();
        for (Integer value : values) {
            System.out.println(value);
        }

Set集合

Set集合为无序不可重复的集合,是Collection接口的子接口 不能get()值,只能通过迭代器取值

HashSet:内部通过hashMap实现,HashSet存入的值会当作key值添加到HashMap;

LinkedHashSet:有序,(保留元素的插入顺序),不可重复的集合

TreeSet:会对数据进行排序

Java线程

进程和线程

进程:整个程序执行的过程中,程序持有的资源上下文和线程的合集。

一个进程包含多个线程。进程是系统进行资源分配和调度的基本单位

通常一个程序有一个进程

线程:是进程中完成特定功能任务的一个程序单元。线程是cpu调度的基本单位。

Java中的线程

Thread类表示线程,通过Thread类的start()方法可以启动一条线程,java中程序的执行必须通过一个线程来调用。默认main方法执行会自动启动一个线程 (主线程)。

创建线程的方式

继承Thread类,并重写run方法

实现Runnable接口,创建Thread时将Runnable的任务对象传入

实现Callable接口,将Callable的任务转换成Runnable任务并传入Thread;

public class CallableTask implements Callable<Integer> {
    int count;
    @Override
    public Integer call() throws Exception {
        for (int i = 0; i < 101; i++) {
            count+=i;
        }

        return count;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建Callable的任务
        CallableTask callableTask=new CallableTask();
        //将Callable转换成FutureTask任务
        FutureTask<Integer> futureTask=new FutureTask(callableTask);
        new Thread(futureTask).start();
        //阻塞等待,获取Callable任务执行结果
        Integer integer = futureTask.get();
        System.out.println(integer);

    }
}

线程池:

当线程启动之后,线程的执行顺序任意情况都有可能;线程之间互相抢占cpu执行权,获取的cpu执权后,能够执行的时间也是不确定的。

线程的Api的方法

get/setName()设置线程名

Thread.sleep() 睡眠(这行代码由哪个线程执行,哪个线程就睡眠)

Thread.currentThread();//获得当前线程

setPriority();设置某个线程优先级,值越大,优先级越高

yeild让出cpu执行权,进入就绪状态,回去继续竞争cpu执行权

A.join()会让当前线程等待A线程执行完毕之后在执行,当前线程会进入休眠

interrupt():可以将线程的中断标示设置为true。用于关闭线程。当线程因调用(join,sleep)处于等待状态时则会抛出中断异常,中断其阻塞状态。捕获异常之后继续运行

isInterrupt():返回线程的中断标识。false|true

isAlive 是否还活着(当线程调用了Start()方法,并且线程没有结束,则为true),线程结束之后则为false

setDaemon(true):是否设置线程为守护线程。

getState:获得线程的状态

线程分类:

用户线程:自己创建的线程默认为用户线程,jvm退出必须等待所有的用户线程执行完毕之后在退出

守护线程:当所有的用户线程结束之后,jvm的退出不需要等待守护线程执行完毕。例如GC垃圾回收器

线程的状态:

新建状态:(new) 刚刚创建好Thread对象,还没调用start()

就绪状态:(READY):调用start()方法。但是还没有获取cpu的执行权正式运行。

运行中状态:RUNNING 线程获取cpu执行权,运行run方法。

等待状态:调用wait join会进入等待状态,无限期等待

超时等待:当调用sleep,wait,join 指定了等待特定时间的方法时会进入一个超时等待,等待时间结束之后就会进入就绪状态。

阻塞:当线程因未获取到同步锁而停止运行时就会进入阻塞状态

终止:当线程运行完毕之后进入死亡状态。

CopyOnWriteArrayList是线程安全的,并且是读写分离的(更多用于读多,写少)

java线程安全问题

线程安全:当多个线程并发执行,代码的运行结果总是与单线程情况一致,此时我们说是线程安全的,否则线程不安全

线程不安全:当多个线程并发执行某个程序时,其结果出现异常的情况(与预期结果不一致),我们说是线程不安全,线程安全问题通常是多个线程同时操作同一份数据导致的。

线程安全问题的解决:

尽量避免同时操作同一份数据。

添加synchronized锁,synchronized为java的同步锁关键字,主要用法有两个

1,在方法上添加synchroized,使得整个方法是同步安全的。当线程执行同步方法时,便可以获得对应的锁对象,其他线程必须等待 该线程执行完毕对应的同步方法,并释放锁之后才能执行。

2.添加在代码块上,对其包裹的代码片段进行加锁,写法为:

sychronized(锁对象){

同步代码块

}

锁对象可以是任意的引用数据类型对象,常见的锁对象有this class

this:只有使用同一个对象调用对应的方法才会同步。

class:所有的对象调用对应的方法都是同步的

添加Lock锁:Lock是java中的锁接口,用来给代码块进行加锁,常见的子类有ReentrantLock。Lock类提供了两个方法:lock加锁,unLock释放锁

lock():给代码加锁,

unlock():释放锁

tryLock():尝试获取锁

死锁

当线程间资源交叉使用,线程互相等待对方释放锁资源,则会产生死锁

死锁的四个条件

互斥条件(同一时间一个资源只能被一个对象持有)

请求与保持条件(一个线程应请求资源而阻塞时,不会释放已经持有的锁对象)

不剥夺条件:一个线程获得的锁资源如果没有执行完,不能被强行剥夺

互相等待:线程之间相互等待对方释放锁,才能继续执行

如何避免死锁:

尽量避免锁之间的嵌套

持有的锁的时间尽量短

使用可以中断的锁

try {
    //如果一定时间内没有获取到锁,则返回false
    boolean b = lock1.tryLock(3, TimeUnit.SECONDS);
    if(!b){
        System.out.println("获取锁失败,放弃了");
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

wait() notify() notifyAll()

wait():只能在线程持有锁对象的情况下,由锁对象调用,会使线程进入等待状态,并释放对象锁

notify():在持有对象锁的情况下,由锁对象调用,会随机唤醒一个因调用wait方法而进入等待状态线程

notifyAll():在持有对象锁的情况下,由锁对象调用,唤醒所有的因调用同一个锁对象的wait方法而进入等待状态的线程。

线程池:

线程池在创建之后便会保有一定数量的线程。我们将任务提交到线程池后,线程池会自动委派线程去执行对应的任务,不需要我们自己去创建线程。

好处:

可以有效地管理线程资源

可以节省线程创建的时间,提高效率。

jdk自带四种常见的线程池

Java中通过Executors类来创建线程池

1.定长线程池:可以创建固定长度的线程池。当任务超过线程数量时,会将任务放入队列中进行等待 newFixedThreadpool

2.可缓冲的线程池:newCachedThreadPool 可缓存的线程池,线程的数量会根据任务的多少而动态改变,最大线程数据为int 的最大值,如果线程没有执行任务,默认一分钟之后执行

3.周期性执行: newScheduledThreadPool:周期性执行线程,可以指定延迟执行,或者周期性执行

4.单线程的线程池:newSingleThreadExecutor:单线程线程池,只有一个线程的线程池;

5.自定义线程池 new ThreadPoolExecutor(int corePoolSize,//核心线程数,不会被回收的
int maximumPoolSize,//最大线程数
long keepAliveTime,//最大空闲时间
TimeUnit unit,.//时间单位
BlockingQueue workQueue //任务阻塞队列

)

public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        test3();

    }

    //定长线程池
    public static void test() throws InterruptedException {
       // ExecutorService executorService = Executors.newFixedThreadPool(4);//创建长度为四的定长线程池
        ExecutorService executorService = Executors.newCachedThreadPool();//可缓存的线程
        //向线程中提交任务
        for (int i = 0; i < 20; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
//                    try {
//                        Thread.sleep(new Random().nextInt(5000));
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
                    System.out.println(Thread.currentThread().getName()+"执行任务");
                }
            });

        }
        executorService.shutdown();
    }
    //
    public static void test1() throws InterruptedException {
        //定时任务
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"当前时间"+System.currentTimeMillis());

            }
            //initialDelay:延迟5s后执行代码
            //period:每次执行的间隔时间
        },5,1000, TimeUnit.MILLISECONDS);
        Thread.sleep(3000);
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"延迟任务,并且只执行一次");
            }
        },2,TimeUnit.MILLISECONDS);
        scheduledExecutorService.shutdown();

    }
    //单线程,一条线程执行10个任务
   public static void test3() throws ExecutionException, InterruptedException {
       ExecutorService executorService = Executors.newSingleThreadExecutor();
       for (int i = 1; i < 5; i++) {
           executorService.submit(new Runnable() {

               @Override
               public void run() {
//                   try {
//                       Thread.sleep(1000);
//                   } catch (InterruptedException e) {
//                       e.printStackTrace();
//                   }
                   System.out.println(Thread.currentThread().getName()+"任务执行中");
               }
           });
       }


       Future<Integer> submit = executorService.submit(new Callable<Integer>() {

           @Override
           public Integer call() throws Exception {
               int count = 1;
               for (int i = 1; i < 5; i++) {
                   count *= i;
               }
               return count;
           }


       });
       System.out.println(submit.get());
       List<Callable<Integer>>  list = new ArrayList<>();
       list.add(new Callable<Integer>() {
           @Override
           public Integer call() throws Exception {
               int count=0;
               for (int i = 0; i < 10; i++) {
                   count+=i;
               }
               return count;
           }
       });
       list.add(new Callable<Integer>() {
           @Override
           public Integer call() throws Exception {
               int count=1;
               for (int i = 1; i < 5; i++) {
                   count*=i;
               }
               return count;
           }
       });
       //单个线程调用invokeAll()提交一个集合的任务
       List<Future<Integer>> futures = executorService.invokeAll(list);
       for (Future<Integer> future : futures) {
           System.out.println(future.get());
       }
   }
}

Excute 和submit invokeAll都可以用来提交任务

Excute:没有返回值,只能执行runnable任务

Submit()可以有返回值,可以提交Runnable和Callable任务

invokeAll:可以提交Callable任务合集,并返回List结果集。

Sleep和Wait的区别

出处:sleep是Thread的静态方法,wait是Object类的方法

作用:sleep会让线程睡眠指定时间,进入超时等待状态,而wait如果不指定时间,会让线程停止执行,进入等待状态(直到notify或 notifyAll才能唤醒)

sleep不会释放对象锁(在同步代码块里面调用sleep他不会释放锁),而wait会释放对象锁

Sleep可以在任意地方调用,二wait必须在持有锁对象的时候,由锁对象调用,否则会抛出异常

Java Io流

简介:

I:input输入的意思

O:output输出的意思

IO流:java用于读取和写入文件的类(API)

Stream:java中的IO操作类通常都是以Stream命名

JavaIO分类:
按功能分

节点流:直接操作对应的对象存储介质的流

处理流:需要传入节点对象,对节点进行增强的流

按流向分:

输入流:inputStream:用来读取内容到程序中去

输出流:outPutStream:用来从程序向外输出内容

按操作方式分

字节流:以字节为单位进行操作的流

字节输入流:

inputStream:字节输入流,抽象类,定义了字节输入流通用方法

常用方法:

int read()读取一个字节,并且以int类型返回,当读到末尾时返回-1,文件末尾。(当文件中没有数据时)

int read(byte b[ ]):读取一个数组(每次读取数组字符长度的字节),并存入b[ ]并返回读取到的字节数量

close():关闭流,每个流用完之后必须进行关闭,最好放到finally中。

available():返回预估的剩余可读取的字节数

常见的子类:

FileInputStream:用来读取文件

BufferInputStream:

字节输出流(OutputStream):

以字节为单位进行输出,抽象类,定义了字节输出流通用方法

write(int b):写入一个字节

write(byte[] byte):写入一个字节数组

write(byte[] int off,int len) :写入一个字节数组,从off位置开始的len个字节

flush():将缓冲区的内容全部清空,写入文件

常见子类:

FileOutputStream(文件字节输出流):将内容写入文件的流

BufferOutputStream:

字节输出流

字符流:以字符为单位进行操作

字符输入流(Reader)

FileReader:文件字符输入流,读取文件,但是不能设置编码格式

InputStreamReader:将字节输入流转化成字符输入流

BufferedReader:字符缓冲流

//读取一行内容,返回一个字符串读取完毕,返回 null
System.out.println(bufferedReader.readLine());

字符输出流(Writer)

FileWriter:字符文件输出流

fileWriter.write("你好呀");
fileWriter.append("你好呀").append("!");//链式操作

OutputStreamWriter:将字节输出流转换成字符输出流

BufferWriter:增加了缓冲区的字符输出流

File对象

File类用来表示文件或目录。并提供了API方法来获取文件的信息,比如文件名,路径,大小等信息,但是不能改变读写内容

常用的API方法:

序列化与反序列化

序列化

将java对象转化成字节序列的过程。使用ObjectOutputStream实现

反序列化:

将字节序列转化成java对象的过程。使用ObjectInputStream实现

要求: 序列化的类必须实现序列化接口。

1.如果没有实现则会抛出java.io.NotSerializableException

2.序列号版本号,如果不显示的定义出来,那么每次对类的修改,会生成一个新的序列化版本号,当反序列化时,版本号如果不一致,则会抛出异常

可以在类中定义版本号,以避免此类问题。

序列化作用:

将对象序列化到文件中进行存储。(缓存信息)

将对象在网络上进行传输。

Clone

实现Cloneable接口

clone() 和反序列化 可以复制一个对象,对象的创建不会调用构造方法

克隆默认是浅拷贝 、、

反序列化是深拷贝

clone和反序列化

浅拷贝:会创建一个新的对象,但是对象中的引用类型的成员变量是与原对象的成员变量为同一个对象,没有进行复制,新拷贝出的对象属性的修改会影响到原对象

深拷贝:不但会创建一个新的对象,对象中的引用数据类型的成员变量也会创建一个新的对象。新拷贝出的对象属性的修改不会影响到原对象

clone可以用来复制一个类,对应的类需要实现Cloneable接口,默认情况下属于浅拷贝D

反序列化也可以复制一个对象,需要实现Serializable接口 不会调用构造方法,为深拷贝

字节流和字符流的区别

读取的方式不一样:字节流是以字节为单位进行的操作,而字符流是以字符为单位进行操作

可操作文件不一样:字节流可以操作任意文件,而字符流只能操作文本文件

字符流底层是通过字节流进行操作,且增加了字符缓冲区,读取文本文件的效率更高。

掌握:

File类

明白Io流的流向和分类

怎么读取和写入文件

序列化和反序列化

注解和反射

java的反射机制是指在程序的运行过程中,对于任意一个类,都能知道该类的属性和方法。对于任意一个对象都能调用其任意的属性和方法,这种动态的获取信息和调用方法的功能,就称之为反射

java反射中涉及到的类
反射的使用

1.获取Class对象,基于Class操作(方法区)

获取Class对象方式

Class.forName(“类的路径”)

类名.class

对象.getClass();

2.通过Class对象调用API方法

a.获取类的信息,类名,父类,父接口

b.获取类属性

c.获取类方法

d.创建对象(newInstance)

3.调用对象的方法和属性

field.get(object);//获得属性对应的值

Socket编程

1.两台计算机通信的过程

ip地址:用来定位计算机(每台电脑会有一个ip地址)Ip地址又分为内网ip和外网ip

内网ip:局域网 在某个局部范围内使用的网络

互联网ip: 由宽带服务提供商来进行提供,接入互联网,可以访问互联网资源,可以被其他互联网计算机访问到

在cmd中执行ipconfig查看本电脑的局域网ip地址(外网的服务器有固定的外网ip地址)

ping ip|域名 向对应的计算机发送数据包,测试本机与指定的计算机的网络连通情况

网关:配置路由器的ip地址

DNS:域名解析,解析域名,找到其他对应的ip地址

协议:http tcp ftp规定数据传输和解析格式

端口:区别同一台计算机上的不同的应用程序。 范围:0-65535 一般0-1023 为系统程序使用。

2.socket套接字编程

Socket是用于两台计算机之间进行网络通信的对象

Socket分为两部分

1.服务器端(Server) 对外提供服务,等待客户端进行连接 ,当有客户端进行连接之后,便可与对应的客户端进行连接

2.客户端(Client) 根据服务器的ip地址和端口号,与服务器端去建立连接

jvm内存模型

线程共享区:

jdk1.8新特性

1.允许使用default和static方法
2.函数式接口:只有一个抽象方法的接口,接口上会添加@FunctionInterface注解进行标识。比如常见的Runnable Callable Comparator
3.Lamdba表达式,主要用来简化函数时接口匿名内部类的编写

(参数1,参数2)->{

//逻辑代码

}

4.方法引用

当lambda表达式中的方法执行的逻辑是某个方法中已经定义时,通过::操作符,去引用对象或类的方法

常见的几种引用方式

类名:: 方法名

对象:: 方法名

5.Stream流操作

Stream流主要是对一组数据(数组,集合)进行筛选,去重等操作

Stream使用的三个步骤

1.获得Stream对象

a.集合中的Stream()方法

2.指定中间操作(去重,筛选,映射)

3.指定终止操作:返回结果

6.新的日期API

新的日期API都是线程安全的

LocalDate:用来表示年月日

LocalTime:用来表示时分秒

LocalDateTime:表示年月日时分秒

Clock():时钟

Duration:日期操作

Period:日期操作 计算日期间隔

//年月日
LocalDate now = LocalDate.now();
//年月日时分秒
LocalDateTime now1 = LocalDateTime.now();

//时分秒
LocalTime now2 = LocalTime.now();
LocalTime now3 = LocalTime.of(12, 0, 0);
LocalDateTime of1 = LocalDateTime.of(now, now2);
System.out.println(now2);
//of方法创建指定日期的方法
LocalDate of = now.of(2019, 10, 1);
System.out.println(of);
LocalDateTime localDateTime = now1.plusDays(11);
System.out.println(localDateTime);
LocalDateTime localDateTime1 = localDateTime.minusDays(11);
System.out.println(localDateTime1);
//对日期进行格式化
String format = localDateTime1.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(format);
//将字符串转化成日期
LocalDate parse = LocalDate.parse("2021/03/31", DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(parse);
//with 设置月份,年份等
LocalDate localDate = parse.withMonth(2).withYear(2025).withDayOfMonth(28);
System.out.println(localDate);

//计算日期差 后面减前面
Period between = Period.between(of,localDate);
System.out.println(between.getYears());
System.out.println(between.getMonths());

//计算时分秒 不能出现年
Duration between1 = Duration.between(now2,now3);
System.out.println(between1);

//时区
LocalDateTime localDateTime2= LocalDateTime.now();
System.out.println(localDateTime2);
//时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
System.out.println(availableZoneIds);
//设置时区
ZonedDateTime zonedDateTime = localDateTime2.atZone(ZoneId.of("America/Sitka"));
System.out.println(zonedDateTime);

对象:: 方法名

5.Stream流操作

Stream流主要是对一组数据(数组,集合)进行筛选,去重等操作

Stream使用的三个步骤

1.获得Stream对象

a.集合中的Stream()方法

2.指定中间操作(去重,筛选,映射)

3.指定终止操作:返回结果

6.新的日期API

新的日期API都是线程安全的

LocalDate:用来表示年月日

LocalTime:用来表示时分秒

LocalDateTime:表示年月日时分秒

Clock():时钟

Duration:日期操作

Period:日期操作 计算日期间隔

//年月日
LocalDate now = LocalDate.now();
//年月日时分秒
LocalDateTime now1 = LocalDateTime.now();

//时分秒
LocalTime now2 = LocalTime.now();
LocalTime now3 = LocalTime.of(12, 0, 0);
LocalDateTime of1 = LocalDateTime.of(now, now2);
System.out.println(now2);
//of方法创建指定日期的方法
LocalDate of = now.of(2019, 10, 1);
System.out.println(of);
LocalDateTime localDateTime = now1.plusDays(11);
System.out.println(localDateTime);
LocalDateTime localDateTime1 = localDateTime.minusDays(11);
System.out.println(localDateTime1);
//对日期进行格式化
String format = localDateTime1.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(format);
//将字符串转化成日期
LocalDate parse = LocalDate.parse("2021/03/31", DateTimeFormatter.ofPattern("yyyy/MM/dd"));
System.out.println(parse);
//with 设置月份,年份等
LocalDate localDate = parse.withMonth(2).withYear(2025).withDayOfMonth(28);
System.out.println(localDate);

//计算日期差 后面减前面
Period between = Period.between(of,localDate);
System.out.println(between.getYears());
System.out.println(between.getMonths());

//计算时分秒 不能出现年
Duration between1 = Duration.between(now2,now3);
System.out.println(between1);

//时区
LocalDateTime localDateTime2= LocalDateTime.now();
System.out.println(localDateTime2);
//时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
System.out.println(availableZoneIds);
//设置时区
ZonedDateTime zonedDateTime = localDateTime2.atZone(ZoneId.of("America/Sitka"));
System.out.println(zonedDateTime);

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值