文章目录
- 基本概念
- cmd命令
- Java构成
- 原码/反码/补码
- 基本数据类型*
- switch表达式
- 运算符
- 三大特性
- 关键字*
- 对象四种关系
- 对象的引用
- 内存分配*
- 接口*
- 抽象类*
- 内部类
- 方法重载
- 方法重写
- 可变参数
- 代码块
- 包装类
- 字符串*
- 基础知识
- 常用API
- Math
- System
- Runtime
- Object
- Objects
- Arrays
- BigInteger
- BigDecimal
- 正则表达式
- 对象
- 字符串
- 分组
- 时间相关类
- SimpleDateFormat
- Calendar
- 核心内容
- 数组
- 异常
- 处理异常
- Throwable方法
- 自定义异常
- Throw 和 throws
- 集合**
- Collection (单列)
- List(有序 可重复 有索引)
- Set(无序 不重复 无索引)
- Map (双列)
- Hashtable
- HashMap
- TreeMap
- ConcurrentHashmap
- Collections
- 不可变集合
- File类
- 绝对/相对路径
- 构造方法
- 判断、获取
- 创建、删除
- 获取并遍历
- IO流
- 分类
- 体系结构
- 字节流 (8位字节)
- FileOutputStream
- FileInputStream
- 字符流 (16位字节)
- FileReader
- FileWriter
- 缓冲流
- 字节缓冲流
- 字符缓冲流
- 转换流
- 序列化流
- 打印流
- PrintStream
- PrintWriter
- 多线程
- 基本概念
- 实现方式
- 方式一:继承Thread类
- 方式二:实现Runnable接口
- 方式三:实现Callable接口
- 成员方法
- 线程分类
- 生命周期
- 线程同步
- 方式一:同步代码块
- 方式二:同步方法
- 方式三:Lock锁 (更灵活的代码控制)
- 线程通信
- 线程池
- 网络编程
- 软件架构
- 三要素
- IP地址
- 端口
- 协议
- 其他内容
- 泛型
- 枚举
- 注解
- 反射
- 获取Class对象
- 获取对象
- lambda表达式
- 方法引用
- Stream流
- 步骤
- 注意
- 中间操作
- 终端操作
基本概念
cmd命令
- cd 目录:进入目录
- cd ..:回退目录
- cd \:回退到盘符目录
- cd 目录1\目录2:进入多级目录
- start 文件名字:打开文件夹或文件
- 盘符名称+冒号:切换盘符
- dir:查看路径下的内容
- del 文件名:删除文件
- cls:清屏
- exit:退出窗口
- ctrl+c:终止命令
- net user:查看用户
- whoami:查看当前用户
- ipconfig:查看ip地址
- netstat -ano:查看进程id
- shutdown -s:关机
- shutdown -r:关机并重启
- shutdown -s -t 60:定时关机,定时60s
- shutdown -r -t 秒数:一段时间后重启
- write:写字板
- calc:启动计算器
- mspaint:画图板
- notepad:打开记事本
- control:打开控制面板
- winver:检查Windows版本
- regedit:打开注册列表编辑器
Java构成
- JDK:java development kit:java开发工具包,是开发人员所需要安装的环境
- JRE:java runtime environment:java运行环境,java程序运行所需要安装的环境
- JVM:Java 虚拟机 (JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现 (Windows, Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言 “一次编译,随处可以运行” 的关键所在
环境变量:任意的目录都可以打开指定的软件,软件的路径配置到path环境中
编译:javac HelloWord.java
运行:java HelloWord
原码/反码/补码
正数原码、反码、补码相同
负数:
-
反码:符号位不变,数值取反
-
补码:反码加1
补码能多记录一个值-128,计算机中的存储和计算都是以补码的形式进行的
基本数据类型*
byte、short、int、long、float、double、char、boolean
定义long后加 L,定义float后加 F
switch表达式
(将要匹配的值)取值为byte、short、int、char,JDK5以后可以是枚举,JDK7以后可以是String
运算符
隐式转换:取值范围小的转换为大的,byte、short、char类型数据参与运算会先提升为int类型
强制转换:取值范围大的转换为小的。目标数据类型 变量名 = (目标数据类型)被强转的数据;
三大特性
- 封装 -> (private修饰对象字段)
- 继承 ->(分页对象继承父类)
- 多态 ->(创建集合对象)
关键字*
**权限修饰符:**public>protected>默认>private
**Javac:**将java源代码转化成JVM能够识别的语言(Java字节码)
**javap:**反编译:javap test.class
static:
- 修饰成员变量,随着类的加载而加载,优先于对象
- 修饰成员方法,不需要创建对象,可以直接通过类名调用,多用于工具类
- 静态代码块,当第一次用到本类时,静态代码块执行唯一的一次,静态的内容优先于非静态执行
- 静态不能直接访问非静态,只能访问静态
this:
- 指向当前对象的引用,区分成员变量和局部变量
- this()只能写在构造方法中,第一条语句
super:
- 在子类的构造方法中调用父类的构造方法
- super()必须为子类构造函数中的第一行
- 可以访问父类的成员方法或变量,super.方法名()
final:
- 修饰类,不能被继承
- 修饰方法,不能被重写
- 修饰变量,值不能变 必须赋初始值
**finally:**通常放在 try…catch…的后面,程序无论正常执行还是发生异常,只要 JVM 不关闭都能执行,释放资源
**finalize:**在垃圾收集器将对象从内存中清除出去之前做必要的清理工作,是由垃圾收集器在销毁对象时调用的
**instanceof:**一个对象是不是另一个类(接口)的实例,或者直接或者间接子类或者实现类
对象四种关系
-
依赖:Person类没有Car和House类的属性,Car和House的实例是以参量的方式传入到buy()方法中
-
关联:一个类知道另一个类的属性和方法,使用成员变量来实现
-
聚合:关联关系的一种,强的关联关系。比如汽车类与引擎、轮胎类
-
组合:关联关系的一种,比聚合关系强。整体的对象需要负责保持部分对象和存活
对象的引用
-
强:程序内存不足时也不会被回收,使用:String str = new String(“str”);
-
弱:只要JVM垃圾回收器发现了它,就会被回收
- 使用:WeakReference wrf = new WeakReference(str);
-
软:在程序内存不足时被回收
- 使用:SoftReference wrf = new SoftReference(new String(“str”));
-
虚:回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中
内存分配*
-
栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中)
-
堆:存放所有new出来的对象
-
方法区:存储可以运行的class文件
-
寄存器:最快的存储区,由编译器根据需求进行分配,我们在程序中无法控制
接口*
- 使用interface修饰;不能实例化;可以实现多个接口
- Java8之前,接口中的方法都是抽象方法,省略了public abstract
- Java8之后,接口可以定义静态方法,静态方法必须有方法体,普通方法没有方法体,需要被实现
抽象类*
- 使用abstract修饰;不能被实例化;只能单继承
- 可以包含抽象方法和非抽象方法,非抽象方法需要有方法体
- 一个类继承了抽象类,实现了所有的抽象方法,子类可以不是抽象类;如果没有实现所有抽象方法,子类任然是抽象类
内部类
- 内部类可以访问外部类的所有成员,外部类访问内部类需要创建对象
- 成员、静态、局部内部类、匿名内部类
方法重载
同一个类中,方法名相同、参数不同,与返回值无关。方法参数必须不同,包括参数的类型或个数不同
方法重写
- 继承关系中子类重写父类的方法,参数列表、返回类型、方法名必须相同
- 重写方法的访问权限不能比父类中的方法权限低
- 声明为final、static的方法不能被重写
- 构造方法不能被重写
可变参数
格式:数据类型…参数名称 例如:int…a
注意事项:形参列表中可变参数只能有一个;可变参数必须放在形参列表的最后面
代码块
局部代码块、构造代码块、静态代码块
包装类
Integer:自动拆箱/装箱
转换String
1.toString()
基本数据类型没有toString()方法
2.(String)强转
(String)强转,先使用instanceof做类型检查,可能出现异常
3.String.valueOf (推荐)
如果为null,String.valueOf()返回结果是字符串“null”
compareTo方法
可以 Byte, Double, Integer, Float, Long 或 Short 类型参数
指定的数与参数相等返回 0
指定的数小于参数返回 -1
指定的数大于参数返回 1
字符串*
String、StringBuilder、StringBuffer、StringJoiner
StringJoiner:底层是StringBuilder,线程不安全
public StringJoiner(间隔符合)
public StringJoiner(间隔符合,开始符号,结束符号)
基础知识
常用API
Math
- sqrt:求平方根
- abs:获取绝对值
- pow(a,b):a的b次幂的值
- random:随机值 [0.0,1.0)
- ceil/floor/round:向上/向下/四舍五入
System
- exit:终止Java虚拟机
- 0:表示虚拟机正常停止
- 非0:表示虚拟机异常停止
- currentTimeMillis():当前系统时间的毫秒值
- arraycopy(原数组,开始索引,目的数组,开始索引,拷贝个数):数组拷贝
Runtime
Object
- toString():返回对象的字符串表示形式
- equals(Object object):比较两个对象是否相等
拷贝/克隆
浅拷贝
对基本数据类型进行值传递,对引用数据类型进行引用传递的拷贝 (实现Cloneable接口,重写clone方法)
clone(Object object):对象克隆
深拷贝
对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容 (实现Cloneable接口,重写clone方法)
-
实现方式:改写重写的clone方法
-
使用第三方工具(gson)
Objects
- equals(Object object,Object object):先判空,比较两个对象
- isNull(Object object):判断对象是否为null,为null返回true
- nonNull(Object object):判断对象是否为空,与isNull相反
Arrays
BigInteger
BigDecimal
除法舍入模式枚举类:RoundingMode
四舍五入:HALF_UP
正则表达式
对象
- Pattern
- compile(表达式):获取正则对象
- Matcher:下面两个方法必须同时使用
- find():判断是否存在
- group():获取数据
字符串
- String[] matches(String reges):判断字符串是否满足正则规则
- String replaceAll(String reges):按照正则表达式的规则进行替换
- String[] split(String reges):按照正则表达式的规则切割字符串
分组
时间相关类
SimpleDateFormat
yyyy年MM月dd日 HH:mm:ss
Calendar
日历类中月份的范围:0~11
日历类中星期的特点:星期日是一周中的第一天
核心内容
数组
-
一维数组
静态初始化:int[] array ={1,2,3,4};
动态初始化:int[] array =new int[5];
-
二维数组
静态初始化:a[][3]={1,2,3,4,5,6,7,8,9};
可以省略一维的大小,但不可省略二维的大小
异常
原因
- 编写程序代码中的错误产生的异常
- Java内部错误发生的异常,Java虚拟机产生异常
- 通过throw(抛出异常)语句手动生成的异常
分类
处理异常
JVM默认处理异常的方式:
- 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
- 程序停止执行,异常下面的代码不会再执行了
try - catch 方式处理异常:可以让程序继续往下执行,不会停止
throws异常处理
Throwable方法
- public String getMessage():返回此throwable的详细消息字符串
- public String toString():返回此可抛出的简短描述
- public void printStackTrace():把异常的错误信息输出在控制台
自定义异常
- 定义异常类
- 写继承关系
- 空参、带参构造
自定义异常类一般都是以Exception结尾
必须继承:Exception (编译异常) 或 RuntimeException (运行异常)
Throw 和 throws
集合**
Collection (单列)
遍历方式
迭代器遍历:不依赖索引,删除元素时使用
- 遍历结束指针不会复位
- 循环中只能用一次next方法
- 不能用集合的方法进行增加或删除
增强for循环:底层是迭代器,修改增强for中的变量,不会改变集合原数据
Lambda表达式遍历:default void forEach(Consumer<? super T> action);
常用方法
List(有序 可重复 有索引)
**遍历方式:**迭代器、列表迭代器、增强for、Lambda表达式、普通for
-
列表迭代器:ListIterator
-
迭代器:删除
-
列表迭代器:添加
-
增强for、Lambda表达式:遍历
-
普通for:遍历时操作索引
**Vector:**和ArrayList几乎是完全相同,线程安全。Vector每次扩容请求其大小的2倍空间,而ArrayList是1.5倍
ArrayList、LinkedList
线程不安全,相对线程安全的Vector,执行效率高,ArrayList是动态数组的数据结构,LinkedList是双向链表的数据结构
对于查询操作ArrayList优于LinkedList,因为LinkedList要移动指针,对于新增和删除操作LinkedList比较占优势,因为ArrayList要移动数据
ArrayList集合底层原理:
- 利用空参创建的集合,在底层创建一个默认长度为0的数组
- 添加第一个元素时,底层会创建一个新的长度为10的数组
- 存满时,会扩容1.5倍
- 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准
Set(无序 不重复 无索引)
HashSet
无序、可以是 null、线程不安全
底层是哈希表
- JDK8之前:数组+链表
- JDK8开始:数组+链表+红黑树
底层原理:
哈希值的特点:
- 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
- 如果已经重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
- 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
**子类 LinkedHashSet:**有序,使用双向链表维护元素的次序
TreeSet
排序方式
- 自然/默认排序:该对象的类必须实现Comparable接口,重写compareTo(Object obj) 方法
- 定制/比较器排序:实现Comparator接口,重写compare
线程不安全、底层使用红黑树结构存储数据:
自平衡的二叉搜索树
1.每个结点是红的或者黑的
2 根结点是黑的
3 每个叶子结点是黑的(NULL)
4 树中不存在两个相邻的红色结点(即红色结点的父结点和孩子结点均不能是红色)
5 从任意一个结点 (包括根结点)到其任何后代 NULL 结点 (默认是黑色的)的每条路径都具有相同数量的黑色结点
加入红黑树的原因,也是为了避免链表过长,降低了效率。
那为何不直接用红黑树呢?还得加上链表?因为红黑树需要进行左旋,右旋操作, 而单链表不需要。
平衡:为了达到平衡,需要对树进行旋转。而红黑树能够达到自平衡,靠的也就是左旋、右旋和变色。
Map (双列)
遍历方式
键找值:
键值对:
Lambda表达式:
常用方法
put方法:添加/覆盖
Hashtable
子类 Properties:key 和 value 都是字符串类型
线程安全,不允许使用 null 作为 key 和 value
HashMap
允许使用null键和null值;线程不安全
子类 LinkedHashMap:有序,使用了一对双向链表来记录添加元素的顺序
TreeMap
线程不安全,可自然排序、定制排序
底层使用红黑树结构存储数据
ConcurrentHashmap
线程安全,多线程场景下使用
Collections
不可变集合
集合不能添加、删除、修改
List:直接用
Set:元素不能重复
Map:元素不能重复,键值对数量最多10个,超过10个用ofEntries
File类
绝对/相对路径
构造方法
判断、获取
public String getParent():返回给定文件对象的父对象
创建、删除
delete删除不走回收站、delete只能删除空文件夹
获取并遍历
public File[] listFiles():获取当前该路径下的所有内容
IO流
分类
按照数据的流向
- 输入流:读数据
- 输出流:写数据
按照数据类型来分
- 字节流 (记事本打开我们不能读懂):字节输入流,字节输出流
- 字符流 (记事本打开我们能读懂):字符输入流,字符输出流
使用场景
如果操作的是纯文本文件,优先使用字符流
如果操作的是图片、视频、音频等二进制文件。使用字节流
如果不确定文件类型,优先使用字节流。字节流是万能的流
随用随创建,什么时候不用什么时候关闭
加密解密:异或一个数字两次会得到原结果
例如:
- 100^10 = 110
- 110^10 = 100
体系结构
字节流 (8位字节)
FileOutputStream
文件字节输出流 (写)
实现步骤:
- 创建字节输出流对象 (调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法,刷新数据
- 释放资源 (关闭此文件输出流 释放与此流相关联的任何系统资源)
实现换行:
- windows:\r\n
- linux:\n
- mac:\r
追加写入:public FileOutputStream(String name,boolean append)
创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
FileInputStream
文件字节输入流 (读)
实现步骤:
- 创建字节输入流对象
- 调用字节输入流对象的读数据方法
- 释放资源 (先开的流最后关闭)
int by;
while ((by=fis.read())!=-1){
System.out.print((char)by);
}
public int read(byte[] b):从输入流读取最多b.length个字节的数据;返回的是读入缓冲区的总字节数,也就是实际的读取字节个数
byte[] bys = new byte[1024]; //1024及其整数倍
int len;
while ((len=fis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
异常处理
为了避免出现异常,要使用finally关闭流,并且要判空!!
字符流 (16位字节)
字节流操作中文不是特别的方便,所以Java就提供字符流。
字符流 = 字节流 + 字符集
编码规则
- 在计算机中,任意数据都是以二进制的形式来存储的
- 计算机中最小的存储单元是一个字节
- ASCII字符集中,一个英文占一个字节
- 简体中文版Windows,默认使用GBK字符集
- GBK字符集完全兼容ASCII字符集
- 一个英文占一个字节,二进制第一位是0
- 一个中文占两个字节,二进制高位字节的第一位是1
Unicode字符集的UTF-8编码格式
- 一个英文占一个字节,二进制第一位是0,转成十进制是正数
- 一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
乱码原因
- 读取数据时未读完整个汉字
- 编码和解码时的方式不统一
解决乱码
- 不用字节流读取文本文件
- 编码解码时使用同一个码表,同一个编码方式
编码解码
IDEA默认使用 UTF-8编码方式
- 一个英文一个字节
- 一个中文三个字节
eclipse默认使用 GBK编码方式
- 一个英文一个字节
- 一个中文两个字节
public byte[] getBytes():使用默认方式进行编码
public byte[] getBytes(String charsetName):使用指定方式进行编码
String(byte[] bytes):使用默认方式进行解码
String(byte[] bytes, String charsetName):使用默认方式进行解码
FileReader
字符输入流 (读)
- public FileReader(File file):创建字符输入流关联本地文件
- public FileReader(String pathname):创建字符输入流关联本地文件
public int read():读取数据,读到末尾返回-1
public int read(char[] buffer):读取多个数据,读到末尾返回-1
注意
- 按字节进行读取,遇到中文一次读多个字节,读取后解码返回一个整数
- 读到文件末尾了,read方法返回-1
原理解析
FileWriter
字符输出流 (写)
public void flush():将缓冲区中的数据刷新到本地文件,还可以继续往文件写数据
public void close():释放资源/关流,无法往文件中写出数据
缓冲流
底层自带了长度为8192的缓冲区提高性能
字节缓冲流
BufferedInputStream:字节缓冲输入流
BufferedOutputStream:字节缓冲输出流
字符缓冲流
BufferedReader:字符缓冲输入流
public String readLine():读取一行数据
String line;
while((( line = br.readLine()) != null)){
System.out.println(line);
}
字符缓冲输出流
public void newLine():跨平台的换行
转换流
作用:
- 指定字符集读写数据
- 字节流想要使用字符流中的方法
InputStreamReader:从字节流到字符流 (输入)
OutputStreamWriter:从字符流到字节流 (输出)
序列化流
序列化: 将数据结构或对象转换成二进制字节流的过程
反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程
ObjectOutputStream:对象序列化流
- public final void writeObject(Object obj):对象序列化写出到文件
ObjectInputStream:对象反序列化流
- public Object readObject():序列化本地文件中的对象读取到程序
实现:
- JDK 自带的序列化,只需实现 java.io.Serializable接口即可
- 生成序列化ID,作为版本号(Javabean定义完后生成),当文件中的内容跟对象中的版本号不匹配时反序列化报错
- 对于不想序列化的变量,使用 transient 关键字修饰
transient 只能修饰变量,不能修饰类和方法。
transient 修饰的变量,在反序列化后变量值将会被置成类型的默认值。如果是修饰 int 类型,那么反序列后结果就是 0。static 变量因为不属于任何对象(Object),所以无论有没有 transient 关键字修饰,均不会被序列化。
打印流
PrintStream
字节打印流
PrintWriter
字符打印流
底层有缓冲区,想要自动刷新需要开启
多线程
基本概念
- 并行:同一时刻,多个CPU同时执行多个任务,多个人同时做不同的事
- 并发:在同一时刻,一个CPU交替执行多个任务,秒杀、多个人做同一件事
- 进程:程序的基本执行实体,每一个正在运行的软件就是一个进程
- 线程:操作系统中能够运算调度的最小单位,被包含在进程之中,是进程中的实际运作单位
使用场景:文件下载;后台任务;异步处理
实现方式
方式一:继承Thread类
1. 创建一个继承于Thread类的子类
- 重写Thread类的run() ,将此线程执行的操作声明在run()中
- 创建Thread类的子类的对象,即创建了线程对象
- 通过此对象调用start():启动当前线程,调用当前线程的run()
一 个线程对象只能调用一次 start() 方法启动
方式二:实现Runnable接口
-
定义子类 ,实现 Runnable接口
-
子类中重写 Runnable接口中的 run()方法
-
通过 Thread类含参构造器创建线程对象
-
将 Runnable接口的子类对象作为实际参数传递给 Thread类的构造器中
-
调用 Thread类的 start()方法,开启线程调用 Runnable子类接口的 run()方法
VS 方式一:没类的单继承性的局限性;多个线程可以共享同一个接口实现类的对象,更适合来处理多个线程共享数据的情况
方式三:实现Callable接口
-
相比 run() 方法,重写 call() 方法,可以有返回值
-
call() 方法可以抛出异常
-
Callable 支持泛型的返回值
-
需要借助 FutureTask 类,获取返回结果
成员方法
抢占式调度:随机
线程优先级,默认5(最小1,最大10)
线程分类
守护线程:当其他的非守护线程执行完毕之后,守护线程会陆续结束
- 应用场景:QQ聊天并且发文件,关闭聊天窗口发送文件就取消
出让/礼让线程:出让CPU的执行权
插入/插队线程:插入到当前线程之前执行
生命周期
线程同步
方式一:同步代码块
该类继承thread类会创建多个对象,如需共享资源,成员变量需要加static静态关键字修饰
synchronized(要同步的对象){ 要同步的操作 }
锁对象一定要是唯一的,一般把当前类的字节码文件对象作为锁对象:类.class
方式二:同步方法
private synchronized void method(){ 要同步的操作 }
锁对象不能自己指定。
非静态:this;静态:当前类的字节码文件对象
方式三:Lock锁 (更灵活的代码控制)
实现类对象:ReentrantLock
- lock.lock(); //锁
- lock.unlock(); //释放锁
加锁释放锁当中如果有循环语句,需要加上try catch finally在最后释放锁,有可能锁资源得不到释放,程序无法停止
死锁
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
解决死锁:
- 剥夺某些进程所占有的资源
- 撤消某些进程
线程通信
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
- 令当前线程挂起并放弃 CPU 、 同步资源并等待, 使别的线程可访问并修改共享资源,而当前线程排队等候其他线程调用 notify() 或 notifyAll() 方法唤醒,唤醒后等待重新获得对监视器的所有权后才能继续执行
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程
注意:
sleep() 和 wait()
相同:一旦执行方法,都可以使当前的线程进入阻塞状态
不同:
- 两个方法声明的位置不同:Thread类中声明sleep(), Object类中声明wait()
- 调用的要求不同:sleep()可以在任何需要的场景先调用。wait()必须在同步代码块或同步方法中调用
- 是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁
线程池
核心原理
- 创建一个池子,池子是空的
- 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
- 如果提交任务时,池子中没有空闲的线程,也无法创建新的线程,任务就会排队等待
代码实现
- 创建线程池
- 提交任务
- 所有的任务全部执行完毕,关闭线程池 (一般不会关闭)
通过 ThreadPoolExecutor 创建
推荐通过 new ThreadPoolExecutor() 的写法创建线程池,这样写线程数量更灵活,开发中多数用这个类创建线程
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize :线程池中核心线程数的最大值
maximumPoolSize :线程池中能拥有最多线程数
workQueue:用于缓存任务的阻塞队列
当调用线程池execute() 方法添加一个任务时,线程池会做如下判断:
1、如果有空闲线程,则直接执行该任务;
2、如果没有空闲线程,且当前运行的线程数少于corePoolSize,则创建新的线程执行该任务;
3、如果没有空闲线程,且当前的线程数等于corePoolSize,同时阻塞队列未满,则将任务入队列,而不添加新的线程;
4、如果没有空闲线程,且阻塞队列已满,同时池中的线程数小于maximumPoolSize ,则创建新的线程执行任务;
5、如果没有空闲线程,且阻塞队列已满,同时池中的线程数等于maximumPoolSize ,则根据构造函数中的 handler 指定的策略来拒绝新的任务。
核心线程数 (不能小于0)
最大线程数 (最大数量>=核心线程数)
空闲线程存活时间 (不能为0)
空闲线程存活时间的单位 (用TimeUnit指定)
任务队列 (不能为null)
线程工厂 (不能为null)
拒绝策略 (不能为null)
阻塞/任务队列
ArrayBlockingQueue:底层是数组,有界
LinkedBlockingQueue:底层是链表,无界,最大为int的最大值
拒绝策略
ThreadPoolExecutor.AbortPolicy:默认策略,丢弃任务并抛出异常
ThreadPoolExecutor.DiscardPolicy:丢弃任务,不抛出异常,不推荐
ThreadPoolExecutor.DiscardOldestPolicy:抛弃队列中等待最久的任务,把当前任务加入队列
ThreadPoolExecutor.CallerRunPolicy:调用任务的run()方法绕过线程池直接执行
成员方法
submit:可以执行有返回值的任务或者是无返回值的任务
execute:只能执行不带返回值的任务
通过 Executors 创建
- Executors.newFixedThreadPool:创建有上限的线程池,创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待
- Executors.newCachedThreadPool:创建一个没有上限的线程池,创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程
- Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序
- Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池
- Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池
- Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】
线程池多大合适
CPU 密集型运算:项目中计算比较多,读取文件或数据库的操作比较少
- 最大并行数+1
I/O 密集型运算:读取文件或数据库的操作比较多,大部分是这种
网络编程
软件架构
C/S 客户端/服务器
1. 画面可以做的非常精美,用户体验好
2. 需要开发客户端,也需要开发服务端
3. 用户需要下载和更新的时候太麻烦
B/S 浏览器/服务器
1. 不需要开发客户端,只需要页面+服务端
2. 用户不需要下载,打开浏览器就能使用
3. 如果应用过大,用户体验收到影响
三要素
IP地址
设备在网络中的地址,是唯一的标识
IP分类
IPv4:互联网通信协议第四版,32位地址长度,分成四组
IPv6:互联网通信协议第六版,128位地址长度,分成8组
IP形式
- 公网地址、私有地址 (局域网使用)
- 192.168. 开头的就是常见的局域网地址
- 范围为192.168.0.0–192.168.255.255,专门为组织机构内部使用
常用命令
- ipconfig:查看本机IP地址
- ping IP地址:检查网络是否连通
- 本机IP:127.0.0.1或者localhost,称为回送地址或本地回环地址
IP操作类
端口
应用程序在设备中唯一的标识
协议
数据在网络中传输的规则,常见协议有UDP、TCP、http、https、ftp
TCP
三次握手建立连接
四次挥手断开连接
UDP
单播:一对一的发送数据
组播:一对多,给一组电脑发送数据
- 组播地址:224.0.0.0~239.255.255.255
- 预留的组播地址:224.0.0.0~224.0.0.255
广播:一对多,可以给局域网中所有电脑发送数据
- 广播地址:255.255.255.255
其他内容
泛型
泛型的本质是参数化类型。三种使用方式:泛型类、泛型接口、泛型方法
参数类型规范
- E:Element (在集合中使用,因为集合中存放的是元素)
- T:Type(Java 类)
- K:Key(键)
- V:Value(值)
- N:Number(数值类型)
- ?:表示不确定的java类型
泛型擦除:编译器会在编译期间「擦除」泛型语法并相应的做出一些类型转换动作
枚举
自定义实现
- 将构造器私有化,目的是防止被new出对象
- 去掉 setXxxx() 方法,防止属性被修改
- 在Season内部,直接创建固定对象
- 对外暴露对象(通过为对象添加 public static final 修饰符)
注解
标准注解:@Override、@Deprecated、@SuppressWarnings等,使用这些注解后编译器就会进行检查
元注解:用于定义注解的注解,包括@Retention、@Target、@Inherited、@Documented、@Repeatable 等
自定义注解:根据自己的需求定义注解
反射
获取Class对象
- 类名.class
- 对象名.getClass()
- Class.forName(全类名)
区别
获取对象
创建对象的方法
- T newInstance(Object… initargs):根据指定的构造器创建对象
- public void setAccessible(boolean flag):设置为true,表示取消访问检查,进行暴力反射
调用成员方法的方法
给成员变量赋值的方法
- void set(Object obj, Object value):赋值
- Object get(Object obj):获取值
lambda表达式
操作符为 “->”
左侧:指定了 Lambda 表达式需要的参数列表
右侧:指定了 Lambda 体,是Lambda 表达式要执行的功能
方法引用
引用静态方法、引用成员方法、引用构造方法、类名引用成员方法、引用数组构造方法
Stream流
步骤
1. 创建 Stream (一个数据源(如:集合、数组),获取一个流)
2. 中间操作 (一个中间操作链,对数据源的数据进行处理)
- 终止操作 ( 一旦执行终止操作,就终止中间操作链,并产生结果)
注意
- Stream 自己不会存储元素
- Stream 不会改变源对象
- Stream 操作是延迟执行的
中间操作
filter 筛选:Stream<Integer> stream = integerList.stream().filter(i -> i > 3);
distinct 去重:Stream<Integer> stream = integerList.stream().distinct();
limit 返回指定流个数:Stream<Integer> stream = integerList.stream().limit(3);
skip 跳过流中的元素:Stream<Integer> stream = integerList.stream().skip(2);
concat 合并流:Stream.concat(Stream a, Stream b)
map 流映射:
List<Integer> collect = stringList.stream()
.map(String::length)
.collect(Collectors.toList());
flatMap 流转换:
List<String> strList = wordList.stream()
.map(w -> w.split(" "))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
allMatch 匹配所有元素:integerList.stream().allMatch(i -> i > 3)
anyMatch匹配其中一个:integerList.stream().anyMatch(i -> i > 3)
noneMatch全部不匹配:integerList.stream().noneMatch(i -> i > 3)
终端操作
foreach 遍历:stringList.stream().forEach(System.out::println);
count 统计元素个数:Long result = integerList.stream().count();
findFirst 查找第一个
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findFirst();
findAny 随机查找一个
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findAny();
reduce 将流中的元素组合:int sum = integerList.stream().reduce(0, Integer::sum);
toArray() 返回数组:Object[] arr = list.stream().toArray();
collect 返回集合:
List<Integer> intList = stringList.stream()
.map(String::length)
.collect(Collectors.toList());
integerList.stream().limit(3);
skip 跳过流中的元素:Stream stream = integerList.stream().skip(2);
concat 合并流:Stream.concat(Stream a, Stream b)
map 流映射:
List collect = stringList.stream()
.map(String::length)
.collect(Collectors.toList());
flatMap 流转换:
List strList = wordList.stream()
.map(w -> w.split(" "))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
allMatch 匹配所有元素:integerList.stream().allMatch(i -> i > 3)
anyMatch匹配其中一个:integerList.stream().anyMatch(i -> i > 3)
noneMatch全部不匹配:integerList.stream().noneMatch(i -> i > 3)
#### 终端操作
```java
foreach 遍历:stringList.stream().forEach(System.out::println);
count 统计元素个数:Long result = integerList.stream().count();
findFirst 查找第一个
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findFirst();
findAny 随机查找一个
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findAny();
reduce 将流中的元素组合:int sum = integerList.stream().reduce(0, Integer::sum);
toArray() 返回数组:Object[] arr = list.stream().toArray();
collect 返回集合:
List<Integer> intList = stringList.stream()
.map(String::length)
.collect(Collectors.toList());