逐梦Offer -- 6 个月学习归纳[整合版]

2. Java 基础

2.1 引用

强引用
软引用 :即将发生内存溢出时,会对这些对象列进回收范围内,进行第二次回收
弱引用 : 只能生存到下一次垃圾收集之前
虚引用 :无法通过虚引用取得一个对象的实例,唯一目的是为了在这个对象被收集器回收时收到 一个系统通知

2.2 重载时的特征签名

Java代码层面的特征签名与字节码层面的特征签名不同。

2.3 动态代理

JDK :JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,
但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。
CGLIB :使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

2.4 输入输出流

1. NIO与IO的区别

一.IO是面向流的,NIO是面向缓冲区的。
二.IO的各种流是阻塞的,NIO是非阻塞模式。
三.Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

2. 相关类

1、FileChannel

1
FileChannel fc = new FileOutputStream("data.txt").getChannel;

2、FileLock

1
2
3
4
5
6
7
// 对整个文件加锁
FileLock fl = new FileOutputStream("data.txt").getChannel.tryLock();
// 对文件的一部分加锁
tryLock(long position, long size, boolean shared);
lock(long position, long size, boolean shared);
// 检查锁的类型
FileLock.isShared();

3、ByteBuffer

1
2
3
4
5
6
7
// 用于写时 OutputStream
fc.write(ByteBuffer.wrap("somethind".getBytes()));
// 用于读时 InputStream
ByteBuffer buff = ByteBuffer.allocate(1024);
fc.read(buff);
// 用于转化
buff.asXxBuffer;

细节 : 四个索引 1,mark 2,position 3, limit 4, capacity;
方法:

1
2
3
4
5
6
7
8
9
10
mark() -- 将mark 设置为 postion
position() -- 返回postion 值
position(int pos) -- 设置 。。
limit() -- 返回limit 值
limit(int lim)
capacity()
flip() -- 将limit 设置为 position ,position设置为0,用于准备从缓冲区读取已经写入的数据
clear() -- 清空缓冲区,将position 设置为0,limit设置为 capacity ,用于覆写缓冲区。
remaining()
hasRemaining()

4、 MappedByteBuffer 内存映射文件

1
2
MappedByteBuffer out = new RandomAccessFile("test.dat","rw")
.getChannel().map(FileChannel.MapMode.READ_WRITE(模式),0(位置),length(长度));

2.5 序列化与反序列化

把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
一.把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
二.在网络上传送对象的字节序列。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

1、Serializable – > ObjectOutputStream -> writeObject();

1
2
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(Bean.out));
out.writeObject(Bean);

2、Serializable – > ObjectInputStream -> readObject();

1
2
ObjectInputStream in = new ObjectInputStream(new FileInputStream(Bean.out));
Bean bean = in.writeObject(Bean);

3、transient + Serializable == Externalizable

xml 解析 的方式

方式 原理 优点 缺点
DOM(Document Object Model) 将结点形成树状结构 方便增删改减 文件过大,内存容易溢出
SAX(Simple API for XML) 基于事件驱动 不会产生内存溢出 不能增删改

开发包: JAXP 与 DOM4J

Statement 与 PreparedStatement 之间的区别

  1. preparedStatement 会使用 预编译 ,以及批处理。 statement 不会。所以每次数据库进行查询时,preparedStatement 可以直接使用 sql 语句。 statement 不行。 但是,如果只是使用一次的话, preparedStatement 不会带来性能提升。不如使用 statement 方便。
  2. preparedStatement 可以使用 占位符 ?,然后再赋值,相对于 statement 更为的灵活
  3. preparedStatement 在导入参数的时候,会进行强制性的类型转换。所以在查询,更新的时候,与底层数据库类型一致,不容易出现问题。更为的安全。

api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Class.forName("com.mysql.jdbc.Driver");
Connection conn = (Connection)DriverManager.getConnection("jdbc:mysql://localhost:3306",username,password);
PreparedStatement pstmt = conn.prepareStatement(sql);

int rows = pstmt.executeUpdate();
ResultSet rs = pstmt.executeQuery();

// 列数统计
int col = rs.getMetaData.getColumnCount();
while(rs.next){
for(int i = 1; i<=col;i++){
System.out.println(rs.getString(i));
}
}

JSP 与 Servlet


3. 多线程

线程安全的单例模式 – (DCL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton{
private volatile static Singleton instance;

public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance == new Singleton();
}
}
}
return instance;
}

public Singleton(){
Singleton.getInstance();
}
}

线程池

  1. newFixedThreadPool 固定长度的线程池
  2. newCachedThreadPool 可缓存的线程池 规模不受限制
  3. newSingleThreadExecutor 单个工作者线程来执行任务
  4. newScheduledThreadPool 固定长度的线程池,并且以延迟或定时的方式来执行。

基础框架

  1. Semaphore 信号量
    acquire()
    release()
  2. CountDownLatch 闭锁
    // 等待事件的完成
    await()
    countDown()
  3. CyclicBarrier 栅栏
    // 等待线程的到达
  4. Exchanger 两方栅栏
    exchanger()
  5. FutureTask
    new Thread(ft); – runnable
    ft.get(); – future
  6. Fork-Join框架

原子性、可见性与有序性

  1. 原子性
    read 、write
    assign 、store
    load 、use

    lock unlock – > monitorenter 、 monitorexit
    2 . 可见性
    volatile synchronized final

  2. 有序性
    volatile(内存屏障) synchronized
    必须 load < – > use assign < – > store
  3. 先行发生原则(happens - before)
    • 程序次序原则
    • 线程启动、终止、中断原则
    • volatlie 变量原则 write –> read
    • 管程锁原则
    • 对象终结原则
    • 传递性 a->b b->c –> a->c

偏向锁、轻量级锁、重量级锁

偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。
一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它,所以当第一个线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头成为偏向锁的时候使用CAS操作,并将对象头中的ThreadID改成自己的ID,之后再次访问这个对象时,只需要对比ID,不需要再使用CAS在进行操作。
一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象时偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。如果不存在使用了,则可以将对象回复成无锁状态,然后重新偏向。
轻量级锁认为竞争存在,但是竞争的程度很轻,一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。 但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。

偏向锁

偏向锁标志位 01
同时用CAS 操作将获取到这个锁的线程ID 记录到对象的 Mark Word 中。以后每次这个线程进入这个锁相关的同步块时,都不需要任何同步操作。

轻量级锁

轻量级锁 00
如果此同步对象没有被锁定(锁标志位 为“01”)在当前线程中栈帧中建立锁记录(Lock Record) 的空间,存储锁对象的 Mark Word 拷贝(官方把这份拷贝加了一个 Dispaced 前缀).
CAS 操作尝试将 对象的 Mark Word 更新为指向 Lock Record 的指针。 并将标志位 转变为 “00”



5. 框架

5.1 SSH 与 SSM

spring 的架构

spring bean

1、 加载过程
2、 实例化
3、 注入方式

spring 中的 IOC 与 AOP

spring 事务

1、事务
事务:是逻辑上一组操作,要么全都成功,要么全都失败.
事务特性:
ACID:

  1. 原子性(Atomic):事务不可分割
  2. 一致性(Consistency):事务执行的前后,数据完整性保持一致.
  3. 隔离性(Isolation):一个事务执行的时候,不应该受到其他事务的打扰
  4. 持久性(Durability):一旦结束,数据就永久的保存到数据库.

如果不考虑隔离性:

  1. 脏读:一个事务读到另一个事务未提交数据
  2. 不可重复读:一个事务只能看到已经提交事务做出的修改。所以当另一个事务更新数据(update),导致一个事务多次查询结果不一致
  3. 幻读:当一个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入新的记录(insert),导致一个事务多次查询结果不一致

事务的隔离级别:

  1. 未提交读:以上情况都有可能发生。
  2. 已提交读:避免脏读,但不可重复读,幻读是有可能发生。
  3. 可重复读:避免脏读,不可重复读,但是幻读有可能发生。
  4. 串行的:避免以上所有情况.

Spring 中的代码解析:

1
2
3
4
PlatformTransactionManager:平台事务管理器.
commit(TransactionStatus status)
getTransaction(TransactionDefinition definition)
rollback(TransactionStatus status)

TransactionDefinition:事务定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ISOLation_XXX:事务隔离级别.
ISOLATION_DEFAULT:默认级别. -- Mysql repeatable_read
ISOLATION_READ_UNCOMMITTED
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE

PROPAGATION_XXX:事务的传播行为.(不是JDBC中有的,为了解决实际开发问题.)
过期时间:

TransactionStatus:事务状态
是否有保存点
是否一个新的事务
事务是否已经提交

关系:PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务,管理事务过程中,产生一些事务状态:状态由TransactionStatus记录.

2、事务的传播行为:(不是JDBC事务管理,用来解决实际开发的问题.)传播行为:解决业务层之间的调用的事务的关系.

  • PROPAGATION_REQUIRED :支持当前事务,如果不存在 就新建一个
    A,B 如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A,B是在一个事务中。)
  • PROPAGATION_SUPPORTS :支持当前事务,如果不存在,就不使用事务
    A,B 如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务.
  • PROPAGATION_MANDATORY :支持当前事务,如果不存在,抛出异常
    A,B 如果A有事务,B使用A的事务,如果A没有事务,抛出异常.
  • PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
    A,B 如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中.事务互不影响.)
  • PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
    基于SavePoint技术.A,B A有事务,A执行之后,将A事务执行之后的内容保存到SavePoint.B事务有异常的话,用户需要自己设置事务提交还是回滚.
  • PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
    A,B 非事务的方式运行,A有事务,就会挂起当前的事务.
  • PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常

SpringMVC 与 Struts2 的原理

SpringMVC 与 Struts2 区别

1、 Struts2是类级别的拦截, 一个类对应一个request上下文,
SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,
所以说从架构本身上SpringMVC就容易实现restful url,
而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类内的属性被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
举例:

1
2
3
4
5
6
7
8
9
10
// springmvc
@requestMapping("/test/{id}")
public String springmvcTest(@pathVariable("id") int id);

// struts2
public class strutsToTest{
int id;
public String test01(int id);
public String test02(int id);
}

可以看到 struts2 的 id 属性是被所有的方法共享的,这样就不能将 id 标识为单独的restful url 的值。
2、 由上边原因,SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,
而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
3、 由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
4、 拦截器实现机制上,Struts2有以自己的interceptor机制,
SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。
5、 SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
6、 SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,
而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
7、 SpringMVC验证支持JSR303,处理起来相对更加灵活方便,这里介绍一下。springmvc使用的是Hibernate Validator(和Hibernate的ORM)进行校验。
通过 在 HandlerAdapter 中加入 自定义绑定 WebBinder (在 自动注解下前面都可以省略)
-> 校验器 validator -> 校验文件 messageSource 的设置。 可以使用 相关的注解
而Struts2是通过自己的inteceptor (name = “params” .. “validation”) 提供。 有一套完备的 validator 供开发者使用。
8、SpringMVC开发效率和性能高于Struts2。


6. 数据库

基础知识

范式

mysql

mysql的逻辑架构

mysql的事务

1、事务
事务:是逻辑上一组操作,要么全都成功,要么全都失败.
事务特性:
ACID:

  1. 原子性(Atomic):事务不可分割
  2. 一致性(Consistency):事务执行的前后,数据完整性保持一致.
  3. 隔离性(Isolation):一个事务执行的时候,不应该受到其他事务的打扰
  4. 持久性(Durability):一旦结束,数据就永久的保存到数据库.

如果不考虑隔离性:

事务的隔离级别:

  1. 未提交读:以上情况都有可能发生。
    脏读:一个事务读到另一个事务未提交数据
  2. 已提交读:避免脏读,但不可重复读,幻读是有可能发生。
    不可重复读:一个事务只能看到已经提交事务做出的修改。所以当另一个事务更新数据(update),导致一个事务多次查询结果不一致
  3. 可重复读:避免脏读,不可重复读,但是幻读有可能发生。
    幻读:当一个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入新的记录(insert),导致一个事务多次查询结果不一致
    不过 mysql 中存在 多版本并发控制 (MVCC ,Multiversion Concurrency Control) :
    在每行记录的后面 保存两个隐藏的列 1、创建时间 2、过期时间 (实际为当前系统的版本号,每开启一个新的事务,版本号就会递增)
    • SELECT
    • INSERT
    • DELETE
    • UPDATE
      只在 REPEATABLE_READ 与 READ_CONMMITED 两个隔离级别下工作。
  4. 串行的:避免以上所有情况

mysql的主从复制

redis


7. 服务器

nginx

8. 函数式编程

递归优化 : 尾递优化

最后一步是纯净的函数式。

1
2
3
4
5
6
7
8
9
10
11
// 递归式
static long factorialRecursive(long n){
return n==1 ? 1 : n*factorialRecursive(n-1);
}
// 纯净的函数式
static long factorialTailRecursive(long n){
return factorialHelper(1,n);
static long factorialHelper(long acc, long n){
return n==1?acc:factorialHelper(acc*n,n-1);
}
}
0%