javaSE笔记

jre的概念:java运行时的的环境
jdk的概念:java程序开发工具

注释

  1. 单行注释://
  2. 多行注释:/* 注释内容 */
  3. 文档注释 : /** 注释内容*/

变量规范

  1. 可以是数字、英文(大小写)
  2. 不能数字开头
  3. 不能是关键字
  4. 不能有空格
    变量可以是合法标识符。

常见关键字

所有关键字都是小写的
true false 不是关键字
在这里插入图片描述

常见转义字符

\b 退格
\n 换行
\t 制表符,相当于tab
\r 回车
\ 反斜杠
\’ 单引号 单引号可以不用转义字符进行转义也能打印
\” 双引号

运算符

1、+号 :数学运算 字符串连接符号
+号 两边是字符串,连接起来还是字符串
2、% :取余符号和除数不能为零 ,属于算数异常
3、a ++ : a=a+1 ,直接用a++的表达式,则会先使用a自己(先没有自 增),然后再自增
4、a=a++; 自增的动作内部,是有一个临时变量
b = a++ + a–:从左到右阅读 、a++先用自己,然后自增需要做掉的,a实 际上是变成2,但后面+号操作时左半部分还是用的1、再用a–时,a已经变成2了,b=1+2,a–的动作要做完的,a最后变成1。
5、++a: 如果是独立行,放前放后是无所谓的,出来的结果是一样的;先自增,后用自增后用的值。
这段表达式是在一个方法或者一大段表达式
1、前置 先自增或自减,然后再用
2、后置 先用自己,在做自增自减
x=x+1等价于x+=1 x+=1强制转换数据类型
6、: 判定 11 不能独立书写,直接用在方法里或赋值给一个变量
7、短路与&&: 左边的式子是false,则不执行右侧的表达式
8、通路与&: 全真则真,有假则假 左右的表达式都需要执行掉
9、通路或| :有真则真
10、短路|| :前真则短,前假则通。
11、异或 ^ :不同为真,相同为假。
12、按位与 按位& :根据二进制计算
13、按位或 按位| :根据二进制计算
14、按位取反 :先取相反数再减一
15、带符号左移<< 按二进制计算
16、带符号右移>>
17、三目(三元)运算符:
格式: boolean表达式?表达式1 :表达式2;
Scanner:从控制台获取一个数字(字符串等都可以)的类
Scanner scanner =new Scanner(System.in);
System.out.println(“请输入一个年份:”)
int num=Scanner.nextInt();
从Scanner类获取一个数字,赋值给一个变量
在类定义之前,需要先做一次Scanner类的导包操作
import java.util.Scanner;
byte d =1+2;编译器优化
byte d=d1 +d2;报错
Scanner :扫描器
bigdecimal 大数数据类型 应用于金钱或计算要求较高的场景下
流程控制
if语句 格式:
if(boolean)
{ 一条语句};
if语句只包含一条结果语句
if(){}else{语句体1};
if(){}else if{}else{};
用Scanner接收一个字符串:sc.next();sc.nextline();
字符串比较相等不能使用==,需要使用.equals()来完成。
switch表达式允许整型 byte short int ,不能是long,也可以是char、string 、enum
switch的特殊情况:1、如果没有break,
2、如果没有default,或者default出现的位置不在最后。default可以嵌套在case的任何位置。
case的值必须不一样

循环语句
while(){
}
do…while();至少执行一次
for(初始化语句;判断条件语句;控制条件语句){
循环体部分;
}
如果定义变量for()内部,则这个变量是一个局部变量,作用范围只在当前所在的for内部。
初始化语句,多个变量,则用逗号隔开,不能用分号。
第一个变种版本:把初始化语句提出来
第二个变种版本:将判断条件语句用if表示放在循环语句这。
第三个变种版本:控制条件语句也被提出来放在循环体内部。
for循环嵌套:
break 中断
退出当前循环
跳出单层或多层循环
带标签的跳出
break一旦被执行到,则会停止和break最接近的一个循环体
break 再多重循环中,只会跳出当前循环体中。
如果break要跳出多重循环时,需要在for前面加标签,格式:标签名 :for
常规来说是单独使用的,在嵌套的循环体中才有可能会使用break.
break直接紧邻的后面不能有语句 ,否则无法编译。
continue 继续
退出本次循环
return 返回
结束一个方法

内部:属性 方法(函数)
System java lang包提供的一个类
out 输出“对象”本质上也是一个类
println 这个是out对象的一个方法
调用方法,都是对象或者类.出来的
普通类不一定需要主方法的

修饰符 常规上是4个 :public default protected private
返回值类型:8个基本数据类型、对象性(String)、空类型(void)
方法名要求:见名知意、小驼峰命名printNumber
主方法要调用自己写的这个方法,额外给这个自定义的方法加一个关键字在public后面,static
方法里不能有方法 只能与main平行
方法参数(形参和实参)

异常处理机制:try catch(Exception e)
扩展数组长度: 数组名=Arrays.copyOf(数组名,数组新长度);
System.Arraycopy(原数组,原数组起始位置,新数组,新数组起始位置,原数组要拷贝的长度);
随机数的产生:Random random=new Random();
random.nextInt(99)+1;
jdk排序 直接做“自然”排序即从小到大排序:Arrays.sort(数组名);(int型)
System.out.println(Arrays.toString(arr));
foreach:数组循环–增强型
foreach 实际上书写还是for,本身是一个语法塘
for(单个元素的数据类型 单个元素的变量:数组名){
//循环体
要使用每一个数据、直接用单个元素的变量,不需要利用下标来获取
}
fori 着重是下标
foreach 忽略掉了下标 for(int x:a){}

面向对象(OOP(Object Oriented programming))

查找算法:二分查找法
大量用到一个包下的多个Java文件,则直接调用import java.util.*;
面向对象思想:
对象的概念和组成:属性和方法
类:抽象
数据抽象 :类的属性
过程抽象:类的方法
Data birthday的数据类型
所有属性(只要不是静态final),正常变量名都应该是小驼峰写法
定义类的方法:
public class 类名{
//方法定义五要素
访问修饰符 返回值类型 方法名(参数列表){
//方法体
}
}
对象使用:
创建对象: 类名 对象名 =new 类名();

对象型即是引用类型
this 关键字 用的是全局变量
同一时间只能导入一个包,如果别的包的同名类也要使用,则需要使用全包路径(或者全限定类名):cn.yyy.A a1=new cn.yyy.A();
NullPointerException 空指针异常 只有运行之后才会报错 只能加上if逻辑语句
如何打印对象信息:定义一个方法public String toString(){
return “姓名:”+name;
}//固定方法 快捷键:alt+insert
同一个类中静态方法不能调用普通方法,反过来则可以
静态方法可以调用静态方法

this关键字:指代当前对象
在方法中写入可变参数 typename… 参数名
本质就是传递了一个数组的结构
用了可变长参数的写法,后面不能再有别的形参
构造方法没有返回值的
如果有多个参数的构造器版本,则如果后期想用空参的版本,则必须显示写出
多参版本一个都没有,则空参版本也可以省略
构造器的快捷方式:alt+insert
this();//一个构造器调用另一个构造器this(screenSize);
用了this()构造器来指向别的构造器时,必须写在当前构造器结构体的第一行

封装
javabean
POJO 纯净简单的对象 正常不带main
全部私有化掉属性private
数组拷贝常见函数:System.arraycopy(原数组名,0,目标数组名,0,原数组长度);
Arrays.copyof(原数组名,新数组长度)
数组排序:jdk排序:Arrays.sort();
冒泡排序(从小到大排序):import java.util.Arrays;
public class Maopao {
public static void main(String[] args) {
int [] a= {4,5,9,2,1,30,0,12};
for (int i = 0; i < a.length-1; i++) {
for (int j = 0; j <a.length-1-i ; j++) {
if(a[j]>a[j+1]){
int temp = a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
System.out.println(Arrays.toString(a));
}
}
选择排序:
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int [] a= {4,5,9,2,1,30,0,12};
for (int i = 0; i < a.length-1; i++) {
for (int j = i+1; j <a.length; j++) {
if(a[i]>a[j]){
int temp = a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
System.out.println(Arrays.toString(a));
}
}
类的对象 实例对象有区别
浮点数除以零得到的结果可能是正无穷或负无穷

数组结构:int[] a=new int[5];
压栈:先入后出
二维数组:int[][] a=new int [3][];行数必须写,列数可以不写;
static(静态关键字): 类的内部 属性和成员方法
加了static ,静态成员 静态方法
所有被static修饰的成员或者方法,都应该利用类名来调用
this 不能在静态方法内部使用,指向不到实例对象。
静态代码块:与成员、方法同级
static {
该位置的语句,会被自动加载”一次“
类多次实例对于静态代码块的执行次数无影响,只会执行一次
静态块会最先执行
可以有多个静态块
}
普通方法块:{
需要依赖实例对象;
优先执行于构造器;
前提是需要实例调用;
}
static 可以用于静态导包

继承
子类继承父类的属性和行为(不是所有的都能继承过来的),子类可以访问父类中的非私有的属性和行为。
用extends关键字表示继承
public class 子类 extends 父类{

}
单继承模式is-a的关系 java不允许多继承
用final修饰的类不能被继承
成员变量不重名 成员变量重名时优先使用子类的属性。
在子类中访问父类的非私有成员变量时,需要使用super关键字进行调用。
重写:发生在子父类 除了访问修饰符(不能比父类的修饰范围还要小)(绝大部分情况还是一样的),其他所有的部分都一样 覆盖注解一般性会加上 @Override,加在子类方法上
重写的快捷键:Ctrl+O
super.say() 代表子类调用say方法时,会自动调用超类的say方法
构造方法不能重写。
子类的实例需要父类的构造方法
子父类加载顺序:父类静态方法>子类静态方法>父类普通>父类构造>子类普通>子类构造

造型
向上造型(向上转型):若是重写方法 则仍然是实现子类方法,若不是则反之。
父类引用指向子类的对象。
多态的体现 小类型转到大类型 之后只能拿到父类的信息。
向下造型:通过强制转换将父类类型变量转换为子类型变量。
子类 子类=(子类)父类引用;
instanceof:类型判定关键字
抽象类是做在父类上 行为抽象化(只要声明,不要实现),全部交给子类实现(子类必须实现)
abstract关键字加在class前面 ,成为抽象类 抽象方法 不需要写方法体。在子类中实现就是重写抽象方法。 有抽象方法的类------->必然该类是抽象类 类是抽象类------->内部可以没有抽象方法。
抽象类并没有完全抽象,称为半抽象。接口为全抽象。
abstract 和final不能同时使用。

接口
引用类型,是抽象方法的集合。
引用数据类型:数组、类、接口
接口的使用,不能创建对象,但是可以被实现(implements,类似于被继承)
接口定义:interface关键字
public interface 接口名称{
//抽象方法
//默认方法
//静态方法
//私有方法
}
接口中不赋值被理解成变量,接口中不允许
接口中赋值被理解成常量,默认隐含了public static final
接口没有构造器
接口默认是不能实例化的 接口本质上是可以new的
接口可以继承的 也是单继承。
重名的抽象方法在子类实现中只会重写一次
两个接口内部如果有重名的默认方法,此时需要在实现手工重写出这个重名的方法
子接口可以继承接口的所有方法(除私有方法)
接口中不可以写静态代码块和普通代码块
abstract不能和private一起用 静态抽象、最终抽象也不可以起用
重写注意点:继承(子父类)、接口实现;方法名一致、参数列表一致、返回类型一致、访问修饰符在子类上一致(可以放大)、注解@Override,编译时让jvm检查是否从父类重写过来的。
不能重写父类的构造方法 构造器可以重载
1.方法重载判断: (1):方法名必须相同。 (2):形式参数个数不同或者参数类型不同(满足其中一个条件就行)。和修饰符、返回类型无关。
2.方法重写判断: (1):访问修饰符权限一定要大于被重写的方法。(当被重写的方法被私有(private)时无法重写)。
集合:ArrayList list=new ArrayList<>();
list.add(s1);

多态
继承或者实现
方法的重写
父类引用指向子类对象
多态体现的格式:父类类型 变量名 =new 子类名();

权限和内部类
final :不可改变。可以用于修饰类、方法和常量。
String Math Scanner 类是一个最终类
final 不能覆盖 父类出现了的方法,子类就不能覆盖同名方法了。

权限修饰符 :public protected default private
publicprotecteddefault(空的)private同一类中√√√√同一包中(子类与无关类)√√√不同包的子类√√不同包中的无关类√
可见,public具有最大权限。private则是最小权限。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
成员变量使用 private ,隐藏细节。成员常量一般性是public
构造方法使用 public ,方便创建对象。
成员方法使用 public ,方便调用方法。
小贴士:不加权限修饰符,其访问能力与default修饰符相同

内部类
内部类定义在外部类内部,通常只服务于外部类,对外部不具备可见性,内部类可以直接调用外部类的成员及方法(包括私有的)。
创建内部类对象格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
内部类的私有,在外部类也能正常获取。
静态内部类与外部类可以当做是平级的
静态内部类是获取不到外部类的方法和变量
外部类通过内部类的实例调用属性和方法 outer.inner a=new outer.inner();
匿名类:new 类名();
匿名内部类:本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。
语法:
SuperType父类名或者接口名 obj=new SuperType父类名或者接口名(…){
// 方法重写
@Override
public void method() {
// 执行语句
}
}
SuperType——用匿名类实现的接口或所继承的父类型声明的引用
(……)构造方法所需要的参数
{}匿名类,可以在里边定义成员变量或方法
使用匿名内部类完成回调:
接口传递 Callback 回调

常用的类
String类:
字符串常量池在堆上;
jvm优化,字面量拼接的问题在"编译期”jvm已经提前完成
final String
equals() 判断字符串。
忽略大小写比较字符串:equalsIngoreCase();
以什么字符开头:startsWith("");
以什么字符结尾的:endsWith(" ");
默认所有的对象不覆盖equals,则比较内存地址,覆盖过equals走自己的逻辑;
获取功能的方法:
public int length () :返回此字符串的长度。
public String concat (String str) :将指定的字符串连接到该字符串的末尾。
public char charAt (int index) :返回指定索引处的 char值。
public int indexOf (String str) :返回指定子字符串第一次出现在该字符串内的索引(找不到返回-1)。
public int lastIndexOf (String str) :返回指定子字符串最后一次出现在该字符串内的索引(找不到返回-1)。
public String substring (int beginIndex) :返回一个子字符串,从beginIndex开始截取字符串到字符串结尾。
public String substring (int beginIndex, int endIndex) :返回一个子字符串,从beginIndex到endIndex截取字符串。含beginIndex,不含endIndex。

转换功能的方法:
public char[] toCharArray () :将此字符串转换为新的字符数组。
public byte[] getBytes () :使用平台的默认字符集将该 String编码转换为新的字节数组。
public String replace (CharSequence target, CharSequence replacement) :将与target匹配的字符串使用replacement字符串替换。

大小写转换:toUpperCase(); toLowerCase();
分割功能的方法:
public String[] split(String regex) :将此字符串按照给定的regex(规则)拆分为字符串数组。
Character.isDigit():判定是否是数字
concat()拼接字符串
String.join()拼接字符串 joiner类

char+String 会有优化
占位符:%s,%d,%f format()

StringBuilder类:
append() 插入拼接方法 无限append新的内容append().append()…append()
insert():插入方法
delete():删除方法 deleteCharAt():删除某个位置的字符
replace():替换方法
reverse():反转方法
toString():转换成String类型的

StringBuffer类:
synchronized关键字:同步 安全的 效率低
System.currentTimeMillis():长整型 毫秒级 计算运行时长
concat:拼接
StringBuilder:不安全 大方向上这个一定更快
StringBuffer:小范围的时候,可能更快一些 线程安全

StringJoiner类
高效拼接,就用StringBuilder
StringJoiner(分隔符,开头要拼接字符,结尾要拼接字符)
trim():去掉空白
intern():常量池上的字符串的引用

包装类
用对象来套一个基本型 装箱/包装 基本型转换成对象型
valueOf() Integer a=new Integer(1);
拆箱 大转小,对象型转换成基本型(提取对应数据)
intValue();拆箱
intValue():获取到Integer大类型内部的小类型内部的底层实现
自动装箱:Integer.valueOf(4);
自动拆箱: 隐式大转小。
转对象型用integer 转基本型用parseInt()

不变类
基本类型与字符串之间的转换
String转换成对应的基本类型
除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型:
public static byte parseByte(String s):将字符串参数转换为对应的byte基本类型。
public static short parseShort(String s):将字符串参数转换为对应的short基本类型。
public static int parseInt(String s):将字符串参数转换为对应的int基本类型。
public static long parseLong(String s):将字符串参数转换为对应的long基本类型。
public static float parseFloat(String s):将字符串参数转换为对应的float基本类型。
public static double parseDouble(String s):将字符串参数转换为对应的double基本类型。
public static boolean parseBoolean(String s):将字符串参数转换为对应的boolean基本类型。
Character没有parse

BigDecimal类
相加计算是用add();相减计算:subtract();相乘:multiply();相除:divide();乘方:pow()
绝对值:abs() 取余:remainder()
除法除不尽时:要精确的小数和舍入模式(divide(new BigDecimal(),保留位数,舍入模式))
八种舍入模式:
ROUND_UP:在最后一位上加一
ROUND_DOWN:最后一位保留
ROUND_CEILING:如果为正时,与ROUND_UP相同
ROUND_FLOOR:如果为正时,与ROUND_DOWN相同
***ROUND_HALF_UP:四舍五入
比较大小:max() ,min();
取相反数:negate()

BigInteger类
gcd():最大公约数
int intValue() :返回大整型
mod():取模

DecimalFormat类
用于格式化十进制数字
主要靠 # 和 0 两种占位符号来指定数字长度,0 表示如果位数不足则以 0 填充,# 表示只要有可能就把数字拉上这个位置。
System.currentTimeMillis():当前系统时间戳
异常处理快捷键:ctrl+alt+t

Math类
向上取整:ceil()
向下取整:floor()
四舍五入取整:round()(不看正负)
两数较大,较小:max() ,min()
乘方:pow()
开方:sqrt()
sin,cos,tan,cot;
Math.random():[0,1)
Object类 equals()
sort 能排对象,有限制,排的对象要实现接口 Comparable
Object类:
Objects.requireNonNull(prefix,message:错误提示);

Date类
Date date=new Date(long);
LocalDate 比Date更好
获得时间戳:new Date().getTime(); System.currenTimeMillis();
getDate():这个月的第几天
getDay():周几

DateFormat类
格式化:从date对象转为String
H 24小时制 h 12小时制
yyyy-MM-dd HH:mm:ss
SimplDateFormat() String ->Date转换 解析:simpleDateFormat.parse(date)
Date->String 格式化 :simpleDateFormat.format(today);

Calendar类
Calendar.getInstance():得到实例 产生出的实例不相同
getInstance().getTime()(得到Date对象).getTime():获得时间戳
instance1.get(Calendar.YEAR);
instance.set() :设置年月日时分秒
instance.set():两参版本:instance.set(Calendar.YEAR,2020);
instance.add(Calendar.DATE,1);:在日期上加一天 (传负数就是减)
getActualMaximum(Calendar.DAY_OF_MONTH) :返回最大值
把日期类放入日历类:calendar.setTime(date)
比较两个时间的大小:
calendar1.after(calendar2) calendar1.before(calendar2) equals()(重写过) 时间是否相等

LocalDate类
java.time包提供了新的日期和时间API,主要涉及的类型有:
本地日期和时间:LocalDateTime,LocalDate,LocalTime;
带时区的日期和时间:ZonedDateTime;
时刻:Instant;
时区:ZoneId,ZoneOffset;
时间间隔:Duration。
以及一套新的用于取代SimpleDateFormat的格式化类型DateTimeFormatter。
属性含义Instant代表的是时间戳LocalDate代表日期,比如2020-01-14LocalTime代表时刻,比如12:59:59LocalDateTime代表具体时间 2020-01-12 12:22:26ZonedDateTime代表一个包含时区的完整的日期时间,偏移量是以UTC/ 格林威治时间为基准的Period代表时间段ZoneOffset代表时区偏移量,比如:+8:00Clock代表时钟,比如获取目前美国纽约的时间
和旧的API相比,新API严格区分了时刻、本地日期、本地时间和带时区的日期时间,并且,对日期和时间进行运算更加方便。
此外,新API修正了旧API不合理的常量设计:
Month的范围用1~12表示1月到12月;
Week的范围用1~7表示周一到周日。
最后,新API的类型几乎全部是不变类型(和String类似),可以放心使用不必担心被修改。
当前日期的实例:LocalDate now=Localdate.now();
设置日期:LocalDate.of(2020,Month.JUNE,1)
获取方法:
localDate.getMonth().getValue() 获取当前月份的值
localDate.getDayOfMonth() 获取当前日期是所在月的第几天
localDate.getDayOfWeek() 获取当前日期是星期几(星期的英文全称)
localDate.getDayOfYear() 获取当前日期是所在年的第几天
localDate.getYear() 获取年份
localDate.getMonth() 获取当前日期所在月份(月份的英文全称)
localDate.getMonthValue() 获取当前日期所在月份的数值
localDate.lengthOfMonth() 获取当前日期所在月份有多少天
localDate.lengthOfYear() 获取当前日期所在年有多少天
localDate.isLeapYear() 获取当前日期所在年是否是闰年
localDate.lengthOfMonth() 获取当前月份的天数
localDate.isLeapYear() 判断是否是闰年

修改值:
localDate.withDayOfMonth(int dayOfMonth) 将参数中的"日"替换localDate中的"日"
localDate.withDayOfYear(int dayOfYear) 将参数中的天数替换localDate中的天数
localDate.withMonth(int month) 将参数中的"月"替换localDate中的"月"
localDate.withYear(int year) 将参数中的"年"替换localDate中的"年"
with开头的方法,我的理解是将参数替换localDate中的对应属性,重新计算得到新的日期。(with开头的方法都是带的纯新的LocalDate类)
localDate.minusDays(long days) 将当前日期减一天
localDate.minusWeeks(long weeks) 将当前日期减一周
localDate.minusMonths(long months) 将当前日期减一月
localDate.minusYears(long years) 将当前日期减一年
localDate.plusDays(long days) 将当前日期加一天
localDate.plusWeeks(long weeks) 将当前日期加一周
localDate.plusMonths(long months) 将当前日期加一月
localDate.plusYears(long years) 将当前日期加一年
将设置的时间实例放到括号中: localDate.atTime()
将设置的时间实例放到括号中: localTime.atDate()

LocalTime类
LocalTime.now():获取时间
LocalTime.of(int hour, int minute) 根据参数设置时间,参数分别为时,分
LocalTime.of(int hour, int minute, int second) 根据参数设置时间,参数分别为时,分,秒
localTime.getHour() 获取当前时间的小时数
localTime.getMinute() 获取当前时间的分钟数
localTime.getSecond() 获取当前时间的秒数
localTime.withHour(int hour) 将参数中的"小时"替换localTime中的"小时"
localTime.withMinute(int minute) 将参数中的"分钟"替换localTime中的"分钟"
localTime.withSecond(int second) 将参数中的"秒"替换localTime中的"秒"
with开头的方法,我的理解是将参数替换localTime中的对应属性,重新计算得到新的时间。
localTime.minusHours(long hours)将当前时间减一小时
localTime.minusMinutes(long minutes) 将当前时间减一分钟
localTime.minusSeconds(long seconds) 将当前时间减一秒
localTime.plusHours(long hours) 将当前时间加一小时
localTime.plusMinutes(long minutes) 将当前时间加一分钟
localTime.plusSeconds(long seconds) 将当前时间加一秒
LocalTime提供了atDate方法,用来表示日期 + 时间
只要日期部分:toLocalDate();toLocalTime();

调整值:
调整年:withYear()
调整月:withMonth()
调整日:withDayOfMonth()
调整时:withHour()
调整分:withMinute()
调整秒:withSecond()

比较时间:
判断两个LocalDateTime的先后,可以使用isBefore()、isAfter()方法
isEqual() 、equals(localDateTime)
Durantion :时间间隔
Duration.between(start,end)
between.todays()
between.toHours()
between.toMinutes()
between.toMillis()
Period:日期间隔
Period.between(localDate1,localDate2);
ChronoUnit.DAYS.between(localDate1,localDate2):间隔的总天数
toEpochDay(end,start);间隔的总天数
localDate.until()

时间格式化:
DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”).var;
dateTimeFormatter.format(LocalDateTime.now())
LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)

时间解析:
DateTimeFormatter.ofPattern(“yyyy-MM-dd”).var;
LocalDate.parse(字符串,dateTimeFormatter).var;
日期字符串的标准格式中加个T yyyy-MM-ddTHH:mm:ss
日期和时间:yyyy-MM-dd’T’HH:mm:ss
带毫秒的日期和时间:yyyy-MM-dd’T’HH:mm:ss.SSS
LocalDateTime.parse(LocalDateTime.DateTimeFormatter.ofPattern(“yyyy-MM-dd’T’HH:mm:ss”))

日期、时间转换
1、java.util.Date --> java.time.LocalDateTime
public static LocalDateTime UDateToLocalDateTime(Date date) {
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone) ;
}
or
public static LocalDateTime dateToLocalDateTime(Date date) {
try {
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
return instant.atZone(zoneId).toLocalDateTime();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

2、java.util.Date --> java.time.LocalDate
public void UDateToLocalDate() {
java.util.Date date = new java.util.Date();
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
LocalDate localDate = localDateTime.toLocalDate();
}

3、java.util.Date --> java.time.LocalTime
public void UDateToLocalTime() {
java.util.Date date = new java.util.Date();
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
LocalTime localTime = localDateTime.toLocalTime();
}

4、java.time.LocalDateTime --> java.util.Date
public static Date localDateTimeToDate(LocalDateTime localDateTime) {
try {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
return Date.from(zdt.toInstant());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

5、java.time.LocalDate --> java.util.Date
public void LocalDateToUdate() {
LocalDate localDate = LocalDate.now();
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
java.util.Date date = Date.from(instant);
}

6、java.time.LocalTime --> java.util.Date
public void LocalTimeToUdate() {
LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.now();
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant();
java.util.Date date = Date.from(instant);
}

7、时间戳转LocalDateTime
public static LocalDateTime timestampToLocalDateTime(long timestamp) {
try {
Instant instant = Instant.ofEpochMilli(timestamp);
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

8、LocalDateTime转时间戳
public static Long localDateTimeToTimestamp(LocalDateTime localDateTime) {
try {
ZoneId zoneId = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zoneId).toInstant();
return instant.toEpochMilli();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

正则表达式

String pwd3 = DigestUtils.md5Hex(pwdLogin);Md5加密代码
String mobilReg="\d{11}"; //d表示全是纯数字
matches(mobileReg)
String mobilReg=“1\d{10}”; 首位数字是1
String mobilReg="(135|139|133)\d{8}";开头三位数字是括号中的其中一个
正则表达式中常用的元字符:
分类符号含义.任意一个字符,除换行符\转义字符,当需要描述一个已经被正则表达式使用的特殊字符时,我们就可以通过使用\将其转变为原来的意思,\在正则表达式中也有一些预定义的特殊内容预定义字符集\d任意一个数字\w任意一个单词字符(只能是数字、字母、下划线)\s任意一个空白字符(\t \r \n \f \x0B 空格符号)\D任意一个非数字字符\W任意一个非单词字符\S任意一个非空白字符字符集合[]用来描述单一字符,方括号内部可以定义这个字符的内容,也可以描述一个范围[abc]该字符只能是a或b或c[123]该字符只能是1或2或3[a-z]a到z任意一个字符(所有小写字母)[0-9]任意一个数字[a-zA-Z0-9_]字母数字下划线数量词X?0个或1个XX0个或任意多个XX+1个或任意多个X(大于等于1个X)X{n}n个XX{n,}n到任意多个X(大于等于n个X)X{n,m}n个到m个X[\u4e00-\u9fa5]{1,}1到多个中文字符
注意:非单词是除了数字、英文字符、下划线,其他的都是非单词;
匹配规则总结
单个字符的匹配规则如下
正则表达式规则可以匹配A指定字符A\u548c指定Unicode字符和.任意字符a,b,&,0\d数字0909\w大小写字母,数字和下划线az,AZ,0~9,\s空格、Tab键空格,Tab\D非数字a,A,&,,……\W非\w&,@,中,……\S非\sa,A,&,_,……
多个字符的匹配规则如下:
正则表达式规则可以匹配A
任意个数字符空,A,AA,AAA,……A+至少1个字符A,AA,AAA,……A?0个或1个字符空,AA{3}指定个数字符AAAA{2,3}指定范围个数字符AA,AAAA{2,}至少n个字符AA,AAA,AAAA,……A{0,3}最多n个字符空,A,AA,AAA

复杂匹配规则总结

正则表达式规则可以匹配开头字符串开头$结尾字符串结束[ABC][…]内任意字符A,B,C[A-F0-9xy]指定范围的字符A,……,F,0,……,9,x,y[A-F]指定范围外的任意字符非A~FAB|CD|EFAB或CD或EFAB,CD,EF
排除掉某些情况 ^
^ 没出现在中括号,则代码以某个字符打头
^ 取反
或规则匹配 |
使用括号 ()
matcher类
Pattern类
Pattern.compile(“\d+”)
pattern.matches(string)
分组匹配 (…) 在正则表达式上加上几组()进行分组
matcher.group() group() 无参版本打印出所有的字符串 ;有参版本就是按照参数的值打印出分组
要走group() 代码,前提先走一次matches,不走报错
find()匹配部分时或完全匹配时返回 true,反之返回false
贪婪匹配转费贪婪匹配 :加?
反向引用:把搜索到的指定字符串进行替换
正则表达式中至少有一对小括号,才能形成分组

垃圾回收机制GC

System.gc();告诉JVM做一次回收动作
Runtime.getRuntime().gc();和上一个回收一样的

集合

在Java中,如果一个Java对象可以在内部持有若干其他Java对象,并对外提供访问接口,我们把这种Java对象称为集合。
Iterator 单列集合最顶级接口 主要目的是所有的子类要实现遍历的功能
Collection接口:
单列集合 1、List接口
2、Set接口
双列集合
Map接口 双列集合最顶级的接口
ArrayList类:
格式: ArrayList arrayList=new ArrayList<>();
add() 添加元素 remove() 移除元素
removeIf(new Predicate) 删除同一个所有对象
set(index,value):修改值
get(index):遍历 查
contains() indexOf() lastIndexOf()
clear();清空集合
迭代器 iterator()
stream流版本:遍历
ArrayList<>(新集合)
addAll(新集合)
cotainsAll(部分集合)
remove():正向循环时,慎用;使用逆向遍历删除元素没问题
foreach:简单用来获取或者设置,禁止用来删除
removeAll():删除子集合
retainAll()只保留指定的子集
Object[] toArray():变成数组,将元素存储到数组中
有参版本toArray():T[] toArray(T[] a);
subList():子集合提取出来 [起始,末尾); 对subList() 操作remove(0原集合的元素也会删除
数组转集合:Arrays.asList(数组)(可修改,但不能在新集合中删除元素) ;按照可变长度参数写asList()方法
get(index):根据下标获取元素
subList().clear():将提取出来的子集删除从而使大集合删除子集

集合的迭代----Iterator迭代器
通过实例.iterator()来获得迭代器实例
Iterator iterator =list.iterator();
iterator.next():返回迭代的下一个元素,并将指针向前移动一个元素
iterator.hasNext():判定是否有下一个元素(初始位置在第一个元素之前)
while(iteartor.hasNext()){
System.out.println(iterator.next());
}
把集合的所有元素删除:
while(iteartor.hasNext()){
String next=iterator.next();
iterator.remove();
}
迭代器的remove()没有返回值的;而集合的remove()有返回值的
将2,3的字符串全删除:
while(iteartor.hasNext()){
String next=iterator.next();
if(“2”.equals(next)||“3”.equals(next)){
iterator.remove();
}
}

集合遍历过程中的常见陷阱
这种for-each写法会报出著名的并发修改异常:java.util.ConcurrentModificationException。

LinkedList类
底层实现是循环双向链表数据结构。LinkedList链表由一系列表项连接而成。一个表项总是包含3个部分:元素内容,前驱和后驱。
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法:
public void addFirst(E e):将指定元素插入此列表的开头。
public void addLast(E e):将指定元素添加到此列表的结尾。
public E getFirst():返回此列表的第一个元素。
public E getLast():返回此列表的最后一个元素。
public E removeFirst():移除并返回此列表的第一个元素。
public E removeLast():移除并返回此列表的最后一个元素。
public E pop():从此列表所表示的堆栈处弹出一个元素。(弹头位 如果无数据抛异常)
public void push(E e):将元素推入此列表所表示的堆栈。
public boolean isEmpty():如果列表不包含元素,则返回true。
比较一下ArrayList和LinkedList:
ArrayListLinkedList获取指定元素速度很快需要从头开始查找元素添加元素到末尾速度很快速度很快在指定位置添加/删除需要移动元素不需要移动元素内存占用少较大
通常情况下,我们总是优先使用ArrayList。
ArrayList安全性:不保证,所有方法都没有“synchronized”修饰
LinkedList需要构建实例 和arrayList无差别的构建和添加动作
1、添加:
poll():数据没有的情况下,删除不会报错,最后一个
peek():提取
getXXXX():会抛出异常
peekXXX():不会抛出异常 无数据返回null
offer():插入尾部

和ArrayList不同,Vector中的操作是线程安全的。
ArrayList和Vector的相同点和不同点
相同点不同点都继承于AbstractList,并且实现List接口ArrayList是非线程安全,而Vector是线程安全的都实现了RandomAccess和Cloneable接口ArrayList支持序列化,而Vector不支持都是通过数组实现的,本质上都是动态数组,默认数组容量是10容量增加方式不同,Vector默认增长为原来一倍,而ArrayList却是原来的一半+1都支持Iterator和listIterator遍历Vector支持通过Enumeration去遍历,而List不支持

Collections
常用功能:
java.utils.Collections是集合工具类,用来对集合进行操作。部分方法如下:
public static boolean addAll(Collection c, T… elements):往集合中添加一些元素。
public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。
public static void sort(List list):将集合中元素按照默认规则排序。
public static void sort(List list,Comparator<? super T> ):将集合中元素按照指定规则排序。
List.of():括号中填写一些元素
Arrays的sort可以排对象数组(有前提:Comparable)
sort方法单参在类上实现Comparable

如果Comparable和compare()同时存在时,优先实现Comparable

Set接口

HashSet
不能存储相同的元素,无序的; 初始容量:16 底层是HashMap 安全性不高,多线程下可能有问题
hashXXXX优先比较的是每个对象的hashcode的值(内存的值),java底层做了这个方法的重写
hash算法算一个对象的hashcode值,如果不一样,则大概率equals也不一样;如果一致,也不能保证equals内部判定一样
遍历:pList.foreach
Set中,null能被插入,但是同样会被排重,无序
equals和hashcode:
都在object类中
hashmap对象的空间(空间用数组来做底层的基础)
红黑树:相同对象超过八个才能实现
先算每个对象的hashcode才能走

treeSet类
底层是TreeMap 安全性不高,多线程下可能有问题
TreeSet set=new treeSet<>();
set.add();
treeSet不能添加null值;排重;有序(对象需要实现Comparable,字符串在比较的时候是在比较的每一位)
无参TreeSet构造时,内部对象需要实现comparable
如果内部对象没有实现Comparable接口,则直接异常;但如果实现了Comparable接口,但方法return ,比较器只会认为后面的对象是同一对象,则只会打印第一个对象
TreeSet set=new treeSet<>(new Comparator());

八大基本类型都实现了Comparable接口

linkedHashSet
和TreeSet大部分一致
由链表和哈希表一起实现 ;顺序的
初始容量:16
排重;可以插入一个null
打印顺序和插入顺序一致

List和Set之间的互相转换
List->Set:
List list = new ArrayList<>();
Set set1 = new HashSet<>(list);

Set set2 = new HashSet<>();
set2.addAll(list);

Set->List:
Set set = new HashSet<>();
List list1 = new ArrayList<>(set);

List list2 = new ArrayList<>();
list2.addAll(set);

List->TreeSet:
自定义对象,用treeSet,则前提对象需实现Comparable或者
优先构造出一个带Comparator的实现,把集合的数据带入进来(set.addAll(list))

泛型
定义格式:
修饰符 class 类名<代表泛型的变量> { }

命名要求不高,只要不是数字打头,特殊符号不要,其他的都行
用来替代类内部的一些变量类型或者方法中形参类型或者方法的返回值类型
编译时泛型实际变为object类
限制实例类型的范围
在创建对象时确定泛型
含有泛型的方法:
定义格式:
修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }

含有泛型的接口:
定义格式:
修饰符 interface 类名<代表泛型的变量>{ }

泛型通配符
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
受限泛型通配符:上限符、下限符
泛型的上限:
格式: 类型名称 <? extends 类 > 对象名称
意义: 只能接收该类型及其子类
泛型的下限:
格式: 类型名称 <? super 类 > 对象名称
意义: 只能接收该类型及其父类型

Map接口
特点: (1)以键值对的方式存储数据 (2)通过键获取值 (3)键不能重复(通过equals方法和hashCode方法保证) (4)值允许重复
HashMap
HashMap放自定义对象时,为什么要覆盖hashcode和equals方法?

基于哈希表实现;key和value都允许为null 无序的
HashMap<Integer,String> map=new HashMap<>();
map.put(key,value);加数据
后写的同名键会把值覆盖
map.get();提取数据
map.remove()删除数据
map.cotainsKey():包含数据
遍历HashMap:
遍历键位:
map.keySet().var;
map.values().var; 遍历值
同时遍历键值对 : Entry类
map.entrySet().var;

TreeMap
在这里插入图片描述

LinkedHashMap
插入时和打印时一致
速度快,不安全 有序的
键和值都可以为null
Hashtable
键和值都不能为空、排重键、无序的
继承于Dictionary类
线程安全 效率低
contains()方法不明确
初始容量:11
提取map的value:ArrayListlist=new ArrayList<>(map.values())

异常处理

空指针异常:NullPointerException
算术运算异常:ArithmeticException
数组越界异常:ArrayIndexOutOfBoundsException
越界异常:IndexOutOfBoundsException
非法参数异常:IllegalArgumentException
类型转换异常:ClassCastException
解析异常:ParseException
数字格式化异常:NumberFormatException
Throwable类
最高超类
OutOfMemoryError:内存溢出
Error:只能尽量避免
Exception:由于使用不当导致,可以处理
Exception:检查异常(编译期异常)、不检查异常(运行时异常)
Java异常处理的五个关键字:try、catch、finally、throw、throws
声明异常throws:往上抛异常
Finally:用来保证try catch 中不管是否有异常,都能进入的一段逻辑块
场景:涉及消耗资源,需要用完释放的场景
try…catch…finally:自身需要处理异常,最终还得关闭资源。
try {

}catch(FirstException e) {

}catch(SecondException e) {

}finally {

}
注意:finally不能单独使用
不进finally :System.exit(0);终止程序
子类覆盖了父类的方法,只能抛出和父类一致的异常,或者比父类异常 小的异常
运行时异常,在子类,可以不用抛出
运行时异常被抛出可以不处理。即不捕获也不声明抛出。
如果finally有return语句,永远返回finally中的结果,避免该情况.
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常(只适用于受检异常)。此时子类产生该异常,只能捕获处理,不能声明抛出
异常的捕获顺序应该是:从小到大
final:修饰类(不能被继承)、常量(只能使用,不能修改;初始值要么直接写上,要么放在构造器或者普通代码块的位置初始化)、方法(不能被重写、能被重载)、方法的形参(修饰成final,则内部无法对该形参变量的指针发生变化)
finally:不能单独使用,主要配合try,也可以是try catch;不敢内部是否有异常,最终都会进入finally包裹的代码块执行,实际上大部分情况下,用在一些资源使用后需要消耗资源的场景
finalize:Object类的一个方法,某个类没有被任何指针引用或方法调用时,GC会尝试来处理回收这个对象,那finalize方法如果手工覆盖,则该对象在该finalize中还有一次机会可以逃脱GC

File类

构造器:
public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
判定某个文件是否存在:file.exists();
文件地址格式写法:File.separator:代表/或\
file.getAbsolutePath():文件的绝对路径
文件夹:
file.isDirectory():判定是否是文件夹
file.isFile():判定是否是文件夹
./:相对路径
…/:上一级文件夹路径
file.getPath():获取文件全路径,不一定准确 只是把构造器构成的path带出,可能是相对路径
file.getName():获取文件名
file.length():获取文件内容长度
一个中文算三个长度
file.mkdir():创建一个文件夹
file.mkdirs():级联创建多个文件夹
file.createNewFile():人为代码创建文件
file.getParentFile():得到父级路径

删除文件:
file.delete():删除文件
文件夹里有文件时删除不了

遍历所有子文件和子文件夹:
public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
文件过滤器优化:
在这里插入图片描述

递归遍历文件:
在这里插入图片描述

IO流

流向分为:输入流和输出流(字节流和字符流)
OutputStream(字节输出流)
FileOutputStream子类:
write():在文件中写入内容
write(byte[],int off,int len):拷入数组的部分长度
fileOutputStream.close():关闭io流
maven:仓库 下载第三方工具包
FileOutputStream():构造器上的第二个参数为true,则为追加模式
换行:\r\n

字节输入流:

FileInputStream子类:
FileInputStream fis=new FileInputStream(“文件路径”)
int read=fis.read() 读取字符的Ascall码
如果打印到空时,返回-1
read(byte[] b):
读取文件内容:
int len ;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[2];
// 循环读取
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组变成字符串打印
System.out.print(new String(b,0,len));
}

图片复制
在这里插入图片描述

字符流

字符输入流(Reader类)
FileReader子类
FileReader fr=new FileReader(“文件路径")
自动换行\r\n:两个字节
用char[]数组写入
在这里插入图片描述

字符输出流(writer类)

FileWriter fw=new FileWriter(“文件路径”)
fw.write("字符串”);
FileWriter fw=new FileWriter(“文件路径”,true)
fw.write("字符串”);
Writer 常规try catch 或者向上抛,Writer只要不调用close或者flush方法,则文本不会真的写入文件
flush :刷新缓冲区,流对象可以继续使用。
close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

字符流使用了缓冲区,而字节流没有使用缓冲区。
属性集Properties
java.util.Properties 继承于Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。
遍历:properties.stringPropertyNames();
打印出来的是无序的

与流相关的方法:
load():从字节输入流中读取键值对。
添加键值对:setProperties(String,String );
实际写入:store(new FileOutputStream(),String);

缓冲流

也叫高效流
字节缓冲流:BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader,BufferedWriter
BufferedWriter
readLine():一行一行读取字符串
bw.newLine():换行
forEach():括号内是接口

转换流

new InputStreamReader(new FileInputStraem(),“GBK”);
InputStreamReader类 OutputStreamWriter类

序列化

正向序列化:java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
writeObject():写出对象到文件
public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。
需要实现Serializable接口(标记性接口。用来确定是否可以在网络层面传输或者持久化到磁盘的标记),不然会报错
反序列化
ObjectInputStream类
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
readObject():读对象
public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。
反序列化操作
当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。**发生这个异常的原因如下:
该类的序列版本号与从流中读取的类描述符的版本号不匹配
该类包含未知数据类型
该类没有可访问的无参数构造方法
Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

序列化集合

打印流:PrintStream类
System.setOut(ps)

线程

并发(Cocurrency):并发通常是指多个任务交替使用CPU,同一时刻还是只有一个任务在跑。
并行(Parallelism):并行是指多个任务同时在跑,是真正地同时运行。例:吃饭的时候可以边吃饭边打电话,这两件事情可以同时执行

线程创建
创建线程方式一继承Thread类
Tread():空参版本
start() 、run()
new Tread(): 构建线程类
tread.start():线程开始运行
写法一:新建一个普通类继承Tread类,同时重写run()方法
只有调用start()才是线程
执行顺序不能掌控
写法二:Tread tread=new Tread(){
@override
重写run()
}.start();
获取线程名:getName()
主线程获得线程名:Thread.currentThread().getName();
new Tread(String 线程名)
创建线程的方式二:
new Runnable(){}
new Thread(runnable)
实现 Runnable 接口的原因:避免了继承 Thread 类的单继承局限性。覆盖 Runnable 接口中的 run 方法,将线程任务代码定义到 run 方法中。创建 Thread类的对象,只有创建 Thread 类的对象才可以创建线程。线程任务已被封装到Runnable 接口的 run 方法中,而这个 run 方法所属于 Runnable 接口的子类对象,所以将这个子类对象作为参数传递给 Thread 的构造函数,这样,线程对象创建时就可以明确要运行的线程的任务。
实现 Runnable 的好处
第二种方式实现 Runnable 接口避免了单继承的局限性,所以较为常用。实现Runnable 接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承 Thread 类,线程对象和线程任务耦合在一起。一旦创建 Thread 类的子类对象,既是线程对象,有又有线程任务。实现 runnable 接口,将线程任务单独分离出来封装成对象,类型就是 Runnable 接口类型。Runnable 接口对线程对象和线程任务进行解耦。
创建线程方式三:实现Callable接口
1、Callable接口类似于Runnable接口
2、Callable有返回值
3、Callable可以抛出异常
4、调用call()方法
5、Callable支持泛型
FutureTask类中存了Callable中call方法中业务逻辑最终的返回值

ft.get():提取FutureTask类中的返回值 可能会阻塞
Thread.sleep():模拟慢慢的跑代码
运行一次就会被缓存,结果也就被确定了
多个线程执行同一个FutureTask,则只会运行一次call()
某个线程已经执行过了该call(),该call()的返回值已经被缓存了
Thread.cancel():中止线程
抢占式调度:
线 程 优 先 级 主 要 分 三 种 : MAXPRIORITY( 最 高 级 );MINPRIORITY( 最 低 级 )NORM_PRIORITY(标准)默认优先级高的线程会得到的 CPU 时间多一些,优先执行完成

常用的API

Thread.sleep 睡眠
Thread.yield 谦让(放弃)
完全放弃掉cpu时间片竞争,等待时间过掉,继续做时间竞争
线 程 优 先 级 主 要 分 三 种 : MAXPRIORITY( 最 高 级 );MINPRIORITY( 最 低 级 )NORM_PRIORITY(标准)默认优先级高的线程会得到的 CPU 时间多一些,优先执行完成
yield 和 sleep 的异同
1)yield, sleep 都能暂停当前线程,sleep 可以指定具体休眠的时间,而 yield 则依赖 CPU 的时间片划分。
2)yield, sleep 两个在暂停过程中,如已经持有锁,则都不会释放锁资源。
3)yield 不能被中断,而 sleep 则可以接受中断。
Thread.join 结合 等待该线程终止
public final void join() throws InterruptedException;
public final synchronized void join(long millis) throws InterruptedException;
public final synchronized void join(long millis, int nanos) throws InterruptedException;

其中
(1) 三个方法都被 final 修饰,无法被子类重写。
(2) join(long), join(long, long) 是 synchronized method,同步的对象是当前线程实例。
(3) 无参版本和两个参数版本最终都调用了一个参数的版本。
(4) join() 和 join(0) 是等价的,表示一直等下去;join(非 0)表示等待一段时间。
从源码可以看到 join(0) 调用了 Object.wait(0),其中 Object.wait(0) 会一直等待,直到被 notify/中断才返回。
while(isAlive())是为了防止子线程伪唤醒(spurious wakeup),只要子线程没有TERMINATED 的,父线程就需要继续等下去
(5) join() 和 sleep() 一样,可以被中断(被中断时,会抛出InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会出让锁,而 sleep() 会一直保持锁。
线程编号方法:getId()
概率:Math.random()

Thread.interrupt 中断
isInterrupted():用来做中断状态的校验 慎用Thread.sleep()
标志位中断 :

注意到HelloThread的标志位boolean running是一个线程间共享的变量。线程间共享变量需要使用volatile关键字标记,确保每个线程都能读取到更新后的变量值。
volatile关键字的目的是告诉虚拟机:
每次访问变量时,总是获取主内存的最新值;
每次修改变量后,立刻回写到主内存。
volatile关键字解决的是可见性问题:当一个线程修改了某个共享变量的值,其他线程能够立刻看到修改后的值。

线程状态
这里先列出各个线程状态发生的条件,下面将会对每种状态进行详细解析
线程状态导致状态发生条件NEW(新建)线程刚被创建,但是并未启动。还没调用start方法。Runnable(可运行)线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。Blocked(锁阻塞)当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。Waiting(无限等待)一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。TimedWaiting(计时等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。Teminated(被终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。
Timed_Waiting():计时等待
线程安全
临界资源必须保证是同一个,要么是一个成员()
三种方式完成同步操作:
同步代码块
同步方法
锁机制
同步代码块:sychronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问
格式:
sychronized(同步锁){
需要同步操作的代码
}
同步锁:(互斥锁)
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
锁对象 可以是任意类型。
多个线程对象 要使用同一把锁。
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED)。

同步方法:
同步方法实际上就是同步方法块持有的就是类字节码。
sychronized(类名.Class)
Lock锁机制
Lock lock=new ReentrantLock();重入锁,锁定和解锁
加锁不是所有线程都上锁,是某个线程抢到资源,这个线程去锁住,不让别的线程进入
park方法,synchronized同步锁锁当前线程的wait
unpark():解锁某个特定线程
线程通信
wait():等待 notify()唤醒

守护线程(Daemon Thread):
setDaemon():括号里设置为true,为守护线程

线程池
单线程的线程池
excute()、submit():提交线程
Executors类:单线程
定长线程池:

Future接口
future.get():获得线程池返回的值(Future)
future.cancel(true)、future.isCancelled():线程是否取消
future.isDone():判定线程是否完成
future.get(5,TimeUnit.SECONDS):延迟五秒获取

Executors类(四大功能池)
定长功能池:newFixedThreadPool
Executors.newFixedThreadPool(nThread:5).var:
excutorService.submit(new Callable(){
});
定时功能池:newScheduledThreadPool
scheduledService.schedule(new Callable{},5,TimeUnit.SECOND);
周期性执行:
scheduledService.scheduleAtFixedRate(new Runnable(){
},0,1,TimeUnit.SECOND);
可缓存线程池:newCachedThreadPool
executorService.submit(new Callable{})
executorService.shutdown();
单线程化线程池:SingleThreadExecutor
任务队列为链表结构的有界队列;具有顺序性
###volatile 进阶

反射(reflect)

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。
java.lang.Class类
java.lang.Class 类是实现反射的关键所在,Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型和 void。Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的。
通过类名的静态变量class得到大的Class类型
通过实例对象得到字节码对象

通过类的全限定类名(类的全路径)字符串
Class.forName(“类的全路径”)
strClass.getName()

判定类是否是抽象类,函数在Modifier中
数组没有包
下面列出了通过反射可以访问的信息:
类型访问方法返回值类型说明包路径getPackage()Package 对象获取该类的存放路径类名称getName()String 对象获取该类的名称继承类getSuperclass()Class 对象获取该类继承的类实现接口getlnterfaces()Class 型数组获取该类实现的所有接口构造方法getConstructors()Constructor 型数组获取所有权限为 public 的构造方法getDeclaredContruectors()Constructor 对象获取当前对象的所有构造方法方法getMethods()Methods 型数组获取所有权限为 public 的方法getDeclaredMethods()Methods 对象获取当前对象的所有方法成员变量getFields()Field 型数组获取所有权限为 public 的成员变量getDeclareFileds()Field 对象获取当前对象的所有成员变量内部类getClasses()Class 型数组获取所有权限为 public 的内部类getDeclaredClasses()Class 型数组获取所有内部类内部类的声明类getDeclaringClass()Class 对象如果该类为内部类,则返回它的成员类,否则返回 null
如表 所示,在调用 getFields() 和 getMethods() 方法时将会依次获取权限为 public 的字段和变量,然后将包含从超类中继承到的成员变量和方法。而通过 getDeclareFields() 和 getDeclareMethod() 只是获取在本类中定义的成员变量和方法。

用instanceof不但匹配指定类型,还匹配指定类型的子类。而用==判断class实例可以精确地判断数据类型,但不能作子类型比较。

访问成员变量
通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。
Field getField(name):根据字段名获取某个public的field(包括父类)
Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
Field[] getFields():获取所有public的field(包括父类)
Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
Field 类的常用方法如表 所示
方法名称说明getName()获得该成员变量的名称getType()获取表示该成员变量的 Class 对象get(Object obj)获得指定对象 obj 中成员变量的值,返回值为 Object 类型set(Object obj, Object value)将指定对象 obj 中成员变量的值设置为 valuegetlnt(0bject obj)获得指定对象 obj 中成员类型为 int 的成员变量的值setlnt(0bject obj, int i)将指定对象 obj 中成员变量的值设置为 isetFloat(Object obj, float f)将指定对象 obj 中成员变量的值设置为 fgetBoolean(Object obj)获得指定对象 obj 中成员类型为 boolean 的成员变量的值setBoolean(Object obj, boolean b)将指定对象 obj 中成员变量的值设置为 bgetFloat(Object obj)获得指定对象 obj 中成员类型为 float 的成员变量的值setAccessible(boolean flag)此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量getModifiers()获得可以解析出该方法所采用修饰符的整数

突破访问权限:name.setAccessible(true)

getType():可以获得成员变量的数据类型
通过反射读写字段是一种非常规方法,它会破坏对象的封装。
Void本身是一个对象
执行方法(获取方法)
要动态获取一个对象方法的信息,首先需要通过下列方法之一创建一个 Method 类型的对象或者数组。
Method getMethod(name, Class…):获取某个public的Method(包括父类)
Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
Method[] getMethods():获取所有public的Method(包括父类)
Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

Method 类的常用方法如表所示。
getName() 获取该方法的名称
getParameterType() 按照声明顺序以 Class 数组的形式返回该方法各个参数的类型
getReturnType() 以 Class 对象的形式获得该方法的返回值类型getExceptionTypes() 以 Class 数组的形式获得该方法可能抛出的异常类型invoke(Object obj,Object…args) 利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型isVarArgs()查看该方法是否允许带有可变数量的参数,如果允许返回 true,否则返回 falsegetModifiers()获得可以解析出该方法所采用修饰符的整数、、isPublic()等等
调用私有方法必须在前面先加上setAccessible(true)
调用静态方法:invoke(null,形参类型)
子类覆盖父类的方法,从而调用父类的方法执行的仍然是子类的方法

构造方法
Person p = Person.class.newInstance();
调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。
为了能够动态获取对象构造方法的信息,首先需要通过下列方法之一创建一个 Constructor 类型的对象或者数组。
getConstructor(Class…):获取某个public的Constructor;
getDeclaredConstructor(Class…):获取某个Constructor;
getConstructors():获取所有public的Constructor;
getDeclaredConstructors():获取所有Constructor。
注意Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。
调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问。setAccessible(true)可能会失败。

创建的每个 Constructor 对象表示一个构造方法,然后利用 Constructor 对象的方法操作构造方法。Constructor 类的常用方法如表所示。
isVarArgs() 查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回
falsegetParameterTypes() 按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型getExceptionTypes()以 Class 数组的形式获取该构造方法可能抛出的异常类型newInstance(Object … initargs)通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示 采用默认无参的构造方法
setAccessiable(boolean flag) 如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance() 方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对 象
getModifiers() 获得可以解析出该构造方法所采用修饰符的整数
通过 java.lang.reflect.Modifier 类可以解析出 getMocMers() 方法的返回值所表示的修饰符信息
用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以字符串的形式获得所有修饰符。表 2 列出了 Modifier 类的常用静态方法。
isStatic(int mod) 如果使用 static 修饰符修饰则返回 true,否则返回 falseisPublic(int mod) 如果使用 public 修饰符修饰则返回 true,否则返回 falseisProtected(int mod) 如果使用 protected 修饰符修饰则返回 true,否则返回
falseisPrivate(int mod) 如果使用 private 修饰符修饰则返回 true,否则返回 falseisFinal(int mod) 如果使用 final 修饰符修饰则返回 true,否则返回 falsetoString(int mod) 以字符串形式返回所有修饰符
getSuperClass():获得父类类型
getInterfaces():获得接口信息

继承关系
通过Class对象可以获取继承关系:
Class getSuperclass():获取父类类型;
Class[] getInterfaces():获取当前类实现的所有接口。
通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。

注解

定义:
直接通过@interface关键字进行定义。

publi @interface test{
    
}

静态代码块和代码块不能加注解
RetentionPolicy.RUNTIME:运行期
@target
不写target注解,则所有场景都能正常使用
@Target 有下面的取值
@Target(ElementType.TYPE) 作用接口、类、枚举、注解
@Target(ElementType.FIELD) 作用属性字段、枚举的常量
@Target(ElementType.METHOD) 作用方法
@Target(ElementType.PARAMETER) 作用方法参数
@Target(ElementType.CONSTRUCTOR) 作用构造函数
@Target(ElementType.LOCAL_VARIABLE)作用局部变量
@Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
@Target(ElementType.PACKAGE) 作用于包
@Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
@Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
一般比较常用的是ElementType.TYPE类型
@Documented注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Inherited :给使用了注解的父类去继承给子类

注解的属性
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
直接在使用时,如果是多个值的设置时,不需做成“数组"状态
注解的成员定义时,不允许出现普通类
注解属性类型可以有以下列出的类型
1.基本数据类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
default的用法:
在这里插入图片描述

过期注解:@Deprecated
阻止警告:@SuppressWarnings(“all”)
参数安全类型注解:@SafeVarargs
@Repeatable:可重复的
注解的提取:
直接用getAnnotation()提取注解
getAnnotations()提取全部注解

单元测试

junit
assert 后面写一个boolean的值
@Test org.junit

Lambda

()–>{} :不管什么类型的lamdba,这个都算原始写法
大括号里只有一句话的话就可以不用写大括号(额外移除后面的分号)
带返回值的场景,则return这可以省
在这里插入图片描述

Stream流

循环遍历:list.stream():开启流
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

list.stream.collect(Collectors.toList()):收集成一个新的集合
获取流
java.util.stream.Stream
单列集合
所有的 Collection 集合都可以通过 stream 默认方法获取流;
Stream 接口的静态方法 of 可以获取数组对应的流。
根据数组获取流:Stream.of(…)
数组转List集合:new ArrayList<>(Arrays.asList(数组))返回一个List集合Stream.of().collect(Collector.toList)
Files.lines(Paths.get(path)).forEach:遍历流 返回一个Stream流
forEach:终结方法
过滤:filter 中间操作
映射:map
.map().collect(Collector.toList())
.mapToInt():返回一个IntStream 这个流基本不会收集动作
排重:distinct() 只依赖于equals()
统计元素个数:count():终结操作 返回值类型long
有一次终结操作流就结束了,不能重复使用
取前几个元素:limit(n)
排序:sorted(new Comparator)
跳过元素:skip()
组合流:Stream.concat(Stream a,Stream b);
concat是一个静态方法
输出为数组:

temp.stream().toArray()
List<String> list = List.of("Apple", "Banana", "Orange");
String[] array = list.stream().toArray(String[]::new);

输出为map

Stream<String> stream = Stream.of("APPL:Apple", "MSFT:Microsoft");

Map<String, String> collect = stream
        .collect(Collectors.toMap(s -> s.split(":")[0], s -> s.split(":")[1]));

System.out.println(collect);

intStream类

allMatch():判定是否每个数比另一个数大 anyMatch:至少有一个数比另一个数大
summaryStatistics().getMax .getMin() .getCount() .getSum .getAverage()

集合中分组;
在这里插入图片描述

单例模式(Singleton Pattern)

注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
饿汉模式
类加载时只会加载一次
提供一个静态方法来获取这个实例
在这里插入图片描述

1、安全问题
天生浪费
2、资源是否浪费
可能该实例永远用不到,那就浪费资源了
懒汉模式
在这里插入图片描述

懒汉的安全写法:加一个synchronized关键字

网络编程

常用命令
查看ip地址:ipconfig
检查网络是否连通:ping 空格 ip地址
Socket类
new Socket(String host,端口号)写服务器端的ip+port
在这里插入图片描述

new ServerSocket(端口号)启动服务器
accept():侦听并接受连接,返回一个新的Socket
在这里插入图片描述

做完一次输出,则必须让socket内部停止掉输出的动作

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

与君归

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值