Java基础常见面试题总结(上)java面试

Java基础常见面试题总结(上)

22分钟 ·
播放数22
·
评论数0

女:你好,欢迎收听我们的Java面试小课堂。今天我们来聊聊Java里一些最基础但又特别重要的概念。很多同学在面试的时候,感觉自己都会,但一问就懵。我们今天就来把这些基础知识彻底搞懂。第一个问题,我们常说Java是一门很优秀的语言,那它具体有哪些特点呢?

男:问得好。这几乎是每个Java面试的开场白。简单来说,Java有几个核心特点。首先是“简单易学”,它的语法相对C++要简洁,没有指针这些复杂的概念,上手快。其次,也是最重要的,就是“面向对象”,也就是我们常说的封装、继承、多态,这三大特性是Java设计的基石。

女:嗯,面向对象这个我听得最多。

男:对。还有一个非常经典的特点是“平台无关性”,这得益于Java虚拟机,也就是JVM。我们有句口号叫“Write Once, Run Anywhere”,一次编写,随处运行,说的就是这个。另外,Java天生就支持“多线程”,这在开发高并发应用时非常有优势。当然,还有它的可靠性,比如自带异常处理和垃圾回收机制;以及安全性,通过各种机制限制程序直接访问操作系统。最后,也是我认为现在Java最强大的地方,是它“强大的生态”。

女:生态?你指的是像Spring、MyBatis这些框架吗?

男:完全正确。相比于跨平台这些特性,现在通过Docker等虚拟化技术也很容易实现。但Java发展这么多年积累下来的庞大、成熟的开源社区和框架,才是它真正的护城河。无论你想做什么,几乎都能找到现成的、高质量的解决方案。这才是它至今仍然是企业级开发首选的核心原因。

女:原来如此,生态才是王道!刚才你提到了JVM,那我们经常听到的JVM、JDK、JRE,这三个到底是什么关系啊?

男:这个问题很关键。我给你打个比方吧。假设你想开一家餐厅。JRE,Java运行环境,就好比是餐厅的厨房,里面有炉子(JVM)和基本的厨具、调味料(Java基础类库)。只要有这个厨房,你就可以做出菜肴(运行Java程序)。

女:那JDK呢?

男:JDK,Java开发工具包,就是一整套的中央厨房解决方案。它不仅包含了厨房本身(JRE),还给了你菜谱、厨师刀具、甚至是食品安全检测员(比如编译器javac、调试器jdb等)。所以,如果你只是个食客(用户),只需要JRE就够了。但如果你是厨师(开发者),那你就需要JDK来创造新的菜肴(编写和编译程序)。

女:这个比喻很形象!所以JDK是给开发者用的,包含了JRE,而JRE是运行Java程序必需的,它又包含了JVM。那JVM,也就是Java虚拟机,它具体是做什么的呢?

男:JVM的核心作用就是实现我们刚才说的“平台无关性”。我们写的Java代码(.java文件),通过JDK里的编译器(javac)编译后,会生成一种叫做“字节码”的文件(.class文件)。这个字节码不是针对任何具体操作系统的,比如Windows或Linux。它只面向JVM。

女:所以,只要在不同的操作系统上安装对应版本的JVM,这个JVM就能读懂同一个字节码文件,然后翻译成当前系统能懂的机器码去执行?

男:完全正确!这就是“一次编译,随处运行”的秘密。字节码就像一种世界通用语,而每个平台上的JVM就是当地的翻译官。所以,Java程序的可移植性非常好。

女:那我们是不是可以说,Java是一门解释型语言,因为字节码需要JVM来解释执行?

男:这是一个非常经典的问题,标准答案是:Java是“编译与解释并存”的语言。

女:哦?这话怎么说?

男:你看,我们的Java源代码首先被编译成了字节码,这是“编译”的过程,像C++那样的编译型语言。然后,JVM在运行时,一开始确实是通过解释器逐行解释执行字节码,这个过程效率比较低,这是“解释”的过程。但JVM非常智能,它内部还有一个叫JIT的东西,全称是Just-In-Time Compiler,即时编译器。

女:即时编译器?它做什么用?

男:JIT会监控哪些代码被频繁执行,也就是所谓的“热点代码”。对于这些热点代码,JIT不再逐行解释,而是在运行时把它们一次性编译成当前平台最高效的本地机器码,并缓存起来。下次再执行这段代码时,就直接运行编译好的机器码,速度会快得多。所以,Java是先编译成中间语言(字节码),再在运行时通过解释和即-时编译结合的方式执行。这就是“编译与解释并存”的含义。

女:我明白了,JIT就像一个聪明的翻译,发现客户老是问同一句话,他就干脆把答案写在纸上,下次直接递过去,比每次都重新翻译快多了。那既然有JIT这种运行时编译,我好像还听说过一个叫AOT的技术?它又是什么?有什么优点,为什么不全部用它呢?

男:AOT,全称Ahead-of-Time Compilation,意思是“提前编译”。它和JIT正好相反,它不是在运行时编译,而是在程序运行之前,就直接把字节码或者源代码完整地编译成本地机器码。像C++、Go这些语言就是典型的AOT模式。

女:那听起来AOT启动速度会很快啊,因为它省去了运行时解释和JIT预热的时间。

男:是的,这正是AOT最大的优点。它的启动速度快,内存占用也更少,因为不需要JIT编译器在运行时耗费资源。这在对启动性能要求很高的云原生和微服务场景下非常有吸引力。

女:既然AOT这么好,为什么我们不干脆把所有Java程序都用AOT编译呢?

男:好问题。主要有两个原因。第一,JIT在程序长时间运行后,通过收集各种运行时信息,能做出更精准的优化,所以它的峰值性能(极限处理能力)通常比AOT更高。第二,也是更关键的一点,AOT无法很好地支持Java的一些动态特性,比如反射、动态代理。很多主流框架,比如Spring,就大量依赖这些动态特性。如果全部AOT,这些框架就没法用了,或者需要做大量的改造和适配。所以,JIT和AOT各有优劣,是不同场景下的选择,而不是谁取代谁的关系。

女:原来是这样。聊了这么多Java的底层机制,我们再来和另一门很经典的语言对比一下吧。面试时也常被问到,Java和C++的区别是什么?

男:嗯,即使没写过C++,这个问题也要了解。它们都是面向对象的语言,但区别很明显。第一,Java更安全,它没有C++里“指针”的概念,程序员不能直接操作内存,避免了很多内存错误。第二,Java是单继承,一个类只能有一个父类,但可以通过接口实现多继承的效果;而C++支持多重继承。第三,也是对开发者最友好的,Java有自动内存管理,也就是垃圾回收(GC),我们不用手动释放内存,而C++需要。第四,Java只支持方法重载,而C++还支持运算符重载,比如你可以自己定义加号(+)的行为,Java为了保持简洁性去掉了这个特性。

女:明白了。现在我们从概念转向更具体的语法。我们在写代码的时候,都会写注释,这个很简单,但它有哪几种形式呢?

男:Java的注释主要有三种。第一种是“单行注释”,用两个斜杠//,通常用来解释某一行代码。第二种是“多行注释”,用/**/包起来,可以注释一大段代码。第三种是“文档注释”,用/***/包起来,这种注释很特别,可以通过工具(比如javadoc)自动生成API文档。

女:那是不是注释写得越详细越好?

男:恰恰相反。有一本经典的书叫《Clean Code》,里面强调:好的代码本身就是最好的注释。我们应该努力让代码变得清晰易懂,而不是用复杂的注释去解释糟糕的代码。比如,你有一段if判断,与其在上面写一长串注释说“检查员工是否享受全额福利”,不如把这个判断逻辑封装成一个方法,命名为isEligibleForFullBenefits(),这样代码读起来一目了然。

女:有道理,让代码“自解释”。那我们写代码时要起各种名字,比如类名、变量名,这些叫“标识符”,另外还有一些词比如publicclass,这些叫“关键字”,它俩有什么区别?

男:这个区别可以用一个生活中的例子来理解。你想开个店,给店起个名字,比如“小明的小卖部”,这个店名就是“标识符”,是你自己定义的。但是,你不能给你的店起名叫“警察局”,因为“警察局”这个名字已经被赋予了特殊的含义,是系统专用的,它就是“关键字”。所以,关键字就是被Java语言赋予了特殊含义、我们不能另作他用的标识符。

女:哈哈,这个比喻我记住了。那Java里的关键字具体有哪些呢?需要都背下来吗?

男:不需要死记硬背。你只要知道它们大概分为几类就行了,比如用于访问控制的private, public;用于定义类和继承的class, extends;用于程序流程控制的if, else, for, while;还有定义基本数据类型的int, double等等。有个小技巧,所有的关键字都是小写的,在IDE里它们通常会高亮显示,所以你写代码时自然就熟悉了。

女:嗯,那在流程控制里,有三个词经常让人有点混,就是continuebreakreturn,它们仨的区别是什么?

男:这三个确实需要精准区分。我给你一个场景:你在一个for循环里。continue的作用是“跳过本次循环”,直接开始下一次。比如循环到一半,符合某个条件,continue后面的代码就不执行了,直接进入下一轮循环。break的作用是“终结整个循环”,一旦遇到break,整个循环立刻结束,程序会跳到循环外面的下一行代码继续执行。而return更彻底,它是“结束整个方法”,不管你在几层循环里,一旦遇到return,整个方法就结束了,并返回一个值(如果方法有返回值的话)。

女:所以continue是跳过一次,break是跳出循环,return是跳出方法。作用范围一个比一个大。

男:完全正确。理解了这个,看懂很多复杂的循环逻辑就不难了。

女:好的,语法部分我们先聊到这。接下来我们聊聊数据。Java中有哪些基本数据类型呢?

男:Java有8种基本数据类型。可以分成四大类:首先是整数类型,有byteshortintlong,它们表示的范围从小到大。然后是浮点类型,也就是小数,有floatdouble。接着是字符类型char,用来表示单个字符。最后是布尔类型boolean,它只有两个值:truefalse

女:我们定义变量时,既可以用像int这样的基本类型,也可以用Integer这样的包装类型,它俩有什么区别呢?