为何面试问源码,源码带给你的不单单是一份工做,更多的是这些

我的以为大多数状况下跟着一篇优秀的博客配合着看就足够了,以后再本身写博客总结一遍加深印象,画一下流程图基本都能理顺。(图为学AQS时本人画的获取独占锁流程图)git

1|2类关系

配合idea看类之间的关系(ctrl+alt+shift+u)的功能也能更好的理解整个项目的总体架构。由于不少源码其实并非真的复杂,只是为了扩展性优雅简洁等缘由创建了大量的接口和抽象类以及各类设计模式,使得项目看起来很庞大很复杂,借助这个功能有利于你排除掉一些你暂时不想去关心的设计逻辑。知道那个部分才是最核心的逻辑,专一于去看核心代码。github

1|3多看注释

可是若是你看的博客里面恰好缺乏了一部分你想看的内容,而你又找不到资料,须要本身去看,又或者你想看的源码一点点资料都找不到的状况下想去看源码。面试

这个时候比较有做用的就是注释,源码中的注释看不懂也不要紧,放到百度翻译里基本也能理解大概的意思。仔细看完方法或类的注释以后你就理解了接下来这个类大体是在作什么,以后读它的源码会通顺不少,有一些方法或类甚至在你看完注释以后就已经能知道你想看的内容了,已经没有须要继续往下读了。算法

不只仅是类或方法的注释文档,方法中代码的注释也很重要,基本上稍微复杂一点点的代码,甚至有时候加个锁,做者都会认认真真的写一行注释解释本身这么作的缘由。spring

1|4适当囫囵吞枣

还有一点是适当忽略一些不重要的细节,这个主要看你想看什么,通常咱们看第一遍大多数只是想知道大体的流程是什么样的,因此能够适当忽略并发逻辑和一些方法里的内容(看一眼注释先知道这个方法会作什么的就够了)。第一遍大体知道流程,第二第三遍再去深究细节和并发逻辑等。mongodb

1|5善用debug

多用debug,不少时候源码走的路线会和你想象中的有很大不一样,你觉得会进入这个if,其实他偷偷进了else。设计模式

2|0短路机制

常常看到利用短路机制的代码,这里以 AbstractQueuedSynchronizer 的 acquire 方法为例子,只有 tryAcquire 获取锁失败, !tryAcquire 返回 true 时才会执行后面进入阻塞队列并挂起的方法,若是获取锁成功了,根据短路机制天然不会执行入队方法。mybatis

// AbstractQueuedSynchronizer.acquire(int arg)
if (!tryAcquire(arg) &&架构

acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
selfInterrupt();

}并发

3|0拆高低位

ReentrantReadWriteLock的这段代码里将AQS的state一分为二给共享锁和独占锁使用,我的以为这种设计很是巧妙:

// ReentrantReadWriteLock
abstract static class Sync extends AbstractQueuedSynchronizer {

// 下面这块说的就是将 state 一分为二,高 16 位用于共享模式,低16位用于独占模式
static final int SHARED\_SHIFT   = 16;
static final int SHARED\_UNIT    = (1 << SHARED\_SHIFT);
static final int MAX\_COUNT      = (1 << SHARED\_SHIFT) - 1;
static final int EXCLUSIVE\_MASK = (1 << SHARED\_SHIFT) - 1;
// 取 c 的高 16 位值,表明读锁的获取次数(包括重入)
static int sharedCount(int c)    { return c >>> SHARED\_SHIFT; }
// 取 c 的低 16 位值,表明写锁的重入次数,由于写锁是独占模式
static int exclusiveCount(int c) { return c & EXCLUSIVE\_MASK; }

4|0 While(n-- > 0)和while (--n >= 0)

忘记在哪里看到的了,翻了一下浏览记录应该是在Java AIO部分的源码里,这种写法感受很简洁就记下来了,不过可读性彷佛不过高,特别是第一种乍一看还觉得是lambda表达式

意思等同于 for (int i = 0; i < n; i++) ,可是 while(n-- > 0) 和 while (--n >= 0) 这种写法会直接改变n的值

5|0xx = null

在不少jdk的源码中咱们均可以看到 xx = null // help GC 这样的代码,用来置空引用,帮助jvm完成gc。具体能够了解可达性算法。

这里咱们以LinkList为例子:

// LinkList 的方法
private E unlinkFirst(Node<E> f) {

final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
    last = null;
else
    next.prev = null;
size--;
modCount++;
return element;

}

6|0位移运算符

在不少地方都会使用位移来进行运算,平时写算法题也同样不少人都这么使用,下面以 ArrayList 的 grow 方法为例子,这里经过右移1位使 oldCapacity 变为原来的0.5倍,以后加上它自己获得 newCapacity

// ArrayList.grow(int minCapacity)
private void grow(int minCapacity) {

// . . . . . .
int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity就是1.5倍的oldCapacity
// . . . . . .

}

而源码带给你的可不只仅只是这一些,更多的是编码习惯以及这一个技术最底层的运行原理,当出现问题或者须要这个技术的辅助的时候,你能够更好理解这一技术能起到的做用,以及会产生的问题,双方均衡下,在作出决定,这也是为何如今市面上面试考察源码的东西愈来愈多的缘由。总结就是如下几点

1、解决问题(BUG)

只要是代码,就会有bug,只是说bug的多与少、深与浅罢了。如今你们都喜欢发布、使用开源项目,不一样的开源项目社区成熟度、代码质量又会有较大的差别,遇到bug就不足为奇了。

固然,遇到bug确定是先在网上搜索是否有相似的问题,通常能够在google、Stack Overflow、项目的issues里面有对应的关键词搜索。若是搜不到,那么就只能看源码解决了

2、知其因此然

若是咱们须要将一个开源项目用到本身的项目中,那么就必须了解这项项目的优缺点,并深知原理,对部分细节(尤为是项目的优点、feature)进行深刻研究。

若是是成熟的开源项目,遇到问题也许能google到不少答案;但若是是一个处于快速发展中的开源项目,多了解其架构、核心原理,也能帮助快速定位问题。

另外,有的项目文档可能不那么丰富,但又不得不使用,那么如何以正确的姿式使用呢?也得参考源码

3、学习

看源码也是一种不错的学习方式(虽然不必定不是最佳的方式),尤为对于比较优秀的开源项目,能让人大开眼界。

即便是出于学习的目的,也是有不少侧重的,好比

学习语言:代码风格、规范、惯用法、高级语法。对于某个语言的新手,找一个熟悉领域的开源项目来深刻掌握这门语言,也是一个不错的注意。

学习设计:数据接口、框架、总体架构

学习理论:算法、协议。好比我以前写过的[raft协议][raft],光看论文是很枯燥的,并且算法理论到工程实践仍是有必定的差距,这个时候结合开源项目([mongodb][])实现每每更事半功倍。

4、改造

通常来讲,咱们刚开始仅仅是使用一个开源项目,但随着使用的深刻,会发现一些本身须要的功能并无很好的支持,向项目组提的issues也可能得不到快速的响应,这个时候就要本身开分支,改代码,加功能了。

固然,比较好的是将本身分支比较好的新feature 给原项目提merge request,反哺开源项目,好比阿里的[Blink],而这也是将来在你面试过程当中浓墨重彩的一笔

5、借鉴

他山之石能够攻玉,若是有须要从新开始本身造轮子,那么参考一些已有的、优秀的轮子确定是有好处的。

固然了,整这么多最后仍是为了一份更好的工做,那如今市面上考察的源码知识点都有哪些呢?

源码知识导图

如今市场考察最多的源码主要有如下几点:jdk、spring、mybatis、dubbo、springMVC、Netty

源码解析文档

后期会将文件上传git:https://github.com/biws-byte/pdf

前期还请你们移步,关注公众号:Java架构师联盟,后台回复源码查看获取方式