我在 Oracle 已经工做了近 7 年,面试过从初级到很是资深的Java工程师,且因为 Java 组工做任务的特色,我很是注重面试者的计算机科学基础和编程语言的理解深度,能够不要求面试者非要精通 Java。因此,若是你对 C/C++ 等其余语言可以掌握得很是系统和深刻,也是符合需求的。java
工做多年以及在面试中,我常常能体会到,有些面试者确实是认真努力工做,但坦白说表现出的能力水平却不足以经过面试,一般是两方面缘由:面试
一、“知其然不知其因此然”。作了多年技术,开发了不少业务应用,但彷佛并未思考过种种技术选择背后的逻辑。坦白说,我并不放心把具备必定深度的任务交给他。编程
二、知识碎片化,不成系统。在面试中,面试者彷佛没法完整、清晰地描述本身所开发的系统,或者使用的相关技术。平时可能埋头苦干,或者过于死磕某个实现细节,并无抬头审视这些技术。安全
前人已经掉过的坑,后来的同窗就别再“前仆后继”了!网络
我从个人专栏《Java核心技术36讲》里整理出来了8道Java经典面试题,会从“典型回答”、“考点分析”、“知识扩展”三方面剖析这道题的前因后果及知识要点。不过下文大部分选取了“考点分析”部分,对“典型回答”、“知识扩展”感兴趣的朋友,能够拉到文末,扫码或者点击“阅读原文”订阅个人专栏。架构
至于为何选取“考点分析”,授人以鱼不如授人以渔,但愿你们能经过考点的分析引导,自主思考以找出答案。并发
Java基础app
一、谈谈你对 Java 平台的理解?“Java 是解释执行”,这句话正确吗?框架
考点分析:异步
对于这类笼统的问题,你须要尽可能表现出本身的思惟深刻并系统化,Java 知识理解得也比较全面,必定要避免让面试官以为你是个“知其然不知其因此然”的人。毕竟明白基本组成和机制,是平常工做中进行问题诊断或者性能调优等不少事情的基础,相信没有招聘方会不喜欢“热爱学习和思考”的面试者。
回归正题,对于 Java 平台的理解,能够从不少方面简明扼要地谈一下,例如:Java 语言特性,包括泛型、Lambda 等语言特性;基础类库,包括集合、IO/NIO、网络、并发、安全等基础类库。对于咱们平常工做应用较多的类库,面试前能够系统化总结一下,有助于临场发挥。
下图是我总结的一个相对宽泛的蓝图供你参考。
二、请对比 Exception 和 Error,另外,运行时异常与通常异常有什么区别?
考点分析:
分析 Exception 和 Error 的区别,是从概念角度考察了 Java 处理机制。总的来讲,还处于理解的层面,面试者只要阐述清楚就行了。
咱们在平常编程中,如何处理好异常是比较考验功底的,我以为须要掌握两个方面。
第一,理解 Throwable、Exception、Error 的设计和分类。好比,掌握那些应用最为普遍的子类,以及如何自定义异常等。
不少面试官会进一步追问一些细节,好比,你了解哪些 Error、Exception 或者 RuntimeException?我画了一个简单的类图,并列出来典型例子,能够给你做为参考,至少作到基本内心有数。
第二,理解 Java 语言中操做 Throwable 的元素和实践。掌握最基本的语法是必须的,如 try-catch-finally 块,throw、throws 关键字等。与此同时,也要懂得如何处理典型场景。
三、谈谈 Java 反射机制,动态代理是基于什么原理?
考点分析:
这个题目给个人第一印象是稍微有点诱导的嫌疑,可能会下意识地觉得动态代理就是利用反射机制实现的,这么说也不算错但稍微有些不全面。功能才是目的,实现的方法有不少。
总的来讲,这道题目考察的是 Java 语言的另一种基础机制: 反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言使人意外的活力,经过运行时操做元数据或对象,Java 能够灵活地操做运行时才能肯定的信息。而动态代理,则是延伸出来的一种普遍应用于产品开发中的技术,不少繁琐的重复编程,均可以被动态代理机制优雅地解决。
从考察知识点的角度,这道题涉及的知识点比较庞杂,因此面试官可以扩展或者深挖的内容很是多,好比:
考察你对反射机制的了解和掌握程度。
动态代理解决了什么问题,在你业务系统中的应用场景是什么?
JDK 动态代理在设计和实现上与 cglib 等方式有什么不一样,进而如何取舍?
四、Java 提供了哪些 IO 方式? NIO 如何实现多路复用?
在实际面试中,从传统 IO 到 NIO、NIO 2,其中有不少地方能够扩展开来,考察点涉及方方面面,好比:
基础 API 功能与设计, InputStream/OutputStream 和 Reader/Writer 的关系和区别。
NIO、NIO 2 的基本组成。
给定场景,分别用不一样模型实现,分析 BIO、NIO 等模式的设计和实现原理。
NIO 提供的高性能数据操做方式是基于什么原理,如何使用?
或者,从开发者的角度来看,你以为 NIO 自身实现存在哪些问题?有什么改进的想法吗?
IO 的内容比较多,专栏一讲很难可以说清楚。IO 不只仅是多路复用,NIO 2 也不只仅是异步 IO,尤为是数据操做部分,会在专栏下一讲详细分析。
在这里顺便给你们推荐一个架构交流群:617434785,里面会分享一些资深架构师录制的视频录像
五、如何保证容器是线程安全的?ConcurrentHashMap 如何实现高效地线程安全?
典型回答:
Java 提供了不一样层面的线程安全支持。在传统集合框架内部,除了 Hashtable 等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),咱们能够调用 Collections 工具类提供的包装方法,来获取一个同步的包装容器(如 Collections.synchronizedMap),可是它们都是利用很是粗粒度的同步方式,在高并发状况下,性能比较低下。
另外,更加广泛的选择是利用并发包提供的线程安全容器类,它提供了:
各类并发容器,好比 ConcurrentHashMap、CopyOnWriteArrayList。
各类线程安全队列(Queue/Deque),如 ArrayBlockingQueue、SynchronousQueue。
各类有序容器的线程安全版本等。
具体保证线程安全的方式,包括有从简单的 synchronize 方式,到基于更加精细化的,好比基于分离锁实现的 ConcurrentHashMap 等并发实现等。具体选择要看开发的场景需求,整体来讲,并发包内提供的容器通用场景,远优于早期的简单同步实现。
六、谈谈接口和抽象类有什么区别?
考点分析:
这是个很是高频的 Java 面向对象基础问题,看起来很是简单的问题,若是面试官稍微深刻一些,你会发现不少有意思的地方,能够从不一样角度全面地考察你对基本机制的理解和掌握。
好比:
对于 Java 的基本元素的语法是否理解准确。可否定义出语法基本正确的接口、抽象类或者相关继承实现,涉及重载(Overload)、重写(Override)更是有各类不一样的题目。
在软件设计开发中妥善地使用接口和抽象类。你至少知道典型应用场景,掌握基础类库重要接口的使用;掌握设计方法,可以在 review 代码的时候看出明显的不利于将来维护的设计。
掌握 Java 语言特性演进。如今很是多的框架已是基于 Java 8,并逐渐支持更新版本,掌握相关语法,理解设计目的是颇有必要的。
Java进阶
七、synchronized 底层如何实现?什么是锁的升级、降级?
考点分析:
今天的问题主要是考察你对 Java 内置锁实现的掌握,也是并发的经典题目。我在前面给出的典型回答,涵盖了一些基本概念。若是基础不牢,有些概念理解起来就比较晦涩,我建议仍是尽可能理解和掌握,即便有不懂的也不用担忧,在后续学习中还会逐步加深认识。
我我的认为,可以基础性地理解这些概念和机制,其实对于大多数并发编程已经足够了,毕竟大部分工程师未必会进行更底层、更基础的研发,不少时候解决的是知道与否,真正的提升还要靠实践踩坑。
后面我会进一步分析:
从源码层面,稍微展开一些 synchronized 的底层实现,并补充一些上面答案中欠缺的细节,有同窗反馈这部分容易被问到。若是你对 Java 底层源码有兴趣,但尚未找到入手点,这里能够成为一个切入点。
理解并发包中 java.util.concurrent.lock 提供的其余锁实现,毕竟 Java 可不是只有 ReentrantLock 一种显式的锁类型,我会结合代码分析其使用。
八、synchronized 和 ReentrantLock 有什么区别?有人说 synchronized 最慢,这话靠谱吗?
考点分析:
今天的题目是考察并发编程的常见基础题,我给出的典型回答算是一个相对全面的总结。
对于并发编程,不一样公司或者面试官面试风格也不同,有个别大厂喜欢一直追问你相关机制的扩展或者底层,有的喜欢从实用角度出发,因此你在准备并发编程方面须要必定的耐心。
我认为,锁做为并发的基础工具之一,你至少须要掌握:
理解什么是线程安全。
synchronized、ReentrantLock 等机制的基本使用与案例。
更近一步,你还须要:
掌握 synchronized、ReentrantLock 底层实现;理解锁膨胀、降级;理解偏斜锁、自旋锁、轻量级锁、重量级锁等概念。
掌握并发包中 java.util.concurrent.lock 各类不一样实现和案例分析。
典型回答:
synchronized 是 Java 内建的同步机制,因此也有人称其为 Intrinsic Locking,它提供了互斥的语义和可见性,当一个线程已经获取当前锁时,其余试图获取的线程只能等待或者阻塞在那里。
在 Java 5 之前,synchronized 是仅有的同步手段,在代码中, synchronized 能够用来修饰方法,也可使用在特定的代码块儿上,本质上 synchronized 方法等同于把方法所有语句用 synchronized 块包起来。
ReentrantLock,一般翻译为再入锁,是 Java 5 提供的锁实现,它的语义和 synchronized 基本相同。再入锁经过代码直接调用 lock() 方法获取,代码书写也更加灵活。与此同时,ReentrantLock 提供了不少实用的方法,可以实现不少 synchronized 没法作到的细节控制,好比能够控制 fairness,也就是公平性,或者利用定义条件等。可是,编码中也须要注意,必需要明确调用 unlock() 方法释放,否则就会一直持有该锁。
synchronized 和 ReentrantLock 的性能不能一律而论,早期版本 synchronized 在不少场景下性能相差较大,在后续版本进行了较多改进,在低竞争场景中表现可能优于 ReentrantLock。