0

0

Java面试题大全 —推荐几道面试题让你轻松拿下offer

php是最好的语言

php是最好的语言

发布时间:2018-08-02 10:54:37

|

2406人浏览过

|

来源于php中文网

原创

前言

只有光头才能变强

之前在刷博客的时候,发现一些写得比较好的博客都会默默收藏起来。最近在查阅补漏,有的知识点比较重要的,但是在之前的博客中还没有写到,于是趁着闲整理一下(推荐:java面试题大全)。

文本的知识点:

  • Integer常量池

  • TCP拆包粘包

  • select、poll、epoll简单区别

    立即学习Java免费学习笔记(深入)”;

  • jdk1.6以后对Synchronize锁优化

  • Java内存模型

本文力求简单讲清每个知识点,希望大家看完能有所收获

一、神奇的Integer

前阵子在群上看有人在讨论关于Integer的true或者false问题,我本以为我已经懂了这方面的知识点了。但还是做错了,后来去请教了一下朋友。朋友又给我发了另一张图:

1.png

后来发现这是出自《深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)》中的10.3.2小节中~

public class Main_1 {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;
        System.out.println(c == d);
        System.out.println(e == f);
        System.out.println(c == (a + b));
        System.out.println(c.equals(a + b));
        System.out.println(g == (a + b));
        System.out.println(g.equals(a + b));
        System.out.println(g.equals(a + h));
    }

}

你们可以先思考一下再往下翻看答案,看看能不能做对。

1.1解题思路

在解这道题之前,相信很多人都已经知道了,在Java中会有一个Integer缓存池,缓存的大小是:-128~127

1.png答案是:

  • true

  • false

  • true

  • true

  • true

  • false

  • true

简单解释一下:

  • 使用==的情况:

    • 如果比较Integer变量,默认比较的是地址值

    • Java的Integer维护了从-128~127的缓存池

    • 如果比较的某一边有操作表达式(例如a+b),那么比较的是具体数值

  • 使用equals()的情况:

    • 无论是Integer还是Long中的equals()默认比较的是数值

    • Long的equals()方法,JDK的默认实现:会判断是否是Long类型

  • 注意自动拆箱,自动装箱问题。

1.png

反编译一下看看:

import java.io.PrintStream;

public class Main_1 {
    public static void main(String[] paramArrayOfString) {
        Integer localInteger1 = Integer.valueOf(1);
        Integer localInteger2 = Integer.valueOf(2);
        Integer localInteger3 = Integer.valueOf(3);
        Integer localInteger4 = Integer.valueOf(3);
        Integer localInteger5 = Integer.valueOf(321);
        Integer localInteger6 = Integer.valueOf(321);
        Long localLong = Long.valueOf(3L);

        // 缓存池
        System.out.println(localInteger3 == localInteger4);
        
        // 超出缓存池范围
        System.out.println(localInteger5 == localInteger6);
        
        // 存在a+b数值表达式,比较的是数值
        System.out.println(localInteger3.intValue() == localInteger1.intValue() + localInteger2.intValue());

        // equals比较的是数值
        System.out.println(localInteger3.equals(Integer.valueOf(localInteger1.intValue() + localInteger2.intValue())));
        // 存在a+b数值表达式,比较的是数值
        System.out.println(localLong.longValue() == localInteger1.intValue() + localInteger2.intValue());
        // Long的equals()先判断传递进来的是不是Long类型,而a+b自动装箱的是Integer类型
        System.out.println(localLong.equals(Integer.valueOf(localInteger1.intValue() + localInteger2.intValue())));

        // ... 最后一句在这里漏掉了,大家应该可以推断出来
    }
}

我使用的反编译工具是jd-gui,如果还没有试过反编译的同学可以下载来玩玩:

  • https://github.com/java-decompiler/jd-gui/releases

二、Synchronize锁优化手段有哪些

多线程文章回顾:

  • ThreadLocal就是这么简单

  • 多线程三分钟就可以入个门了!

  • Thread源码剖析

  • 多线程基础必要知识点!看了学习多线程事半功倍

  • Java锁机制了解一下

  • AQS简简单单过一遍

  • Lock锁子类了解一下

  • 线程池你真不来了解一下吗?

  • 多线程之死锁就是这么简单

  • Java多线程打辅助的三个小伙子

之前在写多线程文章的时候,简单说了一下synchronized锁在jdk1.6以后会有各种的优化:适应自旋锁,锁消除,锁粗化,轻量级锁,偏向锁。

1.png

本以为这些优化是非常难以理解的东西,其实不然~~~简单了解一下还是很好理解的。

2.1适应自旋锁

锁竞争是kernal mode下的,会经过user mode(用户态)到kernal mode(内核态) 的切换,是比较花时间的。

自旋锁出现的原因是人们发现大多数时候锁的占用只会持续很短的时间,甚至低于切换到kernal mode所花的时间,所以在进入kernal mode前让线程等待有限的时间,如果在此时间内能够获取到锁就避免了很多无谓的时间,若不能则再进入kernal mode竞争锁。

在JDK 1.6中引入了自适应的自旋锁,说明自旋的时间不固定,要不要自旋变得越来越聪明

自旋锁在JDK1.4.2中就已经引入,只不过默认是关闭的,可以使用-XX:+UseSpinning参数来开启,在JDK1.6中就已经改为默认开启了。

2.2锁消除

如果JVM明显检测到某段代码是线程安全的(言外之意:无锁也是安全的),JVM会安全地原有的锁消除掉!

比如说:

    public void vectorTest(){
        Vector vector = new Vector();
        for(int i = 0 ; i < 10 ; i++){
            vector.add(i + "");
        }

        System.out.println(vector);
    }

Vector是默认加锁的,但JVM如果发现vector变量仅仅在vectorTest()方法中使用,那该vector是线程安全的。JVM会把vector内部加的锁去除,这个优化就叫做:锁消除。

2.3锁粗化

默认情况下,总是推荐将同步块的作用范围限制得尽量小

但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,频繁地进行互斥同步操作也会导致不必要的性能损耗

JVM会将加锁的范围扩展(粗化),这就叫做锁粗化。

2.4轻量级锁

轻量级锁能提升程序同步性能的依据是“对于绝大部分的锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。

  • 如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销

  • 但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁会比传统的重量级锁更慢。

简单来说:如果发现同步周期内都是不存在竞争,JVM会使用CAS操作来替代操作系统互斥量。这个优化就被叫做轻量级锁。

2.5偏向锁

偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做了

偏向锁可以提高带有同步但无竞争的程序性能。它同样是一个带有效益权衡(Trade Off)性质的优化,也就是说,它并不一定总是对程序运行有利,如果程序中大多数的锁总是被多个不同的线程访问,那偏向模式就是多余的。在具体问题具体分析的前提下,有时候使用参数-XX:-UseBiasedLocking来禁止偏向锁优化反而可以提升性能。

2.6简单总结各种锁优化

  • 自适应偏向锁:自旋时间不固定

  • 锁消除:如果发现代码是线程安全的,将锁去掉

  • 锁粗化:加锁范围过小(重复加锁),将加锁的范围扩展

  • 轻量级锁:在无竞争的情况下使用CAS操作去消除同步使用的互斥量

  • 偏向锁:在无竞争环境下,把整个同步都消除,CAS也不做。

参考资料:

  • https://blog.csdn.net/chenssy/article/details/54883355

三、TCP粘包,拆包

这是在看wangjingxin大佬面经的时候看到的面试题,之前对TCP粘包,拆包没什么概念,于是就简单去了解一下。

3.1什么是拆包粘包?为什么会出现?

在进行Java NIO学习时,可能会发现:如果客户端连续不断的向服务端发送数据包时,服务端接收的数据会出现两个数据包粘在一起的情况。

TCP的首部格式:

1.png

小微助手
小微助手

微信推出的一款专注于提升桌面效率的助手型AI工具

下载
  • TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界

  • 从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段

基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。

一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包

1.png

接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包

1.png

拆包和粘包的问题导致接收端在处理的时候会非常困难(因为无法区分一个完整的数据包)

3.2解决拆包和粘包

分包机制一般有两个通用的解决方法:

  • 1,特殊字符控制

  • 2,在包头首都添加数据包的长度

如果使用netty的话,就有专门的编码器和解码器解决拆包和粘包问题了。

tips:UDP没有粘包问题,但是有丢包和乱序。不完整的包是不会有的,收到的都是完全正确的包。传送的数据单位协议是UDP报文或用户数据报,发送的时候既不合并,也不拆分。

四、select、poll、epoll简单区别

NIO回顾:

  • JDK10都发布了,nio你了解多少?

在Linux下它是这样子实现I/O复用模型的:

调用select/poll/epoll其中一个函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。

这几个函数是有些区别的,可能有的面试官会问到这三个函数究竟有什么区别:

区别如下图:

1.png

两句话总结:

  • select和poll都需要轮询每个文件描述符,epoll基于事件驱动,不用轮询

  • select和poll每次都需要拷贝文件描述符,epoll不用

  • select最大连接数受限,epoll和poll最大连接数不受限

tips:epoll在内核中的实现,用红黑树管理事件块

4.1通俗例子

现在3y在公司里边实习,写完的代码需要给测试测一遍。

select/poll情况:

  • 开发在写代码,此时测试挨个问所有开发者,你写好程序了没有?要测试吗?

epoll情况:

  • 开发写完代码了,告诉测试:“我写好代码了,你去测测,功能是XXX”。于是测试高高兴兴去找bug了。

其他通俗描述[1]:

一个酒吧服务员(一个线程),前面趴了一群醉汉,突然一个吼一声“倒酒”(事件),你小跑过去给他倒一杯,然后随他去吧,突然又一个要倒酒,你又过去倒上,就这样一个服务员服务好多人,有时没人喝酒,服务员处于空闲状态,可以干点别的玩玩手机。至于epoll与select,poll的区别在于后两者的场景中醉汉不说话,你要挨个问要不要酒,没时间玩手机了。io多路复用大概就是指这几个醉汉共用一个服务员。

其他通俗描述[2]:

简单举个例子(可能也不是很形象)select/poll饭店服务员(内核)告诉饭店老板(用户程序):”现在有客人结账“但是这个服务员没人明确告诉老板,哪几桌的客人结帐。老板得自儿一个一个桌子去问:请问是你要结帐?epoll饭店服务员(内核)告诉饭店老板(用户程序):”1,2,5号客人结账“老板就可以直接去1,2,5号桌收钱了

五、Java内存模型

JVM博文回顾:

  • JVM如何从入门到放弃的?

之前在写JVM的时候,还一度把JVM内存结构与Java内存模型给搞混了~~~还好有热心的网友给我指出来。

JVM内存结构:

1.png

Java内存模型:

1.png

操作变量时的规则:

  • Java内存模型规定了所有的变量都存储在主内存

  • 线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝

  • 线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量

工作内存同步回主内存实现是通过以下的8种操作来完成:

  • lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态。

  • unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

  • read(读取):作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用

  • load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。

  • use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。

  • assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。

  • store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。

  • write(写入):作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中。

Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这3个特征来建立的

保证原子性的操作:

  • read、load、assign、use、store和write

  • synchronized锁

保证有序性(重排序导致无序)的操作:

  • volatile

  • synchronized锁

保证可见性:

  • volatile

  • synchronized锁

  • final

在上面也说了,有序性可以通过volatile和synchronized锁来保证,但我们一般写程序的时候不会总是关注代码的有序性的。其实,我们Java内部中有一个原则,叫做先行发生原则(happens-before)

  • “先行发生”(happens-before)原则可以通过:几条规则一揽子地解决并发环境下两个操作之间是否可能存在冲突的所有问题

  • 有了这些规则,并且我们的操作是在这些规则定义的范围之内。我们就可以确保,A操作肯定比B操作先发生(不会出现重排序的问题)

“先行发生”(happens-before)原则有下面这么几条:

  • 程序次序规则(Program Order Rule):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。

  • 管程锁定规则(Monitor  Lock  Rule):一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而“后面”是指时间上的先后顺序。

  • volatile变量规则(Volatile Variable Rule):对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”同样是指时间上的先后顺序。线程启动规则(Thread  Start  Rule):Thread对象的start()方法先行发生于此线程的每一个动作。

  • 线程终止规则(Thread Termination Rule):线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。

  • 线程中断规则(Thread Interruption Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。

  • 对象终结规则(Finalizer  Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。

  • 传递性(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。

相关文章:

分享java中面试题汇总

10个经典的 Java main 方法面试题

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

9

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

105

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

13

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

106

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

5

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

6

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

111

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

31

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

89

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.7万人学习

Java 教程
Java 教程

共578课时 | 51.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号