Java核心技术面试精讲
杨晓峰
前Oracle首席工程师
立即订阅
43250 人已学习
课程目录
已完结 43 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 以面试题为切入点,有效提升你的Java内功
免费
模块一 Java基础 (14讲)
第1讲 | 谈谈你对Java平台的理解?
第2讲 | Exception和Error有什么区别?
第3讲 | 谈谈final、finally、 finalize有什么不同?
第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别?
第5讲 | String、StringBuffer、StringBuilder有什么区别?
第6讲 | 动态代理是基于什么原理?
第7讲 | int和Integer有什么区别?
第8讲 | 对比Vector、ArrayList、LinkedList有何区别?
第9讲 | 对比Hashtable、HashMap、TreeMap有什么不同?
第10讲 | 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复用?
第12讲 | Java有几种文件拷贝方式?哪一种最高效?
第13讲 | 谈谈接口和抽象类有什么区别?
第14讲 | 谈谈你知道的设计模式?
模块二 Java进阶 (16讲)
第15讲 | synchronized和ReentrantLock有什么区别呢?
第16讲 | synchronized底层如何实现?什么是锁的升级、降级?
第17讲 | 一个线程两次调用start()方法会出现什么情况?
第18讲 | 什么情况下Java程序会产生死锁?如何定位、修复?
第19讲 | Java并发包提供了哪些并发工具类?
第20讲 | 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
第21讲 | Java并发类库提供的线程池有哪几种? 分别有什么特点?
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
第23讲 | 请介绍类加载过程,什么是双亲委派模型?
第24讲 | 有哪些方法可以在运行时动态生成一个Java类?
第25讲 | 谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?
第26讲 | 如何监控和诊断JVM堆内和堆外内存使用?
第27讲 | Java常见的垃圾收集器有哪些?
第28讲 | 谈谈你的GC调优思路?
第29讲 | Java内存模型中的happen-before是什么?
第30讲 | Java程序运行在Docker等容器环境有哪些新问题?
模块三 Java安全基础 (2讲)
第31讲 | 你了解Java应用开发中的注入攻击吗?
第32讲 | 如何写出安全的Java代码?
模块四 Java性能基础 (3讲)
第33讲 | 后台服务出现明显“变慢”,谈谈你的诊断思路?
第34讲 | 有人说“Lambda能让Java程序慢30倍”,你怎么看?
第35讲 | JVM优化Java代码时都做了什么?
模块5 Java应用开发扩展 (4讲)
第36讲 | 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景?
第37讲 | 谈谈Spring Bean的生命周期和作用域?
第38讲 | 对比Java标准NIO类库,你知道Netty是如何实现更高性能的吗?
第39讲 | 谈谈常用的分布式ID的设计方案?Snowflake是否受冬令时切换影响?
周末福利 (2讲)
周末福利 | 谈谈我对Java学习和面试的看法
周末福利 | 一份Java工程师必读书单
结束语 (1讲)
结束语 | 技术没有终点
Java核心技术面试精讲
登录|注册

第1讲 | 谈谈你对Java平台的理解?

杨晓峰 2018-05-05
从你接触 Java 开发到现在,你对 Java 最直观的印象是什么呢?是它宣传的 “Write once, run anywhere”,还是目前看已经有些过于形式主义的语法呢?你对于 Java 平台到底了解到什么程度?请你先停下来总结思考一下。
今天我要问你的问题是,谈谈你对 Java 平台的理解?“Java 是解释执行”,这句话正确吗?

典型回答

Java 本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的“书写一次,到处运行”(Write once, run anywhere),能够非常容易地获得跨平台能力;另外就是垃圾收集(GC, Garbage Collection),Java 通过垃圾收集器(Garbage Collector)回收分配内存,大部分情况下,程序员不需要自己操心内存的分配和回收。
我们日常会接触到 JRE(Java Runtime Environment)或者 JDK(Java Development Kit)。 JRE,也就是 Java 运行环境,包含了 JVM 和 Java 类库,以及一些模块等。而 JDK 可以看作是 JRE 的一个超集,提供了更多工具,比如编译器、各种诊断工具等。
对于“Java 是解释执行”这句话,这个说法不太准确。我们开发的 Java 的源代码,首先通过 Javac 编译成为字节码(bytecode),然后,在运行时,通过 Java 虚拟机(JVM)内嵌的解释器将字节码转换成为最终的机器码。但是常见的 JVM,比如我们大多数情况使用的 Oracle JDK 提供的 Hotspot JVM,都提供了 JIT(Just-In-Time)编译器,也就是通常所说的动态编译器,JIT 能够在运行时将热点代码编译成机器码,这种情况下部分热点代码就属于编译执行,而不是解释执行了。

考点分析

其实这个问题,问得有点笼统。题目本身是非常开放的,往往考察的是多个方面,比如,基础知识理解是否很清楚;是否掌握 Java 平台主要模块和运行原理等。很多面试者会在这种问题上吃亏,稍微紧张了一下,不知道从何说起,就给出个很简略的回答。
对于这类笼统的问题,你需要尽量表现出自己的思维深入并系统化,Java 知识理解得也比较全面,一定要避免让面试官觉得你是个“知其然不知其所以然”的人。毕竟明白基本组成和机制,是日常工作中进行问题诊断或者性能调优等很多事情的基础,相信没有招聘方会不喜欢“热爱学习和思考”的面试者。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java核心技术面试精讲》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(257)

  • Woj
    “一次编译、到处运行”说的是Java语言跨平台的特性,Java的跨平台特性与Java虚拟机的存在密不可分,可在不同的环境中运行。比如说Windows平台和Linux平台都有相应的JDK,安装好JDK后也就有了Java语言的运行环境。其实Java语言本身与其他的编程语言没有特别大的差异,并不是说Java语言可以跨平台,而是在不同的平台都有可以让Java语言运行的环境而已,所以才有了Java一次编译,到处运行这样的效果。
            严格的讲,跨平台的语言不止Java一种,但Java是较为成熟的一种。“一次编译,到处运行”这种效果跟编译器有关。编程语言的处理需要编译器和解释器。Java虚拟机和DOS类似,相当于一个供程序运行的平台。
            程序从源代码到运行的三个阶段:编码——编译——运行——调试。Java在编译阶段则体现了跨平台的特点。编译过程大概是这样的:首先是将Java源代码转化成.CLASS文件字节码,这是第一次编译。.class文件就是可以到处运行的文件。然后Java字节码会被转化为目标机器代码,这是是由JVM来执行的,即Java的第二次编译。
            “到处运行”的关键和前提就是JVM。因为在第二次编译中JVM起着关键作用。在可以运行Java虚拟机的地方都内含着一个JVM操作系统。从而使JAVA提供了各种不同平台上的虚拟机制,因此实现了“到处运行”的效果。需要强调的一点是,java并不是编译机制,而是解释机制。Java字节码的设计充分考虑了JIT这一即时编译方式,可以将字节码直接转化成高性能的本地机器码,这同样是虚拟机的一个构成部分。

    作者回复: 高手

    2018-05-05
    3
    706
  • magict4
    我对『Compile once, run anywhere』这个宣传语提出的历史背景非常感兴趣。这个宣传语似乎在暗示 C 语言有一个缺点:对于每一个不同的平台,源代码都要被编译一次。我不解的地方是,为什么这会是一个问题?不同的平台,可执行的机器码必然是不一样的。源代码自然需要依据不同的平台分别被编译。 我觉得真正问题不在编译这一块,而是在 C 语言源文件这一块。我没有 C 语言的编程经验,但是似乎 C 语言程序经常需要调用操作系统层面的 API。不同的操作系统,API 一般不同。为了支持多平台,C 语言程序的源文件需要根据不同平台修改多次。这应该是一个非常大的痛点。我回头查了一下当时的宣传语,原文是『Write once, run anywhere』,焦点似乎并不在编译上,而是在对源文件的修改上。

    以上是自己一点不成熟的想法,还请大家指正!

    作者回复: 汗颜,是我记错了,非常感谢指正

    2018-05-05
    3
    361
  • 三军
    Java特性:
    面向对象(封装,继承,多态)
    平台无关性(JVM运行.class文件)
    语言(泛型,Lambda)
    类库(集合,并发,网络,IO/NIO)
    JRE(Java运行环境,JVM,类库)
    JDK(Java开发工具,包括JRE,javac,诊断工具)

    Java是解析运行吗?
    不正确!
    1,Java源代码经过Javac编译成.class文件
    2,.class文件经JVM解析或编译运行。
    (1)解析:.class文件经过JVM内嵌的解析器解析执行。
    (2)编译:存在JIT编译器(Just In Time Compile 即时编译器)把经常运行的代码作为"热点代码"编译与本地平台相关的机器码,并进行各种层次的优化。
    (3)AOT编译器: Java 9提供的直接将所有代码编译成机器码执行。

    作者回复: 精辟

    2018-05-05
    295
  • 虾丸派
    内容看了十分钟,评论看了半小时。
    2018-06-25
    209
  • Jerry银银
    关注了好久,终于期盼到了第一讲。

    在看到这个题目时,我并没有立马点进来看原文,而是给了自己一些时间进行思考。

    首先,个人觉得这个题目非常的抽象和笼统,这个问题没有标准答案,但是有『好』答案,而答案的好坏,完全取决于面试者自身的技术素养和对Java系统性的了解。我的理解如下:

    宏观角度:
    跟c/c++最大的不同点在于,c/c++编程是面向操作系统的,需要开发者极大地关心不同操作系统之间的差异性;而Java平台通过虚拟机屏蔽了操作系统的底层细节,使得开发者无需过多地关心不同操作系统之间的差异性。
    通过增加一个间接的中间层来进行”解耦“是计算机领域非常常用的一种”艺术手法“,虚拟机是这样,操作系统是这样,HTTP也是这样。

    Java平台已经形成了一个生态系统,在这个生态系统中,有着诸多的研究领域和应用领域:
    1. 虚拟机、编译技术的研究(例如:GC优化、JIT、AOT等):对效率的追求是人类的另一个天性之一
    2. Java语言本身的优化
    3. 大数据处理
    4. Java并发编程
    5. 客户端开发(例如:Android平台)
    6. ......


    微观角度:
    Java平台中有两大核心:
    1. Java语言本身、JDK中所提供的核心类库和相关工具
    2. Java虚拟机以及其他包含的GC

    1. Java语言本身、JDK中所提供的核心类库和相关工具
    从事Java平台的开发,掌握Java语言、核心类库以及相关工具是必须的,我觉得这是基础中的基础。
    >> 对语言本身的了解,需要开发者非常熟悉语言的语法结构;而Java又是一种面对对象的语言,这又需要开发者深入了解面对对象的设计理念;
    >> Java核心类库包含集合类、线程相关类、IO、NIO、J.U.C并发包等;
    >> JDK提供的工具包含:基本的编译工具、虚拟机性能检测相关工具等。

    2. Java虚拟机
    Java语言具有跨平台的特性,也正是因为虚拟机的存在。Java源文件被编译成字节码,被虚拟机加载后执行。这里隐含的意思有两层:
    1)大部分情况下,编程者只需要关心Java语言本身,而无需特意关心底层细节。包括对内存的分配和回收,也全权交给了GC。
    2)对于虚拟机而言,只要是符合规范的字节码,它们都能被加载执行,当然,能正常运行的程序光满足这点是不行的,程序本身需要保证在运行时不出现异常。所以,Scala、Kotlin、Jython等语言也可以跑在虚拟机上。

    围绕虚拟机的效率问题展开,将涉及到一些优化技术,例如:JIT、AOT。因为如果虚拟机加载字节码后,完全进行解释执行,这势必会影响执行效率。所以,对于这个运行环节,虚拟机会进行一些优化处理,例如JIT技术,会将某些运行特别频繁的代码编译成机器码。而AOT技术,是在运行前,通过工具直接将字节码转换为机器码。

    作者回复: 👍

    2018-05-06
    2
    158
  • 欧阳田
    1,JVM的内存模型,堆、栈、方法区;字节码的跨平台性;对象在JVM中的强引用,弱引用,软引用,虚引用,是否可用finalise方法救救它?;双亲委派进行类加载,什么是双亲呢?双亲就是多亲,一份文档由我加载,然后你也加载,这份文档在JVM中是一样的吗?;多态思想是Java需要最核心的概念,也是面向对象的行为的一个最好诠释;理解方法重载与重写在内存中的执行流程,怎么定位到这个具体方法的。2,发展流程,JDK5(重写bug),JDK6(商用最稳定版),JDK7(switch的字符串支持),JDK8(函数式编程),一直在发展进化。3,理解祖先类Object,它的行为是怎样与现实生活连接起来的。4,理解23种设计模式,因为它是道与术的结合体。

    作者回复: 高手

    2018-05-05
    1
    114
  • zaiweiwoaini
    看评论也能学习知识。

    作者回复: 搬个板凳,哈哈

    2018-05-05
    111
  • 姜亮
    写个程序直接执行字节码就是解释执行。写个程序运行时把字节码动态翻译成机器码就是jit。写个程序把java源代码直接翻译为机器码就是aot。造个CPU直接执行字节码,字节码就是机器码。

    作者回复: 好主意,当年确实有类似项目

    2018-05-07
    110
  • thinkers
    jre为java提供了必要的运行时环境,jdk为java提供了必要的开发环境!

    作者回复: 剧透一下,未来jre将退出历史舞台!

    2018-05-05
    82
  • 刻苦滴涛涛
    我理解的java程序执行步骤:
    首先javac编译器将源代码编译成字节码。
    然后jvm类加载器加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度相对会比较慢。有些方法和代码块是高频率调用的,也就是所谓的热点代码,所以引进jit技术,提前将这类字节码直接编译成本地机器码。这样类似于缓存技术,运行时再遇到这类代码直接可以执行,而不是先解释后执行。

    作者回复: 不错,JIT是运行时编译

    2018-05-05
    77
  • scott
    解释执行和编译执行有何区别

    作者回复: 类比一下,一个是同声传译,一个是放录音

    2018-05-07
    2
    54
  • 张立春
    任何软件问题都可以通过加一层来解决:有了系统API就屏蔽了不同硬件的区别,有了编译器就屏蔽了不同机器语言的区别,有了JVM就屏蔽了不同操作系统的区别,有了TCP/IP就屏蔽了不同系统之间通讯的差异,有了语音识别和翻译就屏蔽了不同语言的差异。也许有一天人工智能可以直接把自然语言翻译成机器码直接生产可用的软件。
    2018-05-07
    1
    46
  • 约书亚
    这种基于运行分析,进行热点代码编译的设计,是因为绝大多数的程序都表现为“小部分的热点耗费了大多数的资源”吧。只有这样才能做到,在某些场景下,一个需要跑在运行时上的语言,可以比直接编译成机器码的语言更“快”

    作者回复: 对,看到本质了

    2018-05-05
    37
  • 一叶追寻
    对Java平台的理解,首先想到的是Java的一些特性,比如平台无关性、面向对象、GC机制等,然后会在这几个方面去回答。平台无关性依赖于JVM,将.class文件解释为适用于操作系统的机器码。面向对象则会从封装、继承、多态这些特性去解释,具体内容就不在评论里赘述了。另外Java的内存回收机制,则涉及到Java的内存结构,堆、栈、方法区等,然后围绕什么样的对象可以回收以及回收的执行。以上是我对本道题的理解,不足之处还请杨老师指出,希望通过这次学习能把Java系统的总结一下~

    作者回复: 非常棒,不同语言对平台无关的支持是不同的,Java是最高等级,未来也许会在效率角度出发,进行某种折衷,比如AOT

    2018-05-05
    36
  • 半日闲
    编译型语言:C/C++、 Pascal(Delphi)
    编译就是把源代码(高级语言,人类容易读,容易理解)转换成机器码(CPU能理解,能高效的执行)

    解释型语言:JavaScript、Perl、Python、Ruby
    解释就简单多了,解析源代码,并且直接执行,没有编译过程

    编译程序是整体编译完了,再一次性执行。 而解释程序是一边解释,一边执行

     JAVA语言是一种编译型-解释型语言,同时具备编译特性和解释特性
     其所谓的编译过程只是将.java文件编程成平台无关的字节码.class文件,
     并不是向C一样编译成可执行的机器语言,在此请读者注意Java中所谓的“编译”和传统的“编译”的区别。
     
     作为编译型语言,JAVA程序要被统一编译成字节码文件——文件后缀是class。此种文件在java中又称为类文件。
     java类文件不能再计算机上直接执行,它需要被java虚拟机翻译成本地的机器码后才能执行,而java虚拟机的翻译过程则是解释性的。
     java字节码文件首先被加载到计算机内存中,然后读出一条指令,翻译一条指令,执行一条指令,该过程被称为java语言的解释执行,是由java虚拟机完成的。
     以上说的是Java的解释执行,但是比如我们大多数情况使用的Hotspot JVM,都提供了动态编译器编译器JIT,能够追踪热点代码, 然后变成机器指令,这种情况下部分热点代码就属于编译执行,而不是解释执行了
     
     其实甭管它什么解释还是编译, 了解了底层的原理就行了
    2018-05-11
    34
  • 非常非常非常非常的普通中下
    没有一个问题是加一个中间层解决不了的,如果解决不了就加两个
    2018-05-08
    29
  • 石头狮子
    1. 一次编译,到处运行。jvm 层面封装了系统API,提供不同系统一致的调用行为。减少了为适配不同操作系统,不同架构的带来的工作量。
    2. 垃圾回收,降低了开发过程中需要注意内存回收的难度。降低内存泄露出现的概率。虽然也带来了一些额外开销,但是足以弥补带来的好处。合理的分代策略,提高了内存使用率。
    3. jit 与其他编译语言相比,降低了编译时间,因为大部分代码是运行时编译,避免了冷代码在编译时也参与编译的问题。
        提高了代码的执行效率,之前项目中使用过 lua 进行相关开发。由于 lua 是解释性语言,并配合使用了 lua-jit。开发过程中遇到,如果编写的 lua 代码是 jit 所不支持的会导致代码性能与可编译的相比十分低下。

    作者回复: 高手

    2018-05-05
    27
  • 国富论中讲到,社会的分工细化起到了提高生产力的关键作用。我觉得一次编写到处运行也是社会分工的一种模式,他使大部分业务程序员注重领域模型的逻辑设计,不必关心底层的实现,使软件工程达到了专业的人做专业的事这一个高度。虽然现在掌握一门技术远远不够,但是对于大部分业务程序员来说,只有把精力花在最重要的地方比如领域模型的设计,才会让业务更加流畅完善。所以我觉得JVM机制蕴含了一定的经济学原理。
    2018-05-08
    23
  • 櫻の空
    以下是我在本节课所得到的收获,结合TIJ的内容整理了一下我个人的理解,若有错误,还望老师指出。
    Java采用的是解释和编译混合的模式。它首先通过javac将源码编译成字节码文件class.然后在运行的时候通过解释器或者JIT将字节码转换成最终的机器码。
    只是用解释器的缺点:抛弃了JIT可能带来的性能优势。如果代码没有被JIT编译的话,再次运行时需要重复解析。
    只用JIT的缺点:
    需要将全部的代码编译成本地机器码。要花更多的时间,JVM启动会变慢非常多;
    增加可执行代码的长度(字节码比JIT编译后的机器码小很多),这将导致页面调度,从而降低程序的速度。
    有些JIT编译器的优化方式,比如分支预测,如果不进行profiling,往往并不能进行有效优化。
    因此,HotSpot采用了惰性评估(Lazy Evaluation)的做法,根据二八定律,消耗大部分系统资源的只有那一小部分的代码(热点代码),而这也就是JIT所需要编译的部分。JVM会根据代码每次被执行的情况收集信息并相应地做出一些优化,因此执行的次数越多,它的速度就越快。
    JDK 9引入了一种新的编译模式AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了JIT预热等各方面的开销。JDK支持分层编译和AOT协作使用。
    注:JIT为方法级,它会缓存编译过的字节码在CodeCache中,而不需要被重复解释

    作者回复: 不错,严格说我说的是oracle jdk和hotspot jvm的行为

    2018-05-14
    22
  • @肘底看拳
    今日读完这一讲之后,最想弄懂的和收获最大的就是,java的write once run anywhere 这句话包含的原理了。也就是java程序执行的过程。因为的基础比较薄弱,一开始我觉得有点迷惑的是编译这两个字的含义和作用到底应该如何理解。
    首先不应该混淆java的编译和其他的语言(比如C)的编译二字的含义,C语言的编译包含两个过程,汇编和编译,C语言代码被汇编之后,会得到汇编语言代码,而编译就是将汇编语言代码翻译称为机器指令代码的过程,然后在经过一个链接的过程生成了一个可执行的文件。所以C语言经历过编译步骤之后直接就变成了可以被平台底层执行的代码了,这个过程是最初的编译的含义。而java的执行过程是,首先通过javac编译java源代码为字节码,然后JVM将这些字节码文件加载进来,加载进来一句,就解释一句,解释出来一句就执行一句,相当于是解释和执行是同步执行的,这种模式被称为解释执行。需要明确的一点:解释执行这个过程并不会产生目标文件,也就是说这些可以被平台执行的机器码文件并没有生成,下次如果还是这部分代码被执行的时候,还需要重新的被解释一遍,这样每次都重复这个过程就会很耗时,因此java引入了JIT,(在程序运行时) 将那些执行比较频繁的代码,也被称作热点代码,编译成为机器码,这个时候其实内存中是保存了一部分这部分机器码的,这样就解决了上面所描述的问题。但是因为JIT是运行时将字节码文件编译成为机器码文件,所以会占用运行时资源,造成进程卡段,因此就又引入了AOT(静态编译),就是在程序运行之前就将字节码编译成为机器码,不会占用到运行时的CPU资源。这样就解决了JIT的问题。但是这样的话在某些程度上其实就和C语言一样了,牺牲了java的跨平台特性,所以JIT和AOT都有不同的优缺点,所以我们可以在虚拟机的指令中指定启动虚拟机的时候采用的模式。来更好的控制虚拟机为我们带来更好的编程体验。
    这就是我学习这节课收获最深的部分。
    2019-03-14
    1
    20
收起评论
99+
返回
顶部