「开发者成长」5 个刁钻的Java String 面试题
这篇来看看关于 Java String 类的 5 道面试题,这五道题,我自己在面试过程中亲身经历过几道题目,本篇就带你了解这些题的答案为什么是这样。
1.判定定义为String类型的st1和st2是否相等,为什么
输出结果:
第一行:true
第二行:true
分析:
先看第一个打印语句,在Java中==这个符号是比较运算符,它可以基本数据类型和引用数据类型是否相等,如果是基本数据类型,==比较的是值是否相等,如果是引用数据类型,==比较的是两个对象的内存地址是否相等。
字符串不属于8中基本数据类型,字符串对象属于引用数据类型,在上面把“abc”同时赋值给了st1和st2两个字符串对象,指向的都是同一个地址,所以第一个打印语句中的==比较输出结果是 true
然后我们看第二个打印语句中的equals的比较,我们知道,equals是Object这个父类的方法,在String类中重写了这个equals方法。在JDK API 1.6文档中找到String类下的equals方法,点击进去可以看大这么一句话“将此字符串与指定的对象比较。当且仅当该参数不为null,并且是与此对象表示相同字符序列的String 对象时,结果才为 true。” 注意这个相同字符序列,在后面介绍的比较两个数组,列表,字典是否相等,都是这个逻辑去写代码实现。
由于st1和st2的值都是“abc”,两者指向同一个对象,当前字符序列相同,所以第二行打印结果也为true。 下面我们来画一个内存图来表示上面的代码,看起来更加有说服力。
内存过程大致如下:
1)运行先编译,然后当前类Demo2_String.class文件加载进入内存的方法区2)第二步,main方法压入栈内存3)常量池创建一个“abc”对象,产生一个内存地址4)然后把“abc”内存地址赋值给main方法里的成员变量st1,这个时候st1根据内存地址,指向了常量池中的“abc”。5)前面一篇提到,常量池有这个特点,如果发现已经存在,就不在创建重复的对象6)运行到代码 Stringst2 =”abc”, 由于常量池存在“abc”,所以不会再创建,直接把“abc”内存地址赋值给了st27)最后st1和st2都指向了内存中同一个地址,所以两者是完全相同的。
2. 下面这句话在内存中创建了几个对象
答案是:在内存中创建两个对象,一个在堆内存,一个在常量池,堆内存对象是常量池对象的一个拷贝副本。
分析:
我们下面直接来一个内存图。
当我们看到了new这个关键字,就要想到,new出来的对象都是存储在堆内存。然后我们来解释堆中对象为什么是常量池的对象的拷贝副本。“abc”属于字符串,字符串属于常量,所以应该在常量池中创建,所以第一个创建的对象就是在常量池里的“abc”。
第二个对象在堆内存为啥是一个拷贝的副本呢,这个就需要在JDK API 1.6找到String(String original)这个构造方法的注释:初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。所以,答案就出来了,两个对象。
3、判定以下定义为String类型的st1和st2是否相等
答案:false 和 true由于有前面两道提内存分析的经验和理论,所以,我能快速得出上面的答案。
==比较的st1和st2对象的内存地址,由于st1指向的是堆内存的地址,st2看到“abc”已经在常量池存在,就不会再新建,所以st2指向了常量池的内存地址,所以==判断结果输出false,两者不相等。
第二个equals比较,比较是两个字符串序列是否相等,由于就一个“abc”,所以完全相等。
内存图如下
4. 判定以下定义为String类型的st1和st2是否相等
答案是:true 和 true
分析:
“a”,”b”,”c”三个本来就是字符串常量,进行+符号拼接之后变成了“abc”,“abc”本身就是字符串常量(Java中有常量优化机制),所以常量池立马会创建一个“abc”的字符串常量对象,在进行st2=”abc”,这个时候,常量池存在“abc”,所以不再创建。所以,不管比较内存地址还是比较字符串序列,都相等。
5、判断以下st2和st3是否相等
答案:false 和 true
分析:
上面的答案第一个是false,第二个是true,第二个是true我们很好理解,因为比较一个是“abc”,另外一个是拼接得到的“abc”,所以equals比较,这个是输出true,我们很好理解。
那么第一个判断为什么是false,我们很疑惑。同样,下面我们用API的注释说明和内存图来解释这个为什么不相等。
首先,打开JDK API 1.6中String的介绍,找到下面图片这句话。
关键点就在红圈这句话,我们知道任何数据和字符串进行加号(+)运算,最终得到是一个拼接的新的字符串。+ 号操作到底做了什么?推荐看下。
上面注释说明了这个拼接的原理是由StringBuilder或者StringBuffer类和里面的append方法实现拼接,然后调用 toString() 把拼接的对象转换成字符串对象,最后把得到字符串对象的地址赋值给变量。
结合这个理解,我们下面画一个内存图来分析。
大致内存过程
1)常量池创建“ab”对象,并赋值给st1,所以st1指向了“ab”2)常量池创建“abc”对象,并赋值给st2,所以st2指向了“abc”3)由于这里走的+的拼接方法,所以第三步是使用StringBuffer类的append方法,得到了“abc”,这个时候内存0x0011表示的是一个StringBuffer对象,注意不是String对象。4)调用了Object的toString方法把StringBuffer对象装换成了String对象。5)把String对象(0x0022)赋值给st3 所以,st3和st2进行==判断结果是不相等,因为两个对象内存地址不同。
总结:
这篇的面试题,完全就是要求掌握JDK API中一些注解和原理,以及内存图分析,才能得到正确的结果,我承认是画内存图让我理解了答案为什么是这样。
画完内存图之后,得到答案,你确实会发现很有趣,最后才会有原来如此的感叹。
105道Java面试题,认真思考对你面试很有价值
1、什么是面向对象?
2、JDK JRE JVM
3、==和equals比较
4、hashCode与equals
5、final
6、String、StringBuffer、StringBuilder
7、重载和重写的区别
8、接口和抽象类的区别
9、List和Set的区别
10、ArrayList和LinkedList区别
11、HashMap和HashTable有什么区别?其底层实现是什么?
12、ConcurrentHashMap原理,jdk7和jdk8版本的区别?
13、什么是字节码?采用字节码的好处是什么?
14、Java中的异常体系
15、Java类加载器
16、双亲委托模型
17、GC如何判断对象可以被回收
选择Java基础里的其中一道解答
JDK JRE JVM
JDK:
Java Develpment Kit java 开发工具
JRE:
Java Runtime Environment java运行时环境
JVM:
java Virtual Machine java 虚拟机
1、线程的生命周期?线程有几种状态
2、sleep()、wait()、join()、yield()的区别
3、对线程安全的理解
4、Thread、Runable的区别
5、对守护线程的理解
6、ThreadLocal的原理和使用场景
7、ThreadLocal内存泄露原因,如何避免
8、并发、并行、串行的区别
9、并发的三大特性
10、volatile
11、为什么用线程池?解释下线程池参数?
12、简述线程池处理流程
13、线程池中阻塞队列的作用?为什么是先添加列队而不是先创建最大线程?
14、线程池中线程复用原理
选择Java线程与并发里的其中一道解答
volatile
(1)保证被volatile修饰的共享变量对所有线程总是可见的,也就是当一个线程修改了一个被volatile修饰共享变量的值,新值总是可以被其他线程立即得知。
如果线程2改变了stop的值,线程1一定会停止吗?不一定。当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。
(2)禁止指令重排序优化。
write方法里的1和2做了重排序,线程1先对flag赋值为true,随后执行到线程2,ret直接计算出结果,再到线程1,这时候a才赋值为2,很明显迟了一步。
但是用volatile修饰之后就变得不一样了
第一:使用volatile关键字会强制将修改的值立即写入主存;
第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
第三:由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主 存读取。
inc++; 其实是两个步骤,先加加,然后再赋值。不是原子性操作,所以volatile不能保证线程安全。
1、如何实现一个IOC容器
2、spring是什么?
3、谈谈你对AOP的理解
4、谈谈你对IOC的理解
5、BeanFactory和ApplicationContext有什么区别?
6、描述一下Spring Bean的生命周期?
7、解释下Spring支持的几种bean的作用域。
8、Spring框架中的单例Bean是线程安全的么?
9、Spring 框架中都用到了哪些设计模式?
10、Spring事务的实现方式和原理以及隔离级别?
11、spring事务传播机制
12、spring事务什么时候会失效?
13、什么是bean的自动装配,有哪些方式?
选择spring里的其中一道解答
谈谈你对AOP的理解
系统是由许多不同的组件所组成的,每一个组件各负责一块特定功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件。
当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从 上到下的关系,但并不适合定义从左到右的关系。例如日志功能。
日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。
在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP:将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。AOP可以对某个对象或某些对象的功能进行增强,比如对象中的方法进行增强,可以在执行某个方法之前额外的做一些事情,在某个方法执行之后额外的做一些事情
1、Spring Boot、Spring MVC 和 Spring 有什么区别
2、SpringMVC 工作流程
3、Spring MVC的主要组件?
4、Spring Boot 自动配置原理?
5、如何理解 Spring Boot 中的 Starter
6、什么是嵌入式服务器?为什么要使用嵌入式服务器?
7、mybatis的优缺点
8、MyBatis 与Hibernate 有哪些不同?
9、#{}和${}的区别是什么?
10、简述 Mybatis 的插件运行原理,如何编写一个插件。
选择springmvc、springBoot、Mybatis里的其中一道解答
SpringMVC 工作流程
1)用户发送请求至前端控制器 DispatcherServlet。
2)DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
3)处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器及处理器(如果有则生成)一并返回给 DispatcherServlet。
4)DispatcherServlet 调用 HandlerAdapter 处理器适配器。
5)HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)
6)Controller 执行完成返回 ModelAndView。
7)HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet。8)DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器。
9)ViewReslover 解析后返回具体 View。
10)DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。
11)DispatcherServlet 响应用户。
1、索引的基本原理
2、mysql聚簇和非聚簇索引的区别
3、mysql索引的数据结构,各自优劣
4、索引设计的原则?
5、什么是最左前缀原则?什么是最左匹配原则
6、锁的类型有哪些
7、InnoDB存储引擎的锁的算法
8、关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?
9、事务的基本特性和隔离级别
10、ACID靠什么保证的?
11、什么是MVCC
12、分表后非sharding_key的查询怎么处理,分表后的排序?
13、mysql主从同步原理
14、简述MyISAM和InnoDB的区别
15、简述mysql中索引类型及对数据库的性能的影响
16、mysql执行计划怎么看
选择MySQL里的其中一道解答
索引的基本原理
索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。
索引的原理:就是把无序的数据变成有序的查询
(1) 把创建了索引的列的内容进行排序
(2)对排序结果生成倒排表
(3)在倒排表内容上拼上数据地址链
(4)在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据
1、RDB 和 AOF 机制
2、Redis的过期键的删除策略
3、Redis线程模型、单线程快的原因
4、简述Redis事务实现
5、redis集群方案
6、redis 主从复制的核心原理
7、缓存雪崩、缓存穿透、缓存击穿
选择Redis里的其中一道解答
Redis的过期键的删除策略
Redis是key-value数据库,我们可以设置Redis中缓存的key的过期时间。Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理。
惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的 指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)
Redis中同时使用了惰性过期和定期过期两种过期策略。
1、CAP理论,BASE理论
2、负载均衡算法、类型
3、分布式架构下,Session 共享有什么方案
4、简述你对RPC、RMI的理解
5、分布式id生成方案
6、分布式锁解决方案
7、分布式事务解决方案
8、如何实现接口的幂等性
9、简述ZAB 协议
10、简述zk的命名服务、配置管理、集群管理
11、讲下Zookeeper watch机制
12、zk和eureka的区别
13、Spring Cloud和Dubbo的区别
14、什么是Hystrix?简述实现机制
15、springcloud核心组件及其作用
16、Dubbo 的整体架构设计及分层
选择分布式与微服务里的其中一道解答
Spring Cloud和Dubbo的区别
底层协议:springcloud基于http协议,dubbo基于Tcp协议,决定了dubbo的性能相对会比较好
注册中心:Spring Cloud 使用的 eureka ,dubbo推荐使用zookeeper
模型定义:dubbo 将一个接口定义为一个服务,SpringCloud 则是将一个应用定义为一个服务
SpringCloud是一个生态,而Dubbo是SpringCloud生态中关于服务调用一种解决方案(服务治理)
1、简述RabbitMQ的架构设计
2、RabbitMQ如何确保消息发送 ? 消息接收?
3、RabbitMQ事务消息
4、RabbitMQ死信队列、延时队列
5、RabbitMQ镜像队列机制
6、简述kafka架构设计
7、kafka怎么处理消息顺序、重复发送、重复消费、消息丢失
8、Kafka在什么情况下会出现消息丢失及解决方案?
9、Kafka是pull?push?优劣势分析
10、Kafka中zk的作用
11、简述kafka的rebalance机制
12、Kafka的性能好在什么地方
选择分布式与微服务里的其中一道解答
简述kafka架构设计
Consumer Group:消费者组,消费者组内每个消费者负责消费不同分区的数据,提高消费能力。逻 辑上的一个订阅者。
Topic:可以理解为一个队列,Topic 将消息分类,生产者和消费者面向的是同一个 Topic。
Partition:为了实现扩展性,提高并发能力,一个Topic 以多个Partition的方式分布到多个 Broker上,每个 Partition 是一个 有序的队列。一个 Topic 的每个Partition都有若干个副本(Replica),一个Leader 和若干个 Follower。生产者发送数据的对象,以及消费者消费数据的对象,都是 Leader。Follower负责实时从 Leader 中同步数据,保持和 Leader 数据的同步。Leader 发生故障时,某个Follower 还会成为新的 Leader。
Offset:消费者消费的位置信息,监控数据消费到什么位置,当消费者挂掉再重新恢复的时候,可以从 消费位置继续消费。
Zookeeper:Kafka 集群能够正常工作,需要依赖于 Zookeeper,Zookeeper 帮助 Kafka 存储和管理 集群信息。
这105道Java面试题的答案已经整理成了PDF文档,如下图:
获取方式:关注小编+转发文章+私信【105】获取105道Java面试题文档
希望能帮助到你在面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
重要的事情说三遍,转发+转发+转发,一定要记得点赞转发哦!!!
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。