什么才是 Java 的基础知识?
数据结构是链表的数组(注:后面的版本为了提升性能,已经是改成链表或者树(节点较多)了)
思想上是空间换时间的算法
构造函数上有容量和负载因子 2 个参数以及作用
决定性能的是 key 的 hashcode 是否够快、结果够分散(不分散就会变成链表的性能了),和扩容的开销(什么时候扩容,和负载因子有关)
然后写代码的时候,如果知道了最终的容量(尤其是数据量大的时候),我都会指定初始化容量,类似如下
List<SomeBean>?list?= doSomeThing();?
Map<Integer, String>?map?=?new?HashMap<>((int)(list.size()/0.75));//0.75 为默认负载因子
如果工作中某个 map 使用特别多,性能还需要继续优化,我就会考虑从以下方面优化
如果 key 是自己定义的对象,那么 hashcode 方法是否够快(最少应该缓存保证只计算一次,而且放入之后不能改变,决定 hashcode 的字段不能改变)? hash 的结果是否够分散?
可以考虑调小负载因子,花更多的空间来换时间
学习源代码的时候,特别有意思,你会强烈感觉到一个词:举一反三!触类旁通!学习 api 使用的时候,如果你只知道使用不知道原理,很难举一反三,感觉的是死记硬背。但学习了原理之后,知识成体系后,很容易举一反三,学的越多就容易,还是以 hashmap 为例,我举一个 hashmap 反三个点。
1. 你会知道但凡有数组的数据结构,构造函数都有一个容量的初始化参数(或者说构造函数有初始化容量的可能都是数组的数据结构)。构造函数如下
public?ArrayList(int?initialCapacity)?//LinkedList 不是数组就没有
public?HashMap(int?initialCapacity)?
public?StringBuffer(int?capacity)
你就会知道,数组扩容很耗性能(数据量大容易 oom),尽量指定容量。
2. 算法是空间换时间,还有没有其他算法是这种思想的?你最少能找到一个桶排序。
3. 数据库的分库分表,思路和 hashmap 大同小异
4. 各种分布式的 hash 一致性算法,第一步都是创建一个最大的数组(Integer.MAX_VALUE),就是避免了 hashmap 最耗性能的扩容运算。
学习了 hashmap 之后,你很自然就会去了解其他的 map,如 TreeMap,LinkedHashmap(超级有用),HashTable,ConcurrentSkipListMap(算法思路很有意思),ConcurrentHashMap 等,你会知道 set 就是用 map 做的,都不需要学。到了这步,map 相关就可以暂告一段落。
在学习中,我发现思想上的东西是最重要的,你理解了思想,一下子就豁然开朗了,在也不需要死记硬背了。如学习 CAS 的时候,大家都知道这是一种指令级的免锁实现。看代码的时候,我一度疑惑为什么会有个 while 死循环(原谅我天资驽钝)
public?final?int?getAndUpdate(IntUnaryOperator updateFunction)?{
int?prev, next;
do?{
prev =?get();
next = updateFunction.applyAsInt(prev);
}?while?(!compareAndSet(prev, next));
return?prev;
}
后来从思想上理解,才知道乐观锁的概念,就是很乐观,假设你不会出错,但你要是出错了我就重试有办法给你修复,对应的就是悲观锁,就是很悲观,觉得不锁就会出错,如 synchronize 关键字和 reentrantlock。这体现了 2 种不同截然不同的管理思想。这种思想经常体现在多个系统集成的设计,有些时候如果你用悲观的思想设计,实现起来很麻烦或者无法实现,但如果你用乐观的思想,减少出错条件,然后出错了能解决,代价就会小很多。
说了这么多,我想说的就是,j2ee 的基础知识就是你做项目中代码背后的东西。提高自己水平的方法很简单,就是把大部分时间去了解实现原理,了解思想,让自己的知识串起来,形成体系。j2ee 的知识特别多,学得人想哭,千万不要一开始把时间花在各种框架、组件的使用上,在我看来那是本末倒置。简单来说:先修内功再练招式。
我觉得重要的、工作会用得到的知识就是一个请求从前台到后台处理的过程需要用到的东西,最少包括以下点:js,html,css,ajax,ajax 跨域,跨站脚本,web 缓存,web 优化,nginx,apache 作用,鉴权方式,cookie,session,servlet,filter,基本数据结构,线程池,线程并发,缓存,io 等等,知识点非常多。如你前台用 jq,你应该了解他的选择器和 ajax 是如何实现的(其实去了解就会发现不复杂)?而不是只是会用。后台你用 springmvc,你要了解他是如何工作,每一个配置是做什么,为什么?
j2ee 知识点特别多,每一个都能写很多,我也在不断学习中。具体要写我还真不知道如何下手,我就列举一下我觉得基础的东西(面试的时候问的问题),有简单有难,你觉得偏可能是你没有做过这块的开发或者做得比较浅:
map 有哪些,特点和使用场景?(只知道 hashmap,hashtable 是不够的。。。)
哪些方面会影响 hashmap 的性能?
线程安全的 map 有哪些,concurrenthashmap 是如何实现线程安全的(jdk1.8 大不同)?
锁有哪几种?
公平锁,读写锁等如何实现?
synchronize 能加在哪些地方?什么区别?
死锁的形成条件?现在很少死锁了,很少问
原子数据对象的原理?
reentrantlock 相关知识,condition 如何使用?(很重要的知识点,强烈推荐阅读 ArrayBlockingQueue 源码,教科书般)
volatile 的相关知识(内存屏障,重排)
ThreadLocal 原理和使用?(超级有用的知识点,工作中使用很多,让代码漂亮很多,后面专门开贴写)
多个线程同步等待?(CountDownLatch,CyclicBarrier,Semaphore 信号量很多语言都有,实际上使用不是很多,线程池就可以实现大部分等待功能)
评论