在之前的文章中,已经发布了常见的面试题,这里我了点时间整理了一下对应的解答,由于个人能力有限,不一定完全到位,如果有解答的不合理的地方还请指点,在此谢过。

本文主要描述字符串的知识点,下面先看下面一段代码:

public static void main(String[] args)  {  String s1 = new String("abc");  String s2 = "abc";  String s3 = new String("abc");  String s4 = "abc";  String s5 = "a"+"bc";  String s6 = new String("a")+"bc";  System.out.println(s1 == s2);//false  System.out.println(s1.equals(s2));//true  System.out.println(s1 == s3);//false  System.out.println(s2 == s3);//false  System.out.println(s2 == s4);//true  System.out.println(s2 == s5);//true  System.out.println(s2 == s6);//false  System.out.println(s1 == s1.intern());//false  System.out.println(s2 == s1.intern());//true  System.out.println(s2 == s2.intern());//true  System.out.println(s1.intern() == s3.intern());//true  }  

上面的题目涉及到的知识点有equals和 == 的区别,jvm的内存模型,intern方法的使用,字符串String常量类。那我们就先把以上涉及的知识点描述一遍之后再来分析答案。

Java中== 和equals的区别是什么?

在实际项目中,我们常常会碰到判断两个相等的情况。在java语言中,== 和equals 都是有判断两者相等的意思,不过,使用场景上有些不同。其主要区别如下:

== 是运算符,equals是Object的基本方法,也就是说每个java类都有这个方法。在java语言中,运算符是不允许重载的,而方法是可以重写的,所以我们可以定义自己的equals的方法,这就意味着equals方法在每个类中有可能判断相等的方式不一样。

== 运算符判断相等的方法是:如果是基本类型的话,则判断的是基本类型的值是否相等;如果是引用类型的话,则判断引用的地址是否相等。而equals方法,我们知道如果不重写的话,那么其底层的实现其实就是 == (参考object的)。

//object 类
public boolean equals(Object obj) {  return (this == obj);  }  

但是如果重写之后的话,我们就要根据类的重写去看下具体的实现了,在这里,我们看下Integer和String的判断思路。

//stringpublic boolean equals(Object anObject) {if (this == anObject) {//先判断是否相等return true;}if (anObject instanceof String) {//依次对比每个字符String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}//Integerpublic boolean equals(Object obj) {//判断是否是整型if (obj instanceof Integer) {return value == ((Integer)obj).intValue();//使用==判断}return false;}

从上面的源码中可以看到,实际上java需要在object中添加equals方法,主要是因为==这个无法重写,那如果我们想要判断是否相等的话,可能就么办法了,所以java干脆写个方法,方便大家自己实现。

jvm的内存模型

Jvm的内存模型是后续jvm中的重点内容,由于刚刚的题目涉及到这块的知识,在这里,先简单介绍下jvm (1.7版本)分为:方法区、堆、栈、本地方法栈、程序计数器。而到了1.8版本,稍微做了些调整,使用了元数据区替换了方法区,并且元数据区并不在jvm的控制范围内,其使用的是本地内存,那么jvm中就只有堆、栈、本地方法栈、程序计数器。在java中,为了避免字符串常量分配的性能消耗,java在初始化字符串的时候,会为字符串放置到字符串常量池中。而字符串常量池在不同的版本实际上存放的位置也是不同的,在1.6版本时放在方法区,在1.7版本又移到了堆中,而到了1.8版本被移动到元空间。Jvm的知识后续还会重点介绍,在这里,主要是说明字符串在jvm中存储位置,方便理解上面的题目。

字符串的intern方法

该方法的作用是:如果某个字符串没有存入常量池,那现在常量池中创建,然后将常量池中的字符串返回。如果已经存在,那就直接将该字符串返回

该方法的作用主要在于:1)节省内存,如果常量中存在的话,那就只有一个对象了。 2)如果大家都用intern的话,可以直接使用==来进行判断是否相同,而不需要使用equals,因为equals的效率是低下的。

字符串是一定不能修改的么?

对于这个问题,我们知道String这个类使用的是final char数组保存数据,如下:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];//指向的地址不能改变}

该数组的地址使用final修饰,那么意味着地址实际上是不能修改的,但是并不意味着里面的值是不能修改的,所以,如果我们能够获取到value的值,是能够将其修改的。但是现在value是private修饰的,并且没有提供获取value的方法,再者String是一个final类,也无法继承。那是不是就无法获取到真正的值了。显然不是的,如果我们使用反射的话,是可以无视private属性的,并且获取到value的值,如果我们将获取到的value的值进行修改,那也就意味着我们能够修改相应的值。

Ok,有了这些基本的知识之后,我们可以对上面的代码进行解答了。回到代码本身,我们依次画出每个存入的位置,知道位置之后,就知道==是否相等了。

上面是画出的每个对象指向的地址,这里常量池不指定是在哪,因为上面介绍了不同版本存入的位置也不相同。在这里有几个需要说明的是:

  1. 使用intern返回一定是字符串常量池的位置
  2. 使用new出来的字符串,一定会在堆中存在字符串,并且指向的是堆中的位置
  3. +运算符对于字符串来说,需要注意的是,在初始化赋值的时候,如果常量字符串+常量字符串(s5 = “a”+”bc”),那么返回的是存入常量池中计算结果(“abc”)。如果是存在其他的需要找地址计算值的话(s6 = new String(“a”) +”bc”),那么只会返回存在堆的计算结果,并不会将结果存入到常量池中。

知道上面的知识点之后,对解决上面的题目应该是ok的。

字符串除了上面的知识点之外,我们还有几个相关的知识点也在本文中说明。

说明一下StringBuilder、StringBuffer和String的区别?

这个是面试可能会出现的问题,虽然现在已经比较少使用StringBuilder或者StringBuffer了,但是我们还是应该要知道一下这两个类出现的作用是什么?

其实核心的问题在于String是不可变,那字符串的拼接就变得不是那么友好,String在做字符串拼接的时候,需要重新申请内存存入新的字符串。基于这样的一个因素,StringBuilder和StringBuffer出现了,其主要的作用是在字符串拼接的效率上。一般来说字符串的拼接速度是StringBuilder>StringBuffer>String。而StringBuilder和StingBuffer的区别在于StringBuilder是线程不安全的,StringBuffer是线程安全的。下面我们看下其append方法,底层都是基于父类实现的:

public AbstractStringBuilder append(String str) {//都是基于父类实现的if (str == null)return appendNull();int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}

而StringBuilder和StringBuffer的区别在于:方法上是否加锁

//StringBuilderpublic StringBuilder append(String str) {super.append(str);return this;}//StringBufferpublic synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;}

Java中hashCode 和equals方法的区别?

我们知道hashCode 和equals方法都是父类Object中的基本方法。HashCode 方法定义的初衷是为了求解一个类的hashCode值,而equals方法的定义初衷是为了判断两个对象是否内容一致。一般情况下,我们会认为equals相等的两个对象,其hashcode值也相等。而hashcode相等的两个对象,equals不一定相等。在《effect java》中有一条重要的规则是:如果重写了equals方法,就一定要重写hashcode方法。规则很简单,原因在于如果我们只重写了其中的一个,可能会导致在某些java的基本类中判断两个对象是否相等的时候出错,尤其是在hashMap中存入的对象作为key的时候,该对象一定要重写两个方法。因为hashMap在判断key是否相同的时候,是先判断hashcode后再判断equals的。

本文的内容就这么多,如果你觉得对你的学习和面试有些帮助,帮忙点个赞。谢谢。

想要了解更多java内容(包含大厂面试题和题解)可以关注公众号,也可以在公众号留言,帮忙内推阿里、腾讯等互联网大厂哈

Java 基础篇--字符串相关推荐

  1. Java基础篇——字符串处理(String,StringBuffer,StringBuild)

    提前说明本次的文章很长但是很有用,有耐心看完的必定不是凡人,必定会有很大的收获.本人在总结的过程中也收获了很多的知识,希望我们可以一起学习.写下这篇文章完全是抱着可以帮助到他人的态度. 虽然要写出很高 ...

  2. qstring 字符相同 不相等_我的编程手册 -- Java 基础篇·字符串 String

    在程序开发中,我们最常用的就是字符串,我们经常声明或初始化各类字符串. 针对String 类型的字符串,a=null,说明其不指向内存区任何一个字符串,但是a=""不同,其指向内存 ...

  3. 菜鸟学习笔记:Java基础篇6(数组、字符串)

    菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...

  4. Java基础篇4——数组

    Java基础篇4--数组 1.数组的概念 当需要在Java程序中记录单个数据内容时,则声明一个变量即可 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数 组即可,一维数组本质上就是 ...

  5. 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)

    菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...

  6. 菜鸟学习笔记:Java基础篇5(抽象类与接口、回调函数、内部类)

    菜鸟学习笔记:Java面向对象篇下 抽象类 接口 回调函数 内部类 成员内部类 匿名内部类 抽象类 通过前面知识的学习,抽象类这个概念应该不难理解,但比较容易和后面要说的接口混淆,而且在面试中也比较爱 ...

  7. 菜鸟学习笔记:Java基础篇4(面向对象三大特征)

    菜鸟学习笔记:Java面向对象篇中 继承 概念 方法重写(override) Object类 Super关键字 组合 final关键字补充 封装 访问控制符 多态 继承 概念 继续上一篇的例子: #m ...

  8. 菜鸟学习笔记:Java基础篇3(面向对象思想、程序执行过程内存分析、面向对象重要概念)

    菜鸟学习笔记:Java面向对象篇上 Java面向对象的思想 Java程序执行过程内存分析 Java垃圾回收机制 构造方法 方法重载(overload) static关键字 this关键字 Java面向 ...

  9. 菜鸟学习笔记:Java基础篇2(变量、运算符、流程控制语句、方法)

    菜鸟学习笔记:Java基础篇2 变量 基本概念 变量作用域 final关键字 运算符 算术运算符 比较运算符 逻辑运算符 位运算符 赋值运算符 条件运算符 运算符优先级 Java三种流程控制语句 顺序 ...

  10. Android面试题Java基础篇

    Android面试题Java基础篇,由本人整理汇总,后续将继续推出系列篇,如果喜欢请持续关注和推荐,更多精彩内容可以关注微信公众号(Android高级编程):android-tech 系列文章目录: ...

最新文章

  1. Headfirst JSP 01 (概述)
  2. 重组完成,京东金融走出京东:猛兽的进化
  3. VS2015 提示 无法启动 IIS Express Web 服务器
  4. 学习笔记(12):Python网络编程并发编程-解决粘包问题-简单版本
  5. 在ARM开发板的嵌入式linux系统上运行的QT程序,必须得要在linux里用QT编吗
  6. Python介绍、发展史、安装、变量、注释、输入
  7. 链表的简单操作-----删除,添加,查找(Xcode)
  8. JavaScript循环结构(1)
  9. 【彻底解决】django migrate (mysql.W002) 【专治强迫症】
  10. ** is not in the sudoers file. This incident will be reported. 给某个用户开放sudo权限。
  11. edius隐藏快捷键_EDIUS7 Pro快捷键使用方法及全部快捷键功能
  12. Matlab 数据类型
  13. 怎么将excel转换pdf在线转换
  14. Dennis Gabor与全息摄影
  15. 微信小程序图片组件,ios不显示,安卓正常
  16. 理解async与await
  17. 【问题】[已修改但尚未保存]/bin/bash: wq:未找到命令 Shell 已返回127
  18. 【原】Java学习笔记025 - 内部类
  19. 基于java家庭理财记账系统计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  20. 蓝牙的ATT协议(属性协议)和GATT协议

热门文章

  1. Win7 系统还原被管理员禁用
  2. burpsuite https 社区版_BurpSuit添加CA证书拦截HTTPS通信
  3. 计算机表格的名次怎么弄,excel表格函数名次怎么做
  4. 华为云ManageOne北向对接之基本名词概念(一)
  5. 基于学术研究下载NOAA气象雷达资料的详细步骤
  6. 靠问卷调查做副业,在家月入过万:聪明的人,从不挣辛苦钱!
  7. 深度学习图像处理目标检测图像分割计算机视觉 10--通用场景图像分割
  8. 一些简单的css,html,js笔记分享给大家,希望能够帮助到大家
  9. Win10 Build 18237发布:登录屏幕启用毛玻璃特效
  10. python爬取头条付费专栏视频_Python3从零开始爬取今日头条的新闻【五、解析头条视频真实播放地址并自动下载】...