系列:《Java核心技术 卷1》笔记
一)简介
1. 语言特点
- 面向对象
- 健壮性
- 安全性
- 可移植性
- 解释型
2. 数据类型
类型 | 存储字节 | 取值范围 |
---|---|---|
int | 4 | [-2^31, 2^31-1] |
short | 2 | [-2^15, 2^15-1] |
long | 8 | [-2^63, 2^63-1] |
byte | 1 | [-2^7, 2^7-1] |
float | 4 | (有效位6-7位) |
double | 8 | (有效位15位) |
char | 2 | [0, 2^16-1] |
boolean | 参考JVM规范 |
3. 枚举类型
enum Size {
SMALL, MIDDLE, LARGE
}
Size size = Size.SMALL;
4. 位运算符之移位
运算符 | 说明 |
---|---|
<< | 左移,低位补0 |
>> | 右移,高位填充符号位 |
>>> | 无符号右移,高位填充0 |
5. 直接输出数组
System.out.println(Arrays.toString(arr))
6. 新的日期时间
LocalDateTime
系列。
7. Java的传参方式
按值引用。
- 对于基本类型,传的值(int等,值)
- 对于引用类型,传的值(Java引用,值即为指向对象的地址)
二)OOP
1. 封装
定义:将数据和行为组合在一个包中,对对象的使用者隐藏具体的实现方式。
意义:重用性和可靠性
访问权限
- public
- protected
- 默认
- private
2. 继承
定义:通过扩展一个类来建立另外一个类的过程
3. 多态
定义:一个对象变量,可指向多种实际类型的现象
动态绑定:在运行时能够自动选择适当的方法
4. 类之间的关系
- 依赖:user-a。方法参数
- 聚合:has-a。成员属性
- 继承:is-a。父子类
5. 关键字
- this
- super
- static
- final
6. 初始化顺序
1. 父类的【静态】:属性,代码块
2. 子类的【静态】:属性,代码块
3. 父类的【成员】:属性,代码块
4. 父类的构造方法
5. 子类的【成员】:属性,代码块
6. 子类的构造方法
说明:
【静态】:静态属性,静态代码块。按定义的先后顺序
【成员】:成员属性,构造代码块
7. 抽象类和接口
主要理解Java的单继承即可。具体的区别其实意义不大,这个更多的看设计时抽象出来的结构。
具体见: 深入理解Java的接口和抽象类
8. lambda表达式
熟悉语法,使用场景。
语法:(parameters) -> expression
,或(paras) -> { statements; }
使用案例:菜鸟教程
9. 内部类
类型:成员内部类,局部内部类,静态内部类,匿名内部类。
10. 函数式接口
有且仅有一个抽象方法的接口。
同类型:方法引用,lambda,函数式接口
自定义一个接口:
@FunctionInterface
interface GreetingService {
void sayMsg(String msg);
}
GreetingService gS = msg -> System.out.println(msg);
gS.sayMsg("hello");
API提供的函数式接口:见源码包java.util.function
三)反射和代理
参考:Java动态代理
1. 什么是反射
运行时
2. 相关API
Class, Method
等
3. 静态代理
角色:委托类、代理类。
实现解耦,可以在代理类进行过滤增强等处理,而无需修改委托类代码。例如对学生五折销售,对商人八折销售等。
/*
场景:销售。生产,商店。
*/
interface Sell {
void sell();
}
// 委托类
class Product implements Sell {
@Override
public void sell() {
System.out.println("生产商");
}
}
// 静态代理类
class Shop implements Sell {
private Product product;
// ToDo 构造器
@Override
public void sell() {
this.product.sell();
}
}
4. 动态代理
代理类,在运行时被创建的代理方式,即动态代理。
优点:对代理类的函数进行统一的处理。而不用修改每个静态代理类的代码。
假设场景:在上述静态代理类的sell方法内,执行product.sell前后都需要输出日志信息。如果只有一个方法sell
,很简单,如果有很多方法呢?每个方法都需要添加日志,较为繁琐。
角色
接口:Sell
委托类:Product
中介类:class SellProxy implements InvocationHandler
Object invoke(Object proxy, Method method, Object[] args);
说明:InvocationHandler只有一个方法需要实现,即invoke
解释:调用代理类对象时,这个调用会转送到invoke方法中,代理类对象作为proxy参数传进去,参数method标识了我们具体调用的代理类的方法,args位方法的参数。如此,可在invoke中添加统一的处理。
// 接口:Sell
// 委托类:Product
// 终结类
class ProductProxy implements InvocationHandler {
private Object obj;
// ToDo 构造器(Object obj)
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// 调用前处理..
// 调用:实际是反射
Object res = method.invoke(obj, args);
// 调用后处理
return res;
}
}
实现机制
需要实现接口,如Sell
。JDK动态代理
常见的还有CGLib,利用ASM开源包,通过修改其字节码生成子类来实现。
四)异常体系
1. 异常层次结构
2. 非检查型异常
Error和RuntimeException
RuntimeException,是可以通过编码避免的异常。
3. 检查型异常
Exception中除RuntimeException
编译器要求必须处理的异常,要么捕获,要么抛出。
4. 如何处理
创建异常类
class MyException extends Exception {..}
class MyException2 extends RuntimeException {..}
抛出异常
void func(T arg) throws Exception {..}
void func2(T arg) {
if (arg == null) {
throw Exception();
}
}
捕获异常
void func() {
try {
...
} catch (Exception e) {
...
// 可抛出:throw Exception;
}
}
5. finally
常用于释放资源。
6. 断言
一种调试程序的方式,建议使用单元测试。
五)泛型
1. 作用
- 省去强制类型转换
- 将运行时错误转到编译期。编译检查
2. 泛型类和泛型方法
3. 限制
List<?> list = null;
List<? extends Number> list2 = null;
List<? super Manager> list3 = null;
..
? super Manager
4. 泛型擦除
虚拟机没有泛型。
了解桥方法(保持多态)。
六)集合
1. 迭代器
作用:遍历。
说明:remove和next的搭配
2. List
实现 | 说明 |
---|---|
ArrayList | 默认容量10,扩容1.5倍 |
LinkedList |
3. Queue & Deque
实现 | 说明 |
---|---|
PriorityQueue | 默认容量11,扩容(2倍+2)或(1.5倍) |
ArrayQueue | 容量=(tail-head+cap)%cap |
ArrayDeque | 默认容量16,扩容2倍 |
LinkedList |
4. Set
实现 | 说明 |
---|---|
HashSet | 允许一个null |
LinkedHashSet | |
TreeSet |
5. Map
实现 | 说明 |
---|---|
HashMap | 默认容量16,扩容2倍,允许null键和值 桶由链表和红黑树实现 |
LinkedHashMap | Node添加前后指针,记录插入顺序 |
TreeMap | 红黑树。节点key+value+left+right+parent+color |
WeakHashMap | |
IdentityHashMap |
6. Collections
常见API的使用。
七)IO
1. 控制台
System.out.println();
Scanner sc = new Scanner(System.in);
2. 文件IO
File file = new File(path);
FileOutputStream fos = ..;
3. 序列化
- 基本类型:
DataInputStream
- 对象:
ObjectInputStream
接口:Serializable
transient
:序列化跳过当前关键字修饰的属性。
说明:可通过重载readObject和writeObject方法实现序列化
4. 设计模式:装饰模式,适配模式
字符流Reader/Writer,适配器: InputStreamReader
和OutputStreamWriter
字节流InputStream/OutputStream,装饰器:FilterInputStream
和FilterOutputStream
5. 网络IO
ServerSocket
Socket
6. Java中的IO类型
常见的BIO,阻塞IO。
然后是NIO,非阻塞IO,基础:IO多路复用
最后是AIO,异步IO。
八)并发
1. 什么是线程
进程中一个单一顺序的控制流。
2. 实现
-
Thread
-
Runnable
-
Callable
3. 线程状态
新建:new Thread®
可运行:start
阻塞:试图获取内部的对象锁,失败,线程被阻塞(synchronized
)
等待:线程等待另一个线程通知调度器出现一个方法时,线程进入等待(wait或join,或j.u.c的Lock或Condition
计时等待:Thread.sleep、Object.wait、Thread.join、Lock.tryLock以及Condition.await
终止:run方法正常退出,或一个没有捕获的异常
4. 线程属性
优先级
中断标志位:静态的Thread.interrupted()
,检查当前线程是否被中断,回清除中断状态;成员方法isInterrupted()
说明:线程被阻塞,其他线程调用interrupt()中断当前线程,会抛出异常
守护线程
5. 同步
通过同步,实现存取的顺序访问
6. 锁
synchronized
ReentrantLock
条件对象:Condition
7. 深入
监视器和synchronized
monitor,略。
volatile
JMM模型:略
- 保证可见性,原理见JMM模型
三大特性:原子性,可见性,有序性
- 内存屏障:禁止指令重排
死锁
情形描述:多个线程同时被阻塞,它们中的一个或全部都在等待某个资源释放。
死锁产生的四个必要条件:
- 互斥:资源被线程占用,别的线程不能使用
- 非抢占:资源只能由占用者释放
- 请求和保持:占用资源的线程同时请求资源
- 循环等待:存在一个等待队列,P1占用P2需要的资源,P2占用P3的资源,…形成环路
如何解决死锁:synchronized,或Lock。
产生死锁的样例:可使用信号量,避免死锁(具体)
线程1
syn(A) {
syn(B) {
..
}
}
线程2
syn(B) {
syn(A) {
..
}
}
线程局部变量
ThreadLocal
方法:void set(T t)和T get()
场景一:管理数据库连接Connection,保证当前线程操作的都是同一个Connection,保证事务
8. 线程安全的集合
阻塞队列:BlockingQueue
-
ArrayBlockingQueue
:必须指定容量 -
LinkedBlockingQueue
:可指定容量,默认Integer.MAX_VALUE
-
DelayQueue
:无上限阻塞队列 -
PriorityBlockingQueue
:无上限 -
TransferQueue
高效的映射、有序集和队列:ConcurrentHashMap
、ConcurrentSkipListMap
、ConcurrentSkipListSet
、ConcurrentLinkedQueue
写数组:CopyOnWriteArrayList
9. 线程池
Executors
:
newCachedThreadPool: 核心线程=1,最大线程=Integer.MAX_VALUE,存活时间60s,同步队列(线程间同步移交任务)
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
newFixedThreadPool: 核心线程=最大线程,LinkedBlockingQueue(容量Integer.MAX_VALUE)
new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
newScheduledThreadPool: 核心线程=core,最大线程=Integer.MAX_VALUE
new ScheduledThreadPoolExecutor(corePoolSize);
newSingleThreadExecutor: 核心线程=最大线程=1,LinkedBlockingQueue(容量int.max)
new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
ThreadPoolExecutor
-
核心线程
-
工作队列:阻塞队列
BlockingQueue
-
最大线程数量 & 工作线程
-
工作线程存活时间
-
饱和策略
AbortPolicy:默认。不执行任务,直接抛出运行时异常 DiscardPolicy:抛弃任务 DiscardOldestPolicy:抛弃head的任务,即最先入队的任务 CallerRunsPolicy:在调用execute的线程执行此任务,会阻塞入口 用户自定义策略:需实现RejectedExecutionHandler