又逢“金九银十”,年轻的毕业生们满怀希望与忐忑,去寻找、竞争一个工作机会。已经在职的开发同学,也想通过社会招聘或者内推的时机争取到更好的待遇、更大的平台。
然而,面试人群众多,技术市场却相对冷淡,面试的同学们不得不面临着 1 个职位 N 个应聘者的巨大竞争。
问:在这种现状下,如何才能收获又多又好的 Offer?
答:短期准备——刷面试题;长期筹谋——巩固核心技能。
面试题怎么刷?刷高频题、有深度的题、符合时效性的题。
核心技能如何巩固?先深入理解原理,再系统应用到实践。
不过,面试成功并不是终极目标。我们要的,是在接下来的工作中,把所学的技能点运用到产品开发,发挥重要的工作价值。
从业十多年,我先是一个被面试者,又成为面试官。为了使更多开发者拿到好 Offer 并且顺利工作,也为了帮助企业找到合适技术人才,我拜访几十家互联网公司、花了大半年,付出很多心血,凝结成这个课程——《Java面试全解析:核心知识点与典型面试题》。
课程亮点500道 Java 常见面试题 + 10万字核心知识解析
丰富的 Java 技术栈:基础和框架,线程池和锁优化,SpringBoot 和分布式消息队列,数据结构和常用算法,设计模式和 JVM 等
易学易会:提供了大量的图片说明和代码示例
Java 核心知识图谱 X1 + 阿里内推名额 X1 + 阿里面试通关攻略 X1 + 阿里内推交流群 X1
- 准备 Java 面试的在校生(大专或研究生)
- 准备跳槽、正在找工作的 Java 工程师
- 自学和准备转行到 Java 技术领域的人
- 想巩固 Java 核心知识、查漏补缺的人
- 收获 Java 技术栈的核心知识点
这个课程几乎涵盖了 Java 技术栈的大部分内容,不止对于面试,在日常的工作中也可以发挥很大的作用。
- 详解 500 多道实用、权威、高频 Java 面试题
这 500 多道面试题,都是目前主流企业使用最高频的面试题库,也都是 Java 版本升级之后,重新整理归纳的最新答案,会让面试者少走很多不必要的弯路。同时每道题都做到了详尽的描述,以确保每个阶段的读者都能看得懂,面试题中的专业短语也都确保提供了必要的介绍,部分难懂的题目也提供了题目解析和示例代码。
- 理解技术背后的实现原理
死记硬背的内容通常会随着时间的推移很快就忘记,所以在学习一门技术的时候,一定要了解其背后的实现原理,从而构建逻辑上的因果关系,这样才能够记的更久。这门课程会深入浅出地对技术背后的原理进行深入的分析,让读者“知其然,并知其所以然”。
作者介绍老王 资深面试官,阿里云社区认证专家。
十余年编程从业经验,现上市公司技术研发经理,曾就职于 360,有着丰富的大型系统设计、开发和调优的经验,在不断探索和学习的过程中,积累了宝贵的编程与面试经验。公众号「Java中文社群」。
- 本课程为图文内容课程,共计 37 篇,8月19日起,每周更新 2 篇或 2 篇以上
- 付费用户可享受文章永久阅读权限
- 读者可在评论区向作者提问或交流
- 本课程为虚拟产品,一经付费概不退款,敬请谅解
- 本课程可在 GitChat 服务号、APP 及网页端 gitbook.cn 上购买,一端购买,多端阅读
- 订购本课程可获得专属海报,分享专属海报每成功邀请一位好友购买,即可获得返现奖励,多邀多得,上不封顶,立即提现
- 提现流程:请在 GitChat 服务号中点击“我-我的邀请-提现”进行提现
你好,我是王磊,某上市公司技术研发经理,前奇虎 360 员工,有着 10 余年的编程工作经验,目前主要负责新员工技术面试和构建企业技术架构的相关事宜。随着面试过的人数增加,我发现面试者们暴露出了技术方面的很多问题,为了让更多面试者少走一些弯路,也为了让企业能招到合适的技术人才,于是就诞生了这门课程。
为了能把这门课程写好,我先后拜访了一二十家互联网公司,与不同的面试官和面试者进行面对面探讨,深入了解了企业对于面试者的要求和常见的 Java 面试题型。之后我花了大半年的时间,结合自己 4 年多作为面试官的经历,把这些内容整理成文,用大约 10万 字的内容对 Java 的核心知识点和常见的 500 多道面试题,做了详细的介绍,也就是本课程中你所看到的全部内容,希望对你能有所帮助。
为什么要学这门课程?「因为它能为你赢得面试的主动权,让你获得更多的 Offer。」
从业十多年,我从面试者变成面试官,在 Java 面试上积累了比较丰富的经验。
其实,很多面试者在搜集面试资料的时候都踩过一些“坑”,你是不是也遇到过:
- 免费搜索的面试题,内容不全面,这就算了,有时候答案都不准确;
- 很多培训机构提供的面试宝典内容虽然不少,但深度不够,且面试题过于老旧脱离了企业实际需要;
- 还有很多付费的面试题存在滥竽充数,提供了很多没有价值的面试题,钱花了,干货没学到;
- 市面上大部分面试题只讲了基础概念,没有提供题目解析和示例代码,不利于读者真正的掌握背后的原理,只能死记硬背,且容易忘记。
为了规避这些“坑”,我跑了很多家互联网公司,来确认 Java 面试中实际考察的高频知识点和常见题型。可是有了第一手素材后,我要如何让大家真正从我的讲解中学到干货、用到实处呢?
经过反复验证,我才设计了如下的内容讲述模式。
第一,500+ 面试题详解。
如果你是还没走入职场的新人,我会为你提供完整的 Java 技术栈讲解,以及 最新、最全、最实用 的 500 多道 Java 面试题详解。
第二,10万字 Java 核心知识点梳理。
本课程的每一篇内容,都采用的是「核心知识点 + N道相关面试题」的模式,让你不单能应付面试,还能学到更多的 Java 核心知识。
第三,技术、面试搭配平衡,不但让你学到心里,还助你展示出来。
面对目前技术市场的相对冷淡和一个职位多个应聘者竞争的现状,面试者们只有掌握更多 Java 核心技能和面试理论知识,才能在众多面试者中脱颖而出。
本课程每篇文章大致分为两个部分:Java 核心点介绍 + 相关面试题详解,这两部分内容相辅相成,前面的核心知识点介绍让后面的面试题更容易理解,后面的面试题加深了读者对于 Java 核心点的掌握。如此一来,让你所学及所用,不仅能够应付面试,更能学习到更多有价值的 Java 技术点,让你在面试中和工作中都能展示的更加出色。
点击收下这份《Java 面试全解析》
课程大纲本课程分为七大部分,共计 37 讲,约 10 万字。
第一部分:Java 基础强化这部分包含 7 篇文章,我会从 Java 最基础的内容讲起。有最常见的 String 面试题从表象到原理的深入讲解;还有 Java 8 中新特性的介绍,比如时间和日期模块,让你使用更简洁和优化的方式写出更完美的代码;还有我们日常用的很多包装类不为人知的有趣现象和知识盲点介绍;还有数组以及算法的介绍,虽然基础但容易被面试者忽略和容易出错的问题……
第二部分:各种类和克隆这部分包含 4 篇文章,除了会深入讲解 Java 中的各种类和接口的相关内容,还会深入讲解浅克隆和深克隆的各种实现方式,以及配合各种图片让你更形象地理解深/浅克隆的本质。
第三部分:数据结构和队列这部分包含 4 篇文章,对面试中必考的集合,除了相关的面试题讲解,更要理清各种集合之间的关系,创建集合之间的联系,这样才能对集合的整体理解做到心中有数。我使用了归纳法和各种关系图,帮你理清思路,打通你的“任督二脉”。其中还有队列的内容,可能开发者经常会听到,但实际的工作中使用的较少,本部分内容也会带你玩转这些数据结构,让你在面试中能够应对自如。
第四部分:反射和动态代理这部分会帮你理清反射和动态代理的关系,并提供很多实际使用的场景,让你更好地使用到反射和动态代理,当然这部分也会为你提供各种形式反射和动态代理的实现方式,让你可以随心所欲的使用它们。这部分内容还提供了 IO 的相关知识,并提供详细的示例和原理分析,也会试着编写一个简单 Socket 服务器。
第五部分:多线程编程这部分包含 7 篇文章,讲述了包含 Java 8 在内的 8 种线程池,以及线程池的正确使用姿势,还有死锁代码的编写和死锁的解决方案。本部分还会介绍 Java 中的各种锁,以及它们的区别和使用场景,还会介绍 CAS 和著名的 ABA 问题的解决方案,还有多线程中的各种高频面试题。
第六部分:Java 热门框架和分布式消息队列这部分包含 6 篇文章,从 Spring 到最近比较热门的微服务框架 SpringBoot,还有国内常用的 Mybatis 和 Java 技术栈中其他常用的框架,比如 Dubbo 和 Zookeeper,还有分布式消息队列 RabbitMQ 和 Kafka 的介绍和面试题汇总。
第七部分:Java 高手进阶本部分内容包含 6 篇文章,可谓 Java 技术栈最实用的面试补充“大礼包”,有设计模式的面试题汇总;还有 DBA 级别的 MySQL 和 Redis 面试题汇总;还有成为高手必懂的 JVM 和算法的面试题汇总;最后回到本课程的主题内容,提供了 Java 最容易出错的面试题汇总作为收束篇目,助你稳健地拿到想要的 Offer。
以下是这门课程的知识树:
点击可查《Java 面试全解析》还会讲什么
课程寄语希望通过本门课程的学习,你不但能拿到 Offer、取得更好的工作,还能建立一个完整的 Java 知识体系,让你学到的所有内容都能转化为实际的生产力,帮你在工作中取得不凡的成绩。并且希望明白原理后的你,能把这些记忆一直存储在自己大脑中,这样它将会成为你一辈子的财富。
我坚信:持续学习才是最有价值的投资,让我们一起行动起来,一起来做这件最有价值的事情。
最后,预祝每一位学习本门课的朋友,都能找到一份自己理想中的工作。
此外,我们为本课程付费读者创建了《Java 面试全解析》的微信交流群,方便读者更有针对性地讨论课程相关问题,以及分享Java 技术和面试心得。
入群请添加「GitChat 小助手泰勒」:识别下方二维码,或者添加 GitChatty5,注明「Java 面试」。
温馨提示:需购买才可入群哦,加小助手后需要截图已购买页面来发给小助手验证一下~
了解任何一门语言的精髓都是先俯览其全貌,从宏观的视角把握全局,然后再深入每个知识点逐个击破,这样就可以深入而快速的掌握一项技能。同样学习 Java 也是如此,本节就让我们先从整体来看一下 Java 中的精髓。
Java 介绍Java 诞生于 1991 年,Java 的前身叫做 Oak(橡树),但在注册商标的时候,发现这个名字已经被人注册了,后来团队的人就在咖啡馆讨论这件事该怎么办,有人灵机一动说叫 Java 如何,因为当时他们正在喝着一款叫做 Java 的咖啡。就这样,这个后来家喻户晓的名字,竟以这种“随意”的方式诞生了,并一直沿用至今。
Java 发展历程:
- 1990,Sun 成立了“Green Team”项目小组
- 1991,Java 语言前身 Oak(橡树)诞生
- 1995,Oak 语言更名为 Java
- 1996,Java 1.0 发布
- 1997,Java 1.1 发布
- 1998,Java 1.2 发布
- 2000,Java 1.3 发布
- 2000,Java 1.4 发布
- 2004,Java 5 发布
- 2006,Java 6 发布
- 2011,Java 7 发布
- 2014,Java 8 发布
- 2017,Java 9(非长期支持版)发布
- 2018.03,Java 10(非长期支持版) 发布
- 2018.09,Java 11(长期支持版)发布
- 2019.03, Java 12(非长期支持版) 发布
注:长期支持版指的是官方发布版本后的一段时间内,通常以“年”为计数单位,会对此版本进行持续维护和升级。
版本发布时间Java 10 之后,官方表示每半年推出一个大版本,长期支持版本(LTS)每三年发布一次。
Java 和 JDK 的关系JDK(Java Development Kit)Java 开发工具包,它包括:编译器、Java 运行环境(JRE,Java Runtime Environment)、JVM(Java 虚拟机)监控和诊断工具等,而 Java 则表示一种开发语言。
Java 程序是怎么执行的?我们日常的工作中都使用开发工具(IntelliJ IDEA 或 Eclipse 等)可以很方便的调试程序,或者是通过打包工具把项目打包成 jar 包或者 war 包,放入 Tomcat 等 Web 容器中就可以正常运行了,但你有没有想过 Java 程序内部是如何执行的?
其实不论是在开发工具中运行还是在 Tomcat 中运行,Java 程序的执行流程基本都是相同的,它的执行流程如下:
- 先把 Java 代码编译成字节码,也就是把 .java 类型的文件编译成 .class 类型的文件。这个过程的大致执行流程:Java 源代码 -> 词法分析器 -> 语法分析器 -> 语义分析器 -> 字符码生成器 -> 最终生成字节码,其中任何一个节点执行失败就会造成编译失败;
- 把 class 文件放置到 Java 虚拟机,这个虚拟机通常指的是 Oracle 官方自带的 Hotspot JVM;
- Java 虚拟机使用类加载器(Class Loader)装载 class 文件;
- 类加载完成之后,会进行字节码效验,字节码效验通过之后 JVM 解释器会把字节码翻译成机器码交由操作系统执行。但不是所有代码都是解释执行的,JVM 对此做了优化,比如,以 Hotspot 虚拟机来说,它本身提供了 JIT(Just In Time)也就是我们通常所说的动态编译器,它能够在运行时将热点代码编译为机器码,这个时候字节码就变成了编译执行。
Java 程序执行流程图如下:
Java 虚拟机判定热点代码的方式有两种:
- 基于采样的热点判定
主要是虚拟机会周期性的检查各个线程的栈顶,若某个或某些方法经常出现在栈顶,那这个方法就是“热点方法”。这种判定方式的优点是实现简单;缺点是很难精确一个方法的热度,容易受到线程阻塞或外界因素的影响。
- 基于计数器的热点判定
主要就是虚拟机给每一个方法甚至代码块建立了一个计数器,统计方法的执行次数,超过一定的阀值则标记为此方法为热点方法。
Hotspot 虚拟机使用的基于计数器的热点探测方法。它使用了两类计数器:方法调用计数器和回边计数器,当到达一定的阀值是就会触发 JIT 编译。
方法调用计数器:在 client 模式下的阀值是 1500 次,Server 是 10000 次,可以通过虚拟机参数: -XX:CompileThreshold=N
对其进行设置。但是JVM还存在热度衰减,时间段内调用方法的次数较少,计数器就减小。
回边计数器:主要统计的是方法中循环体代码执行的次数。
由上面的知识我们可以看出,要想做到对 Java 了如之中,必须要好好学习 Java 虚拟机,那除了 Java 虚拟机外,还有哪些知识是面试必考,也是 Java 工程师必须掌握的知识呢?
1. Java 基础中的核心内容字符串和字符串常量池的深入理解、Array 的操作和排序算法、深克隆和浅克隆、各种 IO 操作、反射和动态代理(JDK 自身动态代理和 CGLIB)等。
2. 集合集合和 String 是编程中最常用的数据类型,关于集合的知识也是面试备考的内容,它包含:链表(LinkedList)、TreeSet、栈(Stack)、队列(双端、阻塞、非阻塞队列、延迟队列)、HashMap、TreeMap 等,它们的使用和底层存储数据结构都是热门的面试内容。
3. 多线程多线程使用和线程安全的知识也是必考的面试题目,它包括:死锁、6 种线程池的使用与差异、ThreadLocal、synchronized、Lock、JUC(java.util.concurrent包)、CAS(Compare and Swap)、ABA 问题等。
4. 热门框架Spring、Spring MVC、MyBatis、SpringBoot
5. 分布式编程消息队列(RabbitMQ、Kafka)、Dubbo、Zookeeper、SpringCloud 等。
6. 数据库MySQL 常用引擎的掌握、MySQL 前缀索引、回表查询、数据存储结构、最左匹配原则、MySQL 的问题分析和排除方案、MySQL 读写分离的实现原理以及 MySQL 的常见优化方案等。Redis 的使用场景、缓存雪崩和缓存穿透的解决方案、Redis 过期淘汰策略和主从复制的实现方案等。
7. Java 虚拟机虚拟机的组成、垃圾回收算法、各种垃圾回收器的区别、Java 虚拟机分析工具的掌握、垃圾回收器的常用调优参数等。
8. 其他常用算法的掌握、设计模式的理解、网络知识和常见 Linux 命令的掌握等。
值得庆幸的是以上所有内容都包含在本课程中,接下来就让我们一起学习,一起构建 Java 的认知体系吧!
点击收下这份《Java 面试全解析》
相关面试题 1. Java 语言都有哪些特点?答:Java 语言包含以下特点。
- 面向对象,程序容易理解、开发简单、方便;
- 跨平台,可运行在不同服务器类型上,比如:Linux、Windows、Mac 等;
- 执行性能好,运行效率高;
- 提供大量的 API 扩展,语言强大;
- 有多线程支持,增加了响应和实时交互的能力;
- 安全性好,自带验证机制,确保程序的可靠性和安全性。
答:要了解 Java 跨平台实现原理之前,必须先要了解 Java 的执行过程,Java 的执行过程如下:
Java 执行流程:Java 源代码(.java)-> 编译 -> Java 字节码(.class) ->通过 JVM(Java 虚拟机)运行 Java 程序。每种类型的服务器都会运行一个 JVM,Java 程序只需要生成 JVM 可以执行的代码即可,JVM 底层屏蔽了不同服务器类型之间的差异,从而可以在不同类型的服务器上运行一套 Java 程序。
3. JDK、JRE、JVM 有哪些区别?答:了解了 JDK、JRE、JVM 的定义也就明白了它们之间的区别,如下所述。
- JDK:Java Development Kit(Java 开发工具包)的简称,提供了 Java 的开发环境和运行环境;
- JRE:Java Runtime Environment(Java 运行环境)的简称,为 Java 的运行提供了所需环境;
- JVM:Java Virtual Machine(Java虚拟机)的简称,是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的,简单来说就是所有的 Java 程序都是运行在 JVM(Java 虚拟机)上的。
总体来说,JDK 提供了一整套的 Java 运行和开发环境,通常使用对象为 Java 的开发者,当然 JDK 也包含了 JRE;而 JRE 为 Java 运行的最小运行单元,一般安装在 Java 服务器上,所以 JDK 和 JRE 可以从用途上进行理解和区分。JVM 不同于 JDK 和 JRE,JVM 是 Java 程序运行的载体,Java 程序只有通过 JVM 才能正常的运行。
4. Java 中如何获取明天此刻的时间?答:JDK 8 之前使用 Calendar.add()
方法获取,代码如下:
Calendar calendar = Calendar.getInstance();calendar.add(Calendar.DATE, 1);System.out.println(calendar.getTime());
JDK 8 有两种获取明天时间的方法。
方法一,使用 LocalDateTime.plusDays()
方法获取,代码如下:
LocalDateTime today = LocalDateTime.now();LocalDateTime tomorrow = today.plusDays(1);System.out.println(tomorrow);
方法二,使用 LocalDateTime.minusDays()
方法获取,代码如下:
LocalDateTime today = LocalDateTime.now();LocalDateTime tomorrow = today.minusDays(-1);System.out.println(tomorrow);
minusDays()
方法为当前时间减去 n 天,传负值就相当于当前时间加 n 天。
答:Java 中跳出多重嵌套循环的两种方式。
- 方法一:定义一个标号,使用 break 加标号的方式
- 方法二:使用全局变量终止循环
方法一,示例代码:
myfor:for (int i = 0; i < 100; i++) { for (int j = 0; j < 100; j++) { System.out.println("J:" + j); if (j == 10) { // 跳出多重循环 break myfor; } }}
方法二,示例代码:
boolean flag = true;for (int i = 0; i < 100 && flag; i++) { for (int j = 0; j < 100; j++) { System.out.println("J:" + j); if (j == 10) { // 跳出多重循环 flag = false; break; } }}
6. char 变量能不能存贮一个中文汉字?为什么?
答:char 变量可以存贮一个汉字,因为 Java 中使用的默认编码是 Unicode ,一个 char 类型占 2 个字节(16 byte),所以放一个中文是没问题的。
7. Java 中会存在内存泄漏吗?请简单描述一下。答:一个不再被程序使用的对象或变量一直被占据在内存中就造成了内存泄漏。
Java 中的内存泄漏的常见情景如下:
- 长生命周期对象持有短生命的引用,比如,缓存系统,我们加载了一个对象放在缓存中,然后一直不使用这个缓存,由于缓存的对象一直被缓存引用得不到释放,就造成了内存泄漏;
- 各种连接未调用关闭方法,比如,数据库 Connection 连接,未显性地关闭,就会造成内存泄漏;
- 内部类持有外部类,如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露;
- 改变哈希值,当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄露。
点击可查《Java 面试全解析》还会讲什么
此外,我们为本课程付费读者创建了《Java 面试全解析》的微信交流群,方便读者更有针对性地讨论课程相关问题,以及分享Java 技术和面试心得。
入群请添加「GitChat 小助手泰勒」:识别下方二维码,或者添加 GitChatty5,注明「Java 面试」。
温馨提示:需购买才可入群哦,加小助手后需要截图已购买页面来发给小助手验证一下~
Java 基础数据按类型可以分为四大类:布尔型、整数型、浮点型、字符型,这四大类包含 8 种基础数据类型。
- 布尔型:boolean
- 整数型:byte、short、int、long
- 浮点型:float、double
- 字符型:char
八种基础类型取值如下:
数据类型代表含义默认值取值包装类boolean布尔型false0(false) 到 1(true)Booleanbyte字节型(byte)0-128 到 127Bytechar字符型'\u0000'(空)'\u0000' 到 '\uFFFF'Charactershort短整数型(short)0-2^15 到 2^15-1Shortint整数型0-2^31 到 2^31-1Integerlong长整数型0L-2^63 到 2^63-1Longfloat单浮点型0.0f1.4e-45 到 3.4e+38Floatdouble双浮点型0.0d4.9e-324 到 1.798e+308Double除 char 的包装类 Character 和 int 的包装类 Integer 之外,其他基础数据类型的包装类只需要首字母大写即可。包装类的作用和特点,本文下半部分详细讲解。
我们可以在代码中,查看某种类型的取值范围,代码如下:
public static void main(String[] args) { // Byte 取值:-128 ~ 127 System.out.println(String.format("Byte 取值:%d ~ %d", Byte.MIN_VALUE, Byte.MAX_VALUE)); // Int 取值:-2147483648 ~ 2147483647 System.out.println(String.format("Int 取值:%d ~ %d", Integer.MIN_VALUE, Integer.MAX_VALUE));}
包装类型
我们知道 8 种基本数据类型都有其对应的包装类,因为 Java 的设计思想是万物既对象,有很多时候我们需要以对象的形式操作某项功能,比如说获取哈希值(hashCode)或获取类(getClass)等。
那包装类特性有哪些?
1. 功能丰富
包装类本质上是一个对象,对象就包含有属性和方法,比如 hashCode、getClass 、max、min 等。
2. 可定义泛型类型参数
包装类可以定义泛型,而基础类型不行。
比如使用 Integer 定义泛型,代码:
List list = new ArrayList();
如果使用 int 定义就会报错,代码:
List list = new ArrayList(); // 编译器代码报错
3. 序列化
因为包装类都实现了 Serializable 接口,所以包装类天然支持序列化和反序列化。比如 Integer 的类图如下:
4. 类型转换
包装类提供了类型转换的方法,可以很方便的实现类型之间的转换,比如 Integer 类型转换代码:
String age = "18";int ageInt = Integer.parseInt(age) + 2;// 输出结果:20System.out.println(ageInt);
5. 高频区间的数据缓存
此特性为包装类很重要的用途之一,用于高频区间的数据缓存,以 Integer 为例来说,在数值区间为 -128~127 时,会直接复用已有对象,在这区间之外的数字才会在堆上产生。
我们使用 == 对 Integer 进行验证,代码如下:
public static void main(String[] args) { // Integer 高频区缓存范围 -128~127 Integer num1 = 127; Integer num2 = 127; // Integer 取值 127 == 结果为 true(值127 num1==num2 => true) System.out.println("值127 num1==num2 => " + (num1 == num2)); Integer num3 = 128; Integer num4 = 128; // Integer 取值 128 == 结果为 false(值128 num3==num4 => false) System.out.println("值128 num3==num4 => " + (num3 == num4)); }
从上面的代码很明显可以看出,Integer 为 127 时复用了已有对象,当值为 128 时,重新在堆上生成了新对象。
为什么会产生高频区域数据缓存?我们查看源码就能发现“线索”,源码版本 JDK8,源码如下:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i true) System.out.println("值127 num1==num2 => " + (num1 == num2)); Integer num3 = 128; Integer num4 = 128; // Integer 取值 128 == 结果为 false(值128 num3==num4 => false) System.out.println("值128 num3==num4 => " + (num3 == num4)); // Integer 取值 128 equals 结果为 true(值128 num3.equals(num4) => true) System.out.println("值128 num3.equals(num4) => " + num3.equals(num4));}
Float 和 Double 不会有缓存,其他包装类都有缓存。
Integer 是唯一一个可以修改缓存范围的包装类,在 VM optons 加入参数:
-XX:AutoBoxCacheMax=666 即修改缓存最大值为 666
。
示例代码如下:
public static void main(String[] args) { Integer num1 = -128; Integer num2 = -128; System.out.println("值为-128 => " + (num1 == num2)); Integer num3 = 666; Integer num4 = 666; System.out.println("值为666 => " + (num3 == num4)); Integer num5 = 667; Integer num6 = 667; System.out.println("值为667 => " + (num5 == num6));}
执行结果如下:
值为-128 => true值为666 => true值为667 => false
由此可见将 Integer 最大缓存修改为 666 之后,667 不会被缓存,而 -128~666 之间的数都被缓存了。
先收下这份《Java 面试全解析》
相关面试题 1. 以下 Integer 代码输出的结果是?Integer age = 10;Integer age2 = 10;Integer age3 = 133;Integer age4 = 133;System.out.println((age == age2) + "," + (age3 == age4));
答:true,false
Double num = 10d;Double num2 = 10d;Double num3 = 133d;Double num4 = 133d;System.out.println((num == num2) + "," + (num3 == num4));
答:false,false
int i = 100;Integer j = new Integer(100);System.out.println(i == j);System.out.println(j.equals(i));
A:true,trueB:true,falseC:false,trueD:false,false
答:A
题目分析:有人认为这和 Integer 高速缓存有关系,但你发现把值改为 10000 结果也是 true,true
,这是因为 Integer 和 int 比较时,会自动拆箱为 int 相当于两个 int 比较,值一定是 true,true
。
final int iMax = Integer.MAX_VALUE;System.out.println(iMax + 1);
A:2147483648B:-2147483648C:程序报错D:以上都不是
答:B
题目解析:这是因为整数在内存中使用的是补码的形式表示,最高位是符号位 0 表示正数,1 表示负数,当执行 +1 时,最高位就变成了 1,结果就成了 -2147483648。
5. 以下程序执行的结果是?Set set = new HashSet();for (short i = 0; i < 5; i++) { set.add(i); set.remove(i - 1);}System.out.println(set.size());
A:1B:0C:5D:以上都不是
答:5
题目解析:Short 类型 -1 之后转换成了 Int 类型,remove() 的时候在集合中找不到 Int 类型的数据,所以就没有删除任何元素,执行的结果就是 5。
6.short s=2;s=s+1;
会报错吗?short s=2;s+=1;
会报错吗?
答:s=s+1 会报错,s+=1 不会报错,因为 s=s+1 会导致 short 类型升级为 int 类型,所以会报错,而 s+=1 还是原来的 short 类型,所以不会报错。
7.float f=3.4;
会报错吗?为什么?
答:会报错,因为值 3.4 是 double 类型,float 类型级别小于 double 类型,所以会报错。如下图所示:
答:需要包装类的原因有两个。
① Java 的设计思想是万物既对象,包装类体现了面向对象的设计理念;② 包装类包含了很多属性和方法,比基础数据类型功能多,比如提供的获取哈希值(hashCode)或获取类(getClass)的方法等。
9. 基础类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗?答:不正确,只有包装类高频区域数据才有缓存。
10. 包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗?答:不正确,基础数据类型的包装类只有 Double 和 Float 没有高频区域的缓存。
11. 包装类的值比较要使用什么方法?答:包装类因为有高频区域数据缓存,所以推荐使用 equals() 方法进行值比较。
12. 包装类有哪些功能?答:包装类提供的功能有以下几个。
- 功能丰富:包装类包含了有 hashCode、getClass 、max、min 等方法;
- 可定义泛型类型参数:例如
List list = new ArrayList();
; - 序列化:包装类实现了 Serializable 接口,所以包装类天然支持序列化和反序列化;
- 类型转换:包装类提供了方便的类型转换方法,比如 Integer 的 parseInt() 方法;
- 高频区域数据缓存:高频区域可使用已有的缓存对象。
详见正文“包装类型”部分内容。
13. 泛型可以为基础类型吗?为什么?答:泛型不能使用基础数据类型。泛型在 JVM(Java虚拟机)编译的时候会类型檫除,比如代码 List list
在 JVM 编译的时候会转换为 List list
,因为泛型是在 JDK 5 时提供的,而 JVM 的类型檫除是为了兼容以前代码的一个折中方案,类型檫除之后就变成了 Object,而 Object 不能存储基础数据类型,但可以使用基础数据类型对应的包装类,所以像 List list
这样的代码是不被允许的,编译器阶段会检查报错,而 List list
是被允许的。
答:我们知道正确的使用包装类,可以提供程序的执行效率,可以使用已有的缓存,一般情况下选择基本数据类型还是包装类原则有以下几个。
① 所有 POJO 类属性必须使用包装类;② RPC 方法返回值和参数必须使用包装类;③ 所有局部变量推荐使用基础数据类型。
15. 基础数据类型在 JVM 中一定存储在栈中吗?为什么?答:基础数据类型不一定存储在栈中,因为基础类型的存储位置取决于声明的作用域,来看具体的解释。
- 当基础数据类型为局部变量的时候,比如在方法中声明的变量,则存放在方法栈中的,当方法结束系统会释放方法栈,在该方法中的变量也会随着栈的销毁而结束,这也是局部变量只能在方法中使用的原因;
- 当基础数据类型为全局变量的时候,比如类中的声明的变量,则存储在堆上,因为全局变量不会随着某个方法的执行结束而销毁。
Integer i1 = new Integer(10);Integer i2 = new Integer(10);Integer i3 = Integer.valueOf(10);Integer i4 = Integer.valueOf(10);System.out.println(i1 == i2);System.out.println(i2 == i3);System.out.println(i3 == i4);
A:false,false,falseB:false,false,trueC:false,true,trueD:true,false,false
答:B
题目解析:new Integer(10) 每次都会创建一个新对象,Integer.valueOf(10) 则会使用缓存池中的对象。
17. 3*0.1==0.3 返回值是多少?答:返回值为:false。
题目解析:因为有些浮点数不能完全精确的表示出来,如下代码:
System.out.println(3 * 0.1);
返回的结果是:0.30000000000000004。
点击可查《Java 面试全解析》还会讲什么
此外,我们为本课程付费读者创建了《Java 面试全解析》的微信交流群,方便读者更有针对性地讨论课程相关问题,以及分享Java 技术和面试心得。
入群请添加「GitChat 小助手泰勒」:识别下方二维码,或者添加 GitChatty5,注明「Java 面试」。
温馨提示:需购买才可入群哦,加小助手后需要截图已购买页面来发给小助手验证一下~
阅读全文: http://gitbook.cn/gitchat/column/5d493b4dcb702a087ef935d9