1.判定定义为String类型的st1和st2是否相等,为什么

package string;public class Demo2_String {public static void main(String[] args) {String st1 = "abc";String st2 = "abc";System.out.println(st1 == st2);System.out.println(st1.equals(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”内存地址赋值给了st2

7)最后st1和st2都指向了内存中同一个地址,所以两者是完全相同的。

2. 下面这句话在内存中创建了几个对象

String st1 = new String(“abc”);

答案是:在内存中创建两个对象,一个在堆内存,一个在常量池,堆内存对象是常量池对象的一个拷贝副本。

分析:

我们下面直接来一个内存图。

当我们看到了new这个关键字,就要想到,new出来的对象都是存储在堆内存。然后我们来解释堆中对象为什么是常量池的对象的拷贝副本。

“abc”属于字符串,字符串属于常量,所以应该在常量池中创建,所以第一个创建的对象就是在常量池里的“abc”。

第二个对象在堆内存为啥是一个拷贝的副本呢,这个就需要在JDK API 1.6找到String(String original)这个构造方法的注释:初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。

所以,答案就出来了,两个对象。

3、判定以下定义为String类型的st1和st2是否相等 

package string;
public class Demo2_String {public static void main(String[] args) {String st1 = new String("abc");String st2 = "abc";System.out.println(st1 == st2);System.out.println(st1.equals(st2));}
}

答案:false 和 true

由于有前面两道提内存分析的经验和理论,所以,我能快速得出上面的答案。

==比较的st1和st2对象的内存地址,由于st1指向的是堆内存的地址,st2看到“abc”已经在常量池存在,就不会再新建,所以st2指向了常量池的内存地址,所以==判断结果输出false,两者不相等。

第二个equals比较,比较是两个字符串序列是否相等,由于就一个“abc”,所以完全相等。

内存图如下

4. 判定以下定义为String类型的st1和st2是否相等

package string;public class Demo2_String {public static void main(String[] args) {String st1 = "a" + "b" + "c";String st2 = "abc";System.out.println(st1 == st2);System.out.println(st1.equals(st2));}
}

答案是:true 和 true

分析:

“a”,”b”,”c”三个本来就是字符串常量,进行+符号拼接之后变成了“abc”,“abc”本身就是字符串常量(Java中有常量优化机制),所以常量池立马会创建一个“abc”的字符串常量对象,在进行st2=”abc”,这个时候,常量池存在“abc”,所以不再创建。所以,不管比较内存地址还是比较字符串序列,都相等。

5、判断以下st2和st3是否相等

package string;public class Demo2_String {public static void main(String[] args) {String st1 = "ab";String st2 = "abc";String st3 = st1 + "c";System.out.println(st2 == st3);System.out.println(st2.equals(st3));}
}

答案:false 和 true

分析:

上面的答案第一个是false,第二个是true,第二个是true我们很好理解,因为比较一个是“abc”,另外一个是拼接得到的“abc”,所以equals比较,这个是输出true,我们很好理解。

那么第一个判断为什么是false,我们很疑惑。同样,下面我们用API的注释说明和内存图来解释这个为什么不相等。

首先,打开JDK API 1.6中String的介绍,找到下面图片这句话。

关键点就在红圈这句话,我们知道任何数据和字符串进行加号(+)运算,最终得到是一个拼接的新的字符串。+ 号操作到底做了什么?推荐看下。关注微信公众号:Java技术栈,在后台回复:java,可以获取我整理的 N 篇最新 Java 教程,都是干货。

上面注释说明了这个拼接的原理是由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中一些注解和原理,以及内存图分析,才能得到正确的结果,我承认是画内存图让我理解了答案为什么是这样。

画完内存图之后,得到答案,你确实会发现很有趣,最后才会有原来如此的感叹。

String相关知识点相关推荐

  1. js 闭包及其相关知识点理解

    本文结合个人学习及实践,对闭包及相关知识点进行总结记录,欢迎读者提出任何不足之处 一.js变量 二.作用域(scope) 三.[[scope]] 和 scope chain 四.作用域(scope)和 ...

  2. Redis:相关知识点纵观

    这篇文章先简单的介绍一下redis有什么相关知识点,然后再从接下去的一些文章对一些重要的知识点进行总结. 一.Redis 是什么 Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存 ...

  3. 并发与多线程相关知识点梳理

    文章目录 并发和并行的概念 如何保证线程安全 1. 数据单线程内可见 2. 只读对象 3. 线程安全类 4. 同步与锁机制 什么是锁 线程同步 引用类型 ThreadLocal LeetCode 相关 ...

  4. ArrayList源码解析与相关知识点

    ArrayList源码解析于相关知识点(超级详细) 文章目录 ArrayList源码解析于相关知识点(超级详细) ArrayList的继承关系 Serializable标记接口 Cloneable标记 ...

  5. 多线程相关知识点总结

    多线程相关知识点总结 1. 线程的概念: 在早期的操作系统中并没有线程的概念,进程是拥有资源和独立运行的最小单位,也是程序执行的最小单位.任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的 ...

  6. Redis 相关知识点

    Redis 相关知识点 概述 为什么要用缓存 为什么用redis 用redis缓存了哪些东西 单线程redis为什么这么快 redis的数据类型和使用场景 redis 的过期策略都有哪些?内存淘汰机制 ...

  7. redis相关知识点讲解,redis面试题

    redis相关知识点讲解,redis面试题 1. redis基本知识点 1.1 什么是redis? 1.2 redis的key的设计 1.3 redis的value数据类型有哪些? 1.3.1 str ...

  8. JAVA基础5——与String相关的系列(1)

    与String相关的系列 String, 是JAVA中常见的一个引用类型,且其具有一定的特殊性. String类型被设置为final型,即不可继承,也就不可修改其中的实现. String可以改变吗 S ...

  9. 卫星轨道推演计算相关知识点总结(含欧拉角、旋转矩阵、及各坐标系转化等)

    来源:轨道机动算法的C++实现_shirro123的专栏-CSDN博客 卫星轨道推演计算相关基础知识点总结 一.卫星的运动特性             二.卫星的空间坐标系               ...

  10. 水下机器人_相关知识点

    485转232 SP3485的管脚及功能: Pin1.RO    接收器输出 Pin2.RE 接收器输出使能(低电平有效) Pin3.DE 驱动器输出使能(高电平有效) Pin4.DI 驱动器输入 P ...

最新文章

  1. linux ldap客户端工具,OpenLDAP 客户端安装部署
  2. 程序员公开上班摸鱼神器!有了它,老板都不好意思打扰你!
  3. 投资学习网课笔记(part7)--基金第七课
  4. Ubuntu中配置NFS服务
  5. web developer tips (1):创建、管理、应用样式表的强大工具
  6. Thread 1: signal SIGABRT
  7. 於岳 linux实用教程(第2版),Linux实用教程 第2版 教学课件 ppt 作者 於岳 编著 06...
  8. 新加坡推出人工智能计划AI.SG 迎战人工智能和数据科学关键难题
  9. 大数据可视化平台的价值有哪些
  10. Namespace名称空间
  11. Mujoco模型学习记录
  12. 【软件需求工程与建模】13组组队项目选题介绍及项目计划安排
  13. 添加MSN客服代码,可显示MSN在线和不在线,自动打开MSN聊天窗口
  14. 什么是上行带宽,什么是下行带宽
  15. 分布式事务中的时间戳详解
  16. springboot admin自定义监控里的info信息
  17. java算法优化_Java学习笔记---Java简单的代码算法优化(例)
  18. haproxy MMM WordPress
  19. 俄罗斯立法机关将于下周开始审核加密货币法律草案
  20. 烤仔的朋友们丨详解数字美元白皮书:双层架构、通证化、汇款通道

热门文章

  1. Zebra打印机,中文转ZPL指令的.net实现,替换FNTHEX32.DLL
  2. android6.0原生brower_六款顶级Android手机原生浏览器决战
  3. 如何进行航拍全景摄影(上)
  4. go 语言调用 python 把.dat格式数据转换为.mat
  5. 复合高斯求积matlab代码,谁有复何求积公式和高斯求积公式在matlab中实现的代码...
  6. 全自动过滤器:全自动自清洗过滤器对给排水总结的经验
  7. 在w ndoWS7中屏幕保护程序,怎么设置Windows 7屏幕保护时间
  8. WPS---EXCEL(八)---互换两列数据
  9. android 邮箱注册功能,手机邮箱怎么注册登录(安卓手机邮箱设置教程)
  10. 推荐几款免费的MacOS/MacBook pro/MacBook air读取NTFS格式磁盘软件(完全免费)