JavaSE进阶
2020-11-10 09:44:55 0 举报
AI智能生成
javase基础笔记
作者其他创作
大纲/内容
JavaSE进阶
关键字
package
定义包
import
导包
class
定义类
获取Class对象
new
void
基本数据类型
byte
short
char
int
long
float
double
boolean
null
return
流程控制
if
else
while
do
for
break
continue
布尔常量
true
false
static
修饰符
静态
被修饰的属于类 不属于对象被所有对象共享使用
静态内容优先于对象存在
修饰内容
成员变量
变量值属于类 可以被所有对象共享
成员方法
方法中不能使用this super
构造代码块
类加载的时候执行 只执行一次
extends
class 子类 extends 父类{...}
this
当前对象引用
作用
区分局部变量和成员变量
this.variable
成员方法中调用本类其他成员方法
this.method()
在本类构造方法第一行调用本类其他构造方法
this()
super
父类对象引用
区分子类成员变量与父类成员变量
子类成员方法中调用父类成员方法
super.method()
在本类构造方法第一行调用父类构造方法
super()
abstract
声明抽象
public abstract class 类名{ public abstract 返回值类型 方法名(形参列表);}
final
最终
修饰类
不能被继承
修饰方法
不能被重写
修饰变量
基本数据类型 值不能修改引用数据类型 地址不能修改
权限修饰符
public
所有都可以访问
protected
同一个包以及不同包的子类
默认
同一个包中
private
同一个类中
interface
声明接口
public interface 接口名{ 接口成员}
implements
实现接口
public class 类名 implements 接口名{...}
default
接口中声明默认方法
instanceof
检查给定的对象是否是一个特定的类或接口的实例
if(对象名 instanceof 类名){...}
异常相关
throws
try
catch
finally
transient
修饰的成员不会被序列化
enum
设计模式
模板模式 Template
用法
单例模式 Singleton
保证一个类能且仅能创建一个对象
使用场景
可用于共享数据
实现方式
程序员式
1.私有化构造2.维护一个public final static修饰的本类对象3.通过类名.对象名获取对象
饿汉式
1.私有化构造2.维护一个private static修饰的本类对象3.提供一个public static getInstance()静态方法返回本类对象4.通过类名.静态方法获取本类对象
懒汉式
数据结构
栈
先进后出
队列
先进先出
数组
内存中顺序存储
链表
节点链接节点
树
二叉树
专业词语
节点
parent
left
right
data
根节点
左右子树
度
树高
度为2的树
二叉查找树
1.二叉树2.左子树的值比自身小3.右子树的值比自身大
平衡二叉树
1.二叉查找树2.左右子树高度差不超过13.任意节点左右子树都是平衡二叉树
旋转
左旋
根节点的右侧往左拉原先的右子节点变成新的父节点并把多余的左子节点出让给已经降级的根节点当右子节点
右旋
根节点的左侧往右拉左子节点变成了新的父节点并把多余的右子节点出让给已经降级根节点当左子节点
左左
根节点左子树的左子树有节点插入
直接对整体进行右旋
左右
当根节点左子树的右子树有节点插入
左旋子树 后整体右旋
右右
当根节点右子树的右子树有节点插入
直接对整体进行左旋
右左
当根节点右子树的左子树有节点插入
右旋子树 后整体左旋
红黑树
Entry
color
key&value
通过红黑规则达到平衡(非高度平衡)的二叉查找树
红黑规则
只有红色和黑色的节点 根节点始终为黑
叶子节点都为黑
叶子节点(节点不存在子节点或者为空节点被称作叶子节点)
不能红红相连
添加节点
被添加的节点颜色为红
直接变黑
非根节点
父节点为黑
直接插入
父节点为红
叔叔节点为红
1.父变黑2.叔变黑3.祖父变红(根节点为黑)
叔叔节点为黑
1.父变黑2.祖父变红3.绕祖父旋转(根节点为黑)
杂
::运算符
引用方法
格式
<Class name>::<method name>
例子
stream.forEach( s-> System.out.println(s));//lambda写法stream.forEach( System.out::println); //::运算符写法
可以引用的方法
静态方法
构造函数
面向对象
包
管理class
分层思想
三层架构
Controller
与用户交互
Service
业务控制
Dao
数据存取
辅助包
utils
第三方工具类
domain
模型类
entry
程序入口
继承
概念
类与类之间存在包含(is a)关系时 可以用继承描述这种关系
好处和弊端
注意事项
类与类之间只能单继承
类的继承具有传递性
所有的类都直接或间接的继承了Object类
构造方法特点
构造方法不能被继承
创建子类对象时默认一定会先创建父类对象
子类构造方法第一行默认调用父类空参构造
每个构造方法只能在第一行调用一次其他构造方法
方法重写
在子类中编写了与父类方法声明一模一样的方法包括返回值 方法名 参数列表
重写可以在不改变父类的方法声明前提下 对父类方法扩展增强
子类不能重写父类的私有方法 静态方法 构造方法
子类重写的方法权限必须不小于父类方法权限
抽象类
包含抽象方法的类
对类的抽象
强制子类重写抽象方法
抽象类不能直接创建对象
子类要么重写全部抽象方法 要么继续抽象
可以有构造方法
抽象类不一定有抽象方法有抽象方法的类一定是抽象类
接口
行为的抽象
制定规则
提升程序扩展性
接口成员
JDK7以前
常量
public static final 类型 常量名
默认添加 "public static final"
抽象方法
默认添加 "public abstract"
JDK8新增
可以通过接口名直接调用
默认方法
通过实现类对象调用
如果有多个接口有相同的默认方法 则实现类必须重写该方法
JDK9新增
私有方法
为静态方法和默认方法服务 用private修饰 外界无法调用
接口不能直接创建对象
接口没有构造方法
接口与接口之间可以多继承
一个类可以同时实现多个接口
实现类必须重写所有方法 否则只能是抽象类
代码块
用"{}"括起来的代码
局部代码块
方法中定义
限定变量生命周期
类中方法外定义
每次构造方法执行时 都会在构造方法第一行之后执行
可以将多个构造方法中相同的代码抽取到构造代码块中
静态代码块
类中方法外 用static修饰
只在类加载的时候执行一次
在类加载时做一些初始化操作
多态
一个对象 多种形态
好处与弊端
提升代码扩展性
不能使用子类特有内容
前提
有继承或接口实现
父类引用指向子类对象使用父类类型变量 保存子类类型对象
成员访问特点
编译和运行都看父类
编译看父类 运行看子类
转型
向上转型
子转父
向下转型
为了使用子类特有的内容
使用强制类型转换
异常
ClassCastException
实际类型与目标类型不一致时
解决方法
使用instanceof 关键字判断 然后再转
if(对象名 instanceof 类名){ 类名 新对象名 = (类名)对象名;}
多态转型只影响形态 本质(地址)没有变化
推荐只在方法形参和返回值类型使用多态
内部类
在类的内部定义的另一个类
成员内部类
成员变量位置
局部内部类
局部变量位置
匿名内部类
new 父类或接口(){ 重写父类或接口的方法;};
lambda
概述
JDK8新增的一种语法
本质上是一个没有名字的方法(匿名方法)
接口类型
接口中有且仅有一个抽象方法
语法
(参数列表)->{方法体;return 返回值;}
省略规则
形参的数据类型可以省略
当形参只有一个时 小括号可以省略
当语句只有一条时 分号 return 大括号都可以省略
lambda与匿名内部类关系
匿名内部类可以是接口 抽象类 具体类lambda只能是有且仅有一个抽象方法的接口
可以用lambda的地方一定可以用匿名内部类可以用匿名内部类的地方不一定能用lambda
lambda编译后不会产生.class文件 运行时动态生成字节码匿名内部类编译后会产生.class文件
泛型
<类型>
类型用字母表示
常用字母
好处
避免了强制类型转换
泛型类
public class Class<E> {}
修饰符 class 类名<类型> { }
泛型方法
修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
泛型接口
修饰符 interface 接口名<类型> { }
public interface Interface<E> {}
泛型通配符
<?>
<? extends 类型>
是"类型"的或者其子类型
<? super 类型>
是"类型"的或者其父类型
多态+泛型
泛型尖括号里的类型不支持直接用多态
ArrayList<Animal> alist = new ArrayList<Dog>();//该代码不通过编译
API
常用API
Math
基本数字运算
常用方法
public static int abs(int a)
返回绝对值
舍入相关
public static double ceil(double a)
返回进一法舍入结果
public static double floor(double a)
返回去尾法舍入结果
public static int round(float a)
返回四舍五入结果
最大最小值
求幂
public static double random()
System
几个有用的字段和方法
public static void exit(int status)
终止当前运行的虚拟机 非零表示异常终止
public static native long currentTimeMillis()
返回当前系统时间毫秒值
拷贝数组
Object
所有类的基类
比较 建议重写
public boolean equals(Object obj) { return (this == obj); }
转字符串 建议重写
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
Objects
对象工具类
null值判断
public static boolean isNull(Object obj)
public static boolean nonNull(Object obj)
返回参数中对象的字符串形式
public static String toString(Object o)
BigDecimal
精确计算
对象创建
构造方法建议使用字符串
public BigDecimal(String val)
public static BigDecimal valueOf(double val)
四则运算
加 减 乘
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
除
如果无法计算出精确结果则抛出ArithmeticException因此建议使用上述参数的除法并指定小数位数(scale)
字符串相关
String
内容不可改变
字符串无法打印地址
构造方法
public String()
创建一个空白字符串对象
public String(char value[])
根据char数组内容创建String对象
public String(String original)
根据传入的字符串内容创建String对象
String s = "abc";
直接赋值创建字符串对象
细节问题
相同的字符串只存储一个在常量池中
直接赋值创建的String对象引用常量池内字符串的地址
new创建的String对象引用堆里的地址
直接赋值创建时 常量与常量拼接时存在常量优化机制
直接赋值创建时 变量与常量相加会创建一个新的字符串
字符串内容比较
str1.equals(str2)
equalsIgnoreCase忽略大小写比较
toUpperCase 返回大写字符串toLowerCase 返回小写字符串
字符遍历
charAt(int index)
toCharArray转换成char数组
字串截取
substring
字串替换
replace
如果匹配多个 会全部替换
字符串切割
split
子串相关
public int indexOf(String str)
返回此字符串的指定子串第一次出现处的索引
public boolean contains(CharSequence s)
当且仅当此字符串包含指定序列返回true
StringBuilder
可变长度的字符串 线程不安全
链式调用
方法返回对象本身(this)则可以链式调用
append
拼接
reverse
反转
length
获取长度
toString
转换成字符串
StringBuilder效率高的原理
String拼接每次都要创建两个对象
StringBuilder只有一个对象
包装类
基本类型和包装类的对应关系
byte short char int long float double boolean
Byte Short Character Integer Long Float Double Boolean
Integer
int类型包装类包装一个对象中的原始类型 int 的值
构造方法(已过时)
public Integer(int value)
public Integer(String s)
public static Integer valueOf(int i)
public static Integer valueOf(String s)
自动装箱 自动拆箱 (JDK1.5)
自动装箱
把基本数据类型转换为对应的包装类类型
自动拆箱
把包装类类型转换为对应的基本数据类型
调用的对象的intValue()方法 把Integer转换成int类型
与String类型转型
int -> String
int i = 0;String s = i+"";
String s = String.valueOf(0);
String -> int
int i = Integer.parseInt("0");
时间日期
计算机时间原点
1970-01-01 00:00:00 GMT1970-01-01 08:00:00 CST
Date
时间日期类
public Date()
以当前时间创建
public Date(long date)
以输入的毫秒值创建
public long getTime()
返回自原点开始的毫秒值
public void setTime(long time)
以毫秒值设置时间日期
SimpleDateFormat
时间日期格式化
1.formatting (date → text)2.parsing (text → date)3.normalization
常用pattern
yyyy-MM-dd HH:mm:ss
public SimpleDateFormat(String pattern)
以指定pattern创建对象
public Date parse(String source) throws ParseException
解析字符串
public final String format(Date date)
格式化成字符串
public void applyPattern(String pattern)
修改pattern
LocalDate
参考LocalDateTime
LocalTime
LocalDateTime
对象获取
public static LocalDateTime now()
获取当前时间的LocalDateTime对象
获取指定时间的LocalDateTime对象
LocalDateTime.of方法的重载
对象转换
public LocalDate toLocalDate()
public LocalTime toLocalTime()
解析&格式化
public String format(DateTimeFormatter formatter)
格式化为字符串
解析成时间日期对象
时间日期增减
以增减天为例 年月日时分秒类似
增减的方法参数均可使用负数
plus系列
增加
public LocalDateTime plusDays(long days)
minus系列
减少
public LocalDateTime minusDays(long days)
with系列
直接修改时间日期
以修改天为例 年月日时分秒类似
public LocalDateTime withDayOfMonth(int dayOfMonth)
get系列
获取时间日期
以获取天为例 年月日时分秒类似
public int getDayOfMonth()
格式化相关
DateTimeFormatter
public static DateTimeFormatter ofPattern(String pattern)
时间间隔相关
Period
计算年月间隔
参数使用LocalDate对象
public long toTotalMonths()
计算两个日期一共相差几个月
get系列获取各个属性的值Period属性存储的是两个日期类的各个属性的差值
Duration
计算天 时间间隔
参数要求实现Temporal接口并且要能获取秒 否则抛出异常
to系列
获取两个时间之间一共相差多少
数组操作
二分查找
前提条件
数组已排序
思路
1.定义两个变量作为查找的边界2.计算中间索引3.判断中间索引指向的元素是否是要查找的元素4.若不是则根据大小比较结果修改查找边界5.直到查到元素或者查找范围缩小到不存在
具体实现参考
补充
结构
冒泡排序
递归
递归算法可以把本身问题分解规模小的同类问题,通过求解规模小的同类问题的解
使用步骤
明确你这个方法想要干什么
寻找递归结束条件
找出方法的等价关系式(递归规则) 每次调用缩小范围
经验
如果用循环解决问题不困难得话,可以使用循环如果解决起来比较困难,可以考虑递归(递和归)
快速排序
核心思路
之后在基准数的左右两边递归调用
Arrays
数组工具类
public static void sort(int[] a)
排序
public static String toString(int[] a)
二分查找 需要已经排序的数组
集合
体系结构
Collection
List
ArrayList
LinkList
Set
HashSet
TreeSet
Map
HashMap
TreeMap
集合 vs 数组
都是容器 可以存储多个数据
数组的长度是不可变的 集合的长度是可变的
数组可以存基本数据类型和引用数据类型集合只能存引用数据类型 基本数据类型使用包装类
单列集合容器的顶级接口
接口通过多态获取对象
boolean add(E e)
添加元素
boolean remove(Object o)
从集合中移除指定的元素
boolean removeIf(Predicate<? super E> filter)
根据条件进行移除元素
参数可用lambda
boolean contains(Object o)
判断集合中是否存在指定的元素
boolean isEmpty()
判断集合是否为空
int size()
获取集合的长度
void clear()
清空集合
迭代器
集合的专用遍历方式
Iterable<T>接口的实例的iterator()方法返回返回的迭代器默认指向当前集合的0索引处
Iterator<T> iterator()
boolean hasNext()
判断当前位置是否有元素可以被取出
E next()
void remove()
删除迭代器对象当前指向的元素
遍历集合
参考格式
ArrayList<T> list = new ArrayList<>();Iterator<T> iterator = list.iterator();while (iterator.hasNext()) { T t = iterator.next();}
原理
1.Iterator<E> iterator(): 获取迭代器对象 默认指向0索引2.boolean hasNext(): 判断当前位置是否有元素可以被取出3.E next(): 获取当前位置的元素 将迭代器对象移向下一个索引位置
增强for
简化数组和Collection集合的遍历
编译后对于数组是for 对于集合是一个迭代器Iterator
实现Iterable接口的类才可以使用迭代器和增强for
在增强for循环中无法改变数组或集合中的元素
三种遍历方法应用场景对比
进行遍历时使用 遍历过程中若要增删元素则不能使用
普通for
遍历过程中需要增删元素或操作索引时使用
注:遍历过程中需要选取出元素 然后再删除元素时使用 否则直接报错
类结构
SortedSet(有序集)
NavigableSet
AbstractCollection
AbstractSet
LinkedHashSet
AbstractList
Vector
Stack(后进先出)
AbstractSequentialList
LinkedList
Queue(队列)
Deque(双端队列)
AbstractQueue
PriorityQueue(优先队列)
ArrayBlockingQueue
LinkedBlockingDeque
BlockingQueue(阻塞队列)
Collection子接口
特点
存取有序
可重复
有索引
在指定索引添加元素
E remove(int index)
移除并返回指定索引的元素
E get(int index)
返回指定索引的元素
修改指定索引的元素
底层原理
用数组存储的单列集合
基本使用
可以添加任何类型
实际通过泛型限制集合的类型
add
在末尾添加元素
在指定索引处添加元素
remove
根据索引删除 返回被删除的元素
根据元素删除 返回布尔值表示是否成功
如果集合存储的全是数字 因为重载 所以删除按索引删除
set
修改元素 返回旧元素
get
根据索引获取元素
size
遍历
使用for循环
循环中删除元素
倒序遍历删除
正序遍历删除会导致跳过元素需要配合索引减一
LinkedList vs ArrayList
底层是数组结构实现,查询快、增删慢
底层是链表结构实现,查询慢、增删快
public void addFirst(E e)
在开头添加元素
public void addLast(E e)
public E getFirst()
返回列表中的第一个元素
public E getLast()
返回列表中的最后一个元素
public E removeFirst()
列表中删除并返回第一个元素
public E removeLast()
列表中删除并返回最后一个元素
底层实现
用双向链表存储的单列集合
不可重复
无索引
存取顺序不一致(但有序)
并没有什么特殊方法
不重复
没索引
按照规则排序元素
自然排序
泛型类需要实现Comparable<T>接口中的compareTo方法
比较器排序
自然 vs 比较器
不同
自然
能满足大部分情况
比较器
存储没有修改权限的类时可以使用(如:String 包装类等)
相同
返回规则一样
如果返回值为负数 表示当前存入的元素是较小值 存左边
如果返回值为0 表示当前存入的元素跟集合中元素重复了 不存
如果返回值为正数 表示当前存入的元素是较大值 存右边
Set的所有特点
哈希表结构
哈希值
获取方式
Object类中成员方法public int hashCode()根据对象的地址值计算出哈希值
没有重写hashCode方法
不同对象调用返回值不同
子类重写hashCode方法
JDK7及以前
哈希表=数组+链表
JDK8及以后
存储流程
计算元素哈希值
计算存入数组中的索引位置
判断存入点是否为空
为空
直接存入
不为空
用equals方法判断是否相同
相同元素
抛弃
不同元素
判断结构
存入链表
存入红黑树
使用hashSet记得重写hashCode和equals
Queue
双列集合 键与值一一对应(键值对)
key不能重复 value可以重复
key与value一一对应
"键值对"称为"Entry"对象
集合的长度
boolean containsKey(Object key)
判断集合是否包含指定的键
boolean containsValue(Object value)
判断集合是否包含指定的值
V remove(Object key)
根据键删除键值对元素
移除所有的键值对元素
遍历方式
Set<K> keySet()
获取所有键的集合
V get(Object key)
根据键获取值
K getKey()
V getValue()
3.forEach遍历
依赖hashCode和equals保证key唯一
key存储自定义对象需要重写hashCode和equals
红黑树结构
Properties
Properties extends Hashtable
默认编码ISO-8859-1
可以保存到流中(store方法)从流中加载(load方法)
只存字符串
读
public synchronized void load(Reader reader)
public synchronized void load(InputStream inStream)
写
设置集合的键和值底层调用ConcurrentHashMap(并发HashMap)的put方法
public String getProperty(String key)
指定键搜索属性
public Set<String> stringPropertyNames()
返回一个不可修改的键集
HashTable
ConcurrentHashMap
不可变集合 JDK9
在整个生命周期中集合是不可被修改(增、删、改)的
创建方法
Map接口中ofEntries方法可以把键值对封装成一个Entry对象再把这个Entry对象添加到集合当中从而创建不可变集合
应用场景
不希望集合内容被修改时(Dao传数据给Service)
可变参数
修饰符 返回值类型 方法名(数据类型... 变量名) { }
public void method(int... nums){}
如果一个方法有多个参数,包含可变参数,可变参数放在最后
当参数类型确定,个数不确定时使用,可以使用可变参数
Stream流
思想
函数式
流水线
方法
获取方法
default Stream<E> stream()
Arrays.stream(T[] array)
同种类型多个数据
Stream.of(T... values)
中间方法
filter
Stream<T> filter(Predicate<? super T> predicate)
过滤流中数据
limit
Stream<T> limit(long maxSize)
skip
Stream<T> skip(long n)
concat
合并a和b两个流为一个流
distinct
Stream<T> distinct()
返回由该流的不同元素(根据Object.equals(Object))组成的流
终结方法
forEach
void forEach(Consumer action)
对此流的每个元素执行操作
count
long count()
返回此流中的元素数
收集方法
collect
R collect(Collector collector)
把结果收集到集合中
Collector对象使用工具类Collectors创建
public static <T> Collector toList()
把元素收集到List集合中
public static <T> Collector toSet()
把元素收集到Set集合中
把元素收集到Map集合中
Function接口是函数式接口
参考例子
备注
集合不能在遍历的时候使用集合对象的add remove等方法修改集合
Throwable
Error
Exception
RuntimeException 及子类
其余的 Exception 子类
分类
运行时异常
无需显式处理(手动处理),也可以和编译时异常一样处理
编译时异常
必须显式处理(手动处理),否则程序就会发生错误,无法通过编译
JVM默认异常处理方式
1.打印栈追踪2.停止程序运行
处理异常方式
public void 方法() throws 异常类名 { //...}
在方法中 当传递的参数有误 没有继续运行的必要时采取抛出处理 抛给调用者处理异常
声明异常 调用方法时可能出现异常可以声明多个
编译时的异常 必须声明谁调用谁处理 最多让JVM来处理运行时异常可以不声明
throw
throw new 异常();
在方法内 表示当前代码手动抛出一个异常 下面的代码无法再执行了
一次只能抛一个异常一旦执行一定抛异常
try...catch
自己捕获并处理异常
try { // 可能出现异常的代码} catch(异常类名 变量名) { // 异常的处理代码}
执行流程
1.执行try语句块中语句2.出现异常跳转到对应的catch语句块3.执行完后程序继续往下执行
细节
try中没有遇到问题
跳过catch代码继续执行
try 中遇到了问题
直接跳转到catch语句块 try中剩余代码不执行
出现的问题没有被捕获
异常抛给调用者处理
同时可能出现多个异常
用多个catch捕获
多个异常之间存在父子关系 父类一定写在子类下面
try...catch...finally
try{ // 可能出现异常的代码}catch(异常类名 变量名){ // 异常的处理代码}finally{ // 执行所有清除操作}
finally中的return会覆盖之前的return
异常基类
常见方法
public String getMessage()
返回详细消息字符串
public String toString()
返回可抛出的简短描述
public void printStackTrace()
把异常的栈追踪输出在控制台
自定义异常
当Java中提供的异常不能满足需求时 可以使用自定义异常
public class 类名 extends RuntimeException { public 类名() { } public 类名(String message) { super(message); }}
类名用 "异常名+Exception"
实际开发过程中使用异常的原则
Java类库中定义的可以预检测方式避免的RuntimeException异常不应该通过catch的方式来处理比如:NullPointerException IndexOutOfBoundsException等等
catch 时请分清稳定代码和非稳定代码 稳定代码指的是无论如何不会出错的代码对于非稳定代码的 catch 尽可能进行区分异常类型 再做对应的异常处理
捕获异常是为了处理它 不要捕获了却什么都不处理而抛弃之如果不想处理它 请将该异常抛给它的调用者最外层的业务使用者 必须处理异常 将其转化为用户可以理解的内容
捕获异常与抛异常 必须是完全匹配 或者捕获异常是抛异常的父类
避免直接抛出 new RuntimeException()更不允许抛出 Exception 或者 Throwable应使用有业务含义的自定义异常推荐业界已定义过的自定义异常 如:DAOException ServiceException等
IO
IO体系
流式部分
字节流
输入流
InputStream(顶级父类)
输出流
OutputStream(顶级父类)
字符流
Reader
Writer
非流式部分
File
操作文件或文件夹
File(String pathname)
通过指定的路径字符串创建File对象
通过File表示的文件夹和子路径创建的File对象
路径
绝对路径
一个完整的路径
public String getAbsolutePath() 获取绝对路径
相对路径
创建
public boolean createNewFile() throws IOException
创建一个新的空文件
public boolean mkdirs()
创建多级目录
删除
public boolean delete()
删除File表示的文件或目录
判断
public boolean exists()
测试File是否存在
public boolean isDirectory()
测试File是否为目录
public boolean isFile()
测试File是否为文件
获取
public String getName()
返回File表示的文件名称或文件夹的名称
public File[] listFiles()
public long length()
返回文件大小
创建一个文件的方法
多级文件夹递归遍历
统计文件种类个数
遍历文件夹依然采用多级文件夹递归遍历的方式统计可以使用Map对象存储出现次数
IO流
读写文件内容
父类
读写文件
FileInputStream
public FileInputStream(String name)
public FileInputStream(File file)
1.创建对象2.读数据3.释放资源
public int read(byte[] b)
FileOutputStream
public FileOutputStream(String name)
1.创建对象2.写数据3.释放资源
void write(int b)
将指定的字节写入此文件输出流一次写一个字节数据
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流一次写一个字节数组数据
创建对象时 若文件不存在则创建 若文件存在默认直接清空
传递整数实际写出的是整数对应的数据
每次用完必须释放资源
换行
- windows:\\- linux:\- mac:\
追加写入
异常处理
字节缓冲流
输入
BufferedInputStream(InputStream in)
public int read()
public int read(byte b[])
输出
BufferedOutputStream(OutputStream out)
public void write(int b)
public void flush()
各在底层创建了一个默认长度为8192的字节数组作为缓冲区每次读写数据到缓冲区内存中直接读写两个缓冲区的数据
使用原则
读写对象(序列化)
序列化
对象->字节流
反序列化
字节流->对象
ObjectInputStream
ObjectInputStream(InputStream in)
创建从指定的InputStream读取的ObjectInputStream
反序列化方法
Object readObject()
从ObjectInputStream读取一个对象
ObjectOutputStream
ObjectOutputStream(OutputStream out)
创建一个写入指定的OutputStream的ObjectOutputStream
序列化方法
void writeObject(Object obj)
将指定的对象写入ObjectOutputStream
Serializable接口
静态成员不会被序列化
修饰的成员变量不会被序列化
serialVersionUID
如果修改了类中的信息.那么虚拟机会再次计算出一个序列号.
如果序列号不一致会抛出InvalidClassException异常
readObject()方法在访问到最后的时候会直接抛出一个EOFExceptionwhile(true)遍历时需要try...catch
只能操作纯文本文件
码表(字符集)
数字与字符对应关系的集合
常见字符集
ASCII字符集
GBXXX字符集
双字节编码中文
Unicode字符集
编码
解码
常见的编码/解码方式
ASCII编码
GBK编码
UTF-8编码
乱码
编码和解码的规则不一致,导致乱码
字符串相关方法
public byte[] getBytes()
public byte[] getBytes(String charsetName)
String(byte[] bytes)
通过使用平台的默认字符集解码指定的字节数组来构造新的String
构造一个新的String由指定用指定的字节的数组解码
字符流=字节流+编码表
解决字节流读取文本文件时出现乱码
抽象父类
FileReader
FileReader(File file)
在给定从中读取数据的 File 的情况下创建一个新 FileReader
FileReader(String fileName)
在给定从中读取数据的文件名的情况下创建一个新 FileReader
int read()
一次读一个字符数据
int read(char[] cbuf)
一次读一个字符数组数据
创建对象时 文件必须存在
用完必须关流释放资源
FileWriter
FileWriter(File file)
根据给定的File对象构造一个FileWriter对象
根据给定的File对象构造一个FileWriter对象append设定是否追加写入
FileWriter(String fileName)
根据给定的文件名构造一个FileWriter对象
根据给定的文件名以及指示是否附加写入数据来构造FileWriter对象
public void write(int c)
public void write(char cbuf[])
public void write(String str)
public void flush()
刷新流 还可以继续写
底层调用writeBytes()写出内存中的数据
public void close()
关闭流 释放资源
底层会先调用writeBytes()写出内存中的数据
创建对象时 若文件不存在则创建(父路径要存在) 若文件存在默认直接清空
写整数实际写出的是整数对应在码表的字母
写字符传数据时 把字符串原样写出
缓冲流
BufferedReader
BufferedReader(Reader in)
特有方法
String readLine()
BufferedWriter
BufferedWriter(Writer out)
public void newLine()
转换流
InputStreamReader(InputStream in)
使用默认字符编码创建InputStreamReader对象
使用指定的字符编码创建InputStreamReader对象
OutputStreamWriter(OutputStream out)
使用默认字符编码创建OutputStreamWriter对象
使用指定的字符编码创建OutputStreamWriter对象
指定字符集
JDK11以前
使用转换流指定字符集
JDK11开始
字符流增加新构造可以指定字符集
打印流
PrintStream
System.out是一个打印流对象
public PrintStream(OutputStream out)
write系列
同输出流
print系列
println系列
printf系列
PrintWriter
类似PrintStream
多线程
意义
提高程序执行效率
进程
正在运行的软件
操作系统资源分配的最小单位
线程
进程里至少有一个线程
CPU调度的最小单元
并行
同时执行
并发
交替执行
extends Thread
Thread类方法
void run()
void start()
1.定义类继承Thread2.在定义的类中重写run方法3.创建定义的类的对象4.对象调用start方法启动线程
implements Runnable
Thread构造方法
Thread(Runnable target)
分配一个新的Thread对象
implements Callable
Callable<V>接口方法
V call()
FutureTask<V>类方法
FutureTask(Callable<V> callable)
构造方法创建FutureTask对象一旦运行就执行给定的Callable
V get()
注意
get()方法的调用一定要在Thread类对象调用start()方法之后
Thread类
void setName(String name)
修改线程的名称
String getName()
返回此线程的名称
static Thread currentThread()
返回当前正在执行的线程对象的引用
static void sleep(long millis)
使当前正在执行的线程停留(暂停执行)指定的毫秒数
final int getPriority()
返回此线程的优先级
final void setPriority(int newPriority)
void setDaemon(boolean on)
优先级
Java使用抢占式调度模型 多线程程序执行具有随机性
守护线程
程序运行的时候在后台提供一种通用服务的线程
其他方法
boolean isAlive()
测试线程是否处于活动状态
void join()
void yield()
系统选择其他或具有更高优先级的线程执行,若无其他相同或更高优先级的线程,则该线程继续执行
线程同步
数据安全问题
出现条件
共享数据
不会共享的数据
多个线程操作共享数据
保证线程同步的方式
synchronized
同步代码块
synchronized(锁对象){...}
锁对象
对象、监视器、同步队列和执行线程之间的关系
分支主题
同步方法
修饰符 synchronized 返回值类型 方法名(方法参数){...}
静态同步方法
修饰符 static synchronized 返回值类型 方法名(方法参数){...}
类名.class
Lock接口
实现类ReentrantLock
ReentrantLock()
void lock()
加锁
boolean tryLock()
尝试加锁
void unlock()
释放锁
常在finally中调用
synchronized vs Lock
锁的细粒度和灵活度低
Lock
锁的细粒度和灵活度高
如何选择
死锁
线程死锁
可能产生的情况
资源有限
同步嵌套
避免
避免一个线程同时获取多个锁
线程通信
Object类方法
wait()
使当前线程等待同时释放锁直到另一个线程调用该对象的notify()方法或notifyAll()方法
notify()/notifyAll()
唤醒正在等待对象监视器的单个/所有线程并不立即释放锁
经典问题
生产者-消费者
消费者步骤
生产者步骤
阻塞队列(BlockingQueue)
在一个队列的基础上又支持了两个附加操作的队列
附加方法
void put(E e)
E take()
常用实现类
底层数组 有界
LinkedBlockingQueue
底层链表 无界 最大为int最大值
生产者-消费者模式
线程状态
Java线程状态
定义在java.lang.Thread.State枚举类中
线程池
存线程的容器
相关方法
Executors
static ExecutorService newCachedThreadPool()
创建一个默认的线程池
static ExecutorService newFixedThreadPool(int nThreads)
创建一个指定最多线程数量的线程池
ExecutorService接口
控制线程池
void shutdown()
AbstractExecutorService抽象类
Future<?> submit(Runnable task)
ThreadPoolExecutor
参数一:核心线程数量,线程池中初始线程数,刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动 而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程 当线程数超过核心线程数时,会将请求的任务放入任务队列参数二:最大线程数,当任务队列满时,如果线程数没有超过最大线程数时,创建新的线程参数三:空闲线程最大存活时间参数四:时间单位---TimeUnit参数五:任务队列 --- 当线程数超过核心线程数量小于最大线程数时,让任务在队列中等着,等有线程空闲了 再从这个队列中获取任务并执行 可用new ArrayBlockingQueue<>(capacity)参数六:创建线程工厂 --- 按照默认的方式创建线程对象 可用Executors.defaultThreadFactory()参数七:任务的拒绝策略 --- 可用new ThreadPoolExecutor.AbortPolicy() 1.什么时拒绝? 当提交的任务 > 池子中最大的线程数量+队列的容量 2.如何拒绝? 拒绝策略
执行顺序
线程池最多可执行的任务数 = 队列容量 + 最大线程数
最佳线程数目 = ((线程等待时间 + 线程CPU时间) / 线程CPU时间) * CPU数目
拒绝策略
ThreadPoolExecutor.AbortPolicy
丢弃任务并抛出RejectedExecutionException异常.默认的策略.
ThreadPoolExecutor.DiscardPolicy
ThreadPoolExecutor.DiscardOldestPolicy
ThreadPoolExecutor.CallerRunsPolicy
调用任务的run()方法绕过线程池直接执行
线程安全
JMM
Java Memory Model
JVM为了屏蔽各个硬件平台和操作系统对内存访问机制的差异化提出的概念
JMM结构
线程 <=> 工作内存(共享变量副本) <=(JMM控制)=> 主内存(共享变量)
JMM规定
线程安全的本质
可见性
原子性
有序性
线程安全-可见性
实现可见性必须保证
线程修改后的共享变量值能够及时从线程工作内存中刷新到主内存中
其他线程能够及时把共享变量的最新值从主内存更新到自己的工作内存中
volatile
线程写volatile变量的过程
JMM会把该线程对应的工作内存(本地内存)中的共享变量值刷新到主内存
线程读volatile变量的过程
JMM会把该线程对应的工作内存(本地内存)置为无效.线程接下来将从主内存中读取共享变量
具体过程
1.线程获得锁2.清空变量副本3.拷贝最新值4.执行代码5.最新值刷新到主内存6.释放锁
线程安全-原子性
Java中的原子操作
除了long和double之外的所有原始类型的赋值
所有volatile变量的赋值
java.concurrent.Atomic* 类的所有操作
锁共享变量的操作
CAS
原子操作类
更新基本类型
AtomicInteger
public AtomicInteger()
初始化一个默认值为0的原子型Integer
public AtomicInteger(int initialValue)
初始化一个指定值的原子型Integer
int get()
获取值
int getAndIncrement()
int incrementAndGet()
int addAndGet(int data)
int getAndSet(int value)
AtomicBoolean
AtomicLong
自旋锁+CAS算法
源码解析
CAS算法
synchronized vs CAS
相同点
不同点
并发工具包
并发容器
Hashtable
Hashtable采取悲观锁synchronized的形式保证数据的安全性
JDK1.7
JDK1.8
并发工具类
CountDownLatch
让某一条线程等待其他线程执行完毕之后再执行
public CountDownLatch(int count)
public void await()
public void countDown()
1.CountDownLatch是通过一个计数器来实现的,计数器的初始值为需要等待线程的数量2.线程调用CountDownLatch的await()方法会阻塞当前线程(即:主线程在闭锁上等待),直到计数器的值为03.当一个工作线程完成了自己的任务后,调用CountDownLatch的countDown()方法,计数器的值就会减1。4.当计数器值为0时,说明所有的工作线程都执行完了,此时,在闭锁上等待的主线程就可以恢复执行任务
Semaphore
可以控制访问特定资源的线程数量
信号量
一个控制访问多个共享资源的计数器
1.Semaphore是通过一个计数器(记录许可证的数量)来实现的,计数器的初始值为需要等待线程的数量2.线程通过acquire()方法获取许可证(计数器的值减1),只有获取到许可证才可以继续执行下去,否则阻塞当前线程3.线程通过release()方法归还许可证(计数器的值加1)
CyclicBarrier(同步屏障)
让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行
CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景
CyclicBarrier vs CountDownLatch
CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。所以CyclicBarrier能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数器,并让线程重新执行一次。
Exchanger
线程间数据交换
两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方
可以用于校对工作
网络编程
超链接
目的
实现设备和设备之间的数据转发
三要素
IP
设备在网络中的唯一标识
ipv4
32位 4字节
点分十进制
ipv6
128位 16字节
冒分十六进制(8组)
相关cmd命令
ping ip或者域名
ipconfig
特殊IP
127.0.0.1
本地回环
InetAddress类
获取对象
public static InetAddress getByName(String host)
可以传入主机名(不推荐)或者IP地址
public String getHostName()
获取主机名
public String getHostAddress()
获取主机地址
端口
协议
UDP
单播
发送端使用步骤
1.创建核心对象
public DatagramSocket(int port)
3.发送数据
datagramSocket.send(DatagramPacket p)
4.释放资源
datagramSocket.close()
接收端使用步骤
2.创建包用于接收
3.接收数据
datagramSocket.receive(DatagramPacket p)
4.解析数据
byte[] arr = datagramPacket.getData(); // 数据写入字节数组int length = datagramPacket.getLength(); // 获取数据长度
5.释放资源
组播
组播发送端ip为组播频段ip
组播接收端使用MulticastSocket对象
组播接收端需要使用MulticastSocket对象的joinGroup方法加入组播频段
广播
广播频段255.255.255.255或者后缀是255
使用广播只需要修改发送端发送的ip为广播ip
TCP
三次握手
客户端发连接请求
服务器返回确认响应
客户端返回确认响应
四次挥手
客户端发取消连接请求
服务器返回收到响应
客户端返回确认信息
客户端
传入要连接的ip和端口
2.获取I/O流和服务器通话
接收服务器数据
给服务器发数据
3.释放资源
socket.close()
服务器端
public ServerSocket(int port)
2.监听客户端连接
public Socket accept()
返回Socket对象
serverSocket.accept()
3.通过Socket获取I/O流对话
接收客户端数据
给客户端发数据
UUID
生成一个不重复的字符串 长度36位 去掉'-'共32位
根据时间戳生成
UUID.randomUUID().toString();
类加载器
负责将.class文件加载到内存
加载类
读取字节码目录下的资源文件(相当于项目src文件下的文件)
类加载时机
用到类的时候加载类进内存
类加载过程
1.加载
链接
2.验证
文件中的信息是否符合虚拟机规范有没有安全隐患
3.准备
初始化静态变量
4.解析
5.初始化
如果有父类先初始化直接父类(不适用于接口)
BootstrapClassLoader
负责加载最底层的东西
PlatformClassLoader
加载大部分的JDK中的类
SystemClassLoader
双亲委派(全盘委托)
双亲委派
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载
ClassLoader
public static ClassLoader getSystemClassLoader()
public ClassLoader getClassLoader()
建议用当前"类名.class.getClassLoader()"获取类加载器对象
加载资源文件
public InputStream getResourceAsStream(String name)
相对路径从字节码根目录开始(相当于项目的src目录)
public URL getResource(String name)
URL对象可以getPath获取绝对路径传给IO流操作文件
可以处理中文
反射
获取该类的Class对象
Class<?> clazz = Class.forName("全限定类名(包名+类名)");
常用
类名.class;
已知类名
.class
对象.getClass();
已知对象名
操作构造方法
Constructor
Class对象.getConstructor(Class... clazz)
clazz传参为构造方法的参数的类型的Class对象
Class对象.getDeclaredConstructor(Class... clazz)
public void setAccessible(boolean flag)
public T newInstance(Object ... initargs)
反射+多态+配置文件
操作成员变量
Field
Class对象.getField(String name)
获取单个公共字段
Class对象.getDeclaredField(String name)
public Object get(Object obj)
obj要被获取值的对象
成员变量必须在对象身上才有意义
操作成员方法
Method
Method[] methods = Class对象.getMethods()
Method[] methods = Class对象.getDeclaredMethods()
获取单个公共方法
XML
可扩展标记语言
可扩展
标签完全由用户自定义
标记语言
由标签和属性组成
配置文件
标签
围堵标签
<标签></标签>
自闭和标签
<标签/>
属性
xml文档声明必须载第一行第一列
<?xml version="1.0" encoding="UTF-8" ?>
xml只能有一个根标签
注释
<!-- 这是一个注释 -->
特殊字符
< --> "<"> --> ">"
CDATA
处理大量特殊字符
<![CDATA[ 内容 ]]>
解析
DOM4J
需要导包
步骤
1.创建一个从SAX解析器
SAXReader saxReader = new SAXReader();
public Document read(InputStream in)
3.使用Document对象的方法getRootElement获取根节点标签
Element getRootElement()
4.解析Element对象
获取标签的属性值
String attributeValue(String name)
获取标签体内容
String getText()
获取子标签
获取多个
List<Element> elements()
List<Element> elements(String name)
获取单个
Element element(String name)
约束
DTD
缺点
不能对文本进行更细节的约束
Schema
编写
引入
枚举
一般在要表示几个固定选项时使用
枚举中只能定义私有构造
枚举项必须在第一行有效语句
每个枚举项本质上是该枚举类的一个对象实例
注解
本质
注解中可以定义抽象方法
public abstract 返回值类型 方法名() default 默认值;
public abstract可以省略default指定方法返回默认值(不指定不写)
定义格式
public @interface 注解名{ ... }
使用注解
@注解名(对注解中所有无默认返回值的方法重写)
重写格式
方法名 = 返回值
当需要重写的仅有一个value方法时 value可以省略
编译检查(JDK实现)
@Override
重写
@Deprected
过时
@SupressWarning("all")
压制警告
携带数据和框架通信
注解属于字节码层面(需要反射)
判断注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
获取注解
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
元注解
修饰注解的注解
@Target
使用枚举类ElementType指定可修饰的东西
ElementType
METHOD
FIELD
字段
TYPE
类
@Retention
使用枚举类RetentionPolicy指定生效时期
RetentionPolicy
CLASS
源码和字节码中生效
RUNTIME
源码和字节码及加载到内存的字节码中生效
SOURCE
源码中生效
@Inherited
标注该注解可以被子类继承
@Documented
单元测试
Junit
给测试方法添加@Test注解就可以独立运行
其他常用注解
@Before
测试方法执行前一定执行
@After
测试方法执行后一定执行
日志
Log4J
优点
可以通过控制配置文件控制日志打印
可以在控制台记录日志 还可以写入文件
创建核心对象
Logger logger = LoggerFactory.getLogger(当前工程中任何类的字节码对象)
使用功能打印对应级别的日志
debug
info
warn
error
使用配置文件控制日志打印
日志级别大小
debug < info < warn < error < fatal
0 条评论
回复 删除
下一页