今天给大家带来的是在面试中经常被问到的一道题:

无论在Java还是Android中,String是一个很常见的类,但是大家真的很了解吗,我这里有几个题:

1.

String str1 = "abc";

String str2 = new String("abc");

这两种创建String对象的方法有什么不同?

2.

String s = "a" + "b" + "c" + "d";

这里面一共创建了多少对象?

这两道题昨天给笔者搞得是一脸懵逼,后来一听这是一道很经典的面试题,就赶快查阅各种资料,现在已经解决了。

在解决这两个题之前,我们先来明确几个知识点,相信把这几个知识点弄完之后再回头看这两个题,就很简单了:

1.引用在栈内存中存储,对象在堆内存中存储。

2.String对象不可变。

3.String创建对象的形式:

4.字符串常量池的意义:

5.intern()方法使用。

我们首先来开第一个:

引用在栈内存中存储,对象在堆内存中存储。

这个是我粗略画的一张图,这张图可能不是很准确,但是我只想表达一个意思,我们的栈内存,存放的是我们对象的引用和我们基本数据类型的值。而堆内存中存放的是我们的对象。就是这么简单。

为什么说String对象不可变

这里我们用一下大佬的图:

如果用代码表示上面的图,那就是:

String s = "abcd";

s = s + "el";

如果没有上面这张图,大家可能会觉得我们只是给s对象后面加了一个el,这不还是原来的s吗?不,我们说的String对象不可变就是这个意思,当我们给s再加上el时候,新的字符串abcdel被存放到了一个新的内存中。已经不是原来的内存了。所以说String对象不可变,如果变了,那就已经变成了一个新的对象。

那说到这里大家可能会返回去看我写的第二个问题:按你的说法这不就7个对象吗?abcd各占一个,每次+到一起都要重新生成对象,一共生成了7个对象。话是没错,但是我想说这道题说多解,等我们讲完了下面这两个知识点,这道题就完全解开了。

String创建对象的形式:

正如我们上面看到的,String有两种创建对象的形式:

1.字面量形式:

String str = "asd";

2.标准的new形式:

String str = new String("asd");

字符串常量池的意义:

字符串常量池,又称为字符串在字面量池。大家不要他想象的多么高深额,其实说白了他就是一块内存,它里面存放的是我们的字符串的引用。

大家可能疑问这个东西有什么意义:假如我们要创建一个字符串,"a" + "b" + "c" + ....+ 我们+了一万次,那么按照上面的说法,我们是不是为了创建一个很长的字符串,创建了很多的对象。这样不但有的字符串被重复的创建了,而且占用了很多不必要的内存,代价有点大。

我们的JVM为了减少字符串的重复创建,维护了一个特殊的内存:就是这个字符串常量池。

在这个字符串常量池中,存放着我们字符串对象的引用。下面我们根据字符串创建对象的两种形式来说明一下常量池是如何存放String对象引用的:

1.通过字面量创建String对象:

我们举个例子,String str = "abc";我们通过字面量形式创建一个值为"abc"的对象,首先我们判断常量池中是否存在一个引用,这个引用的值也是"abc",如果有这个值,那么我们就从常量池中拿到这个引用,返回给str。

如果没有,那么我们就创建这个对象,然后把str这个引用值放到常量池中。

在这里我们要明确几个点了:

1首先常量池存放的不是字符串对象,而是字符串对象的引用。

2.无论常量池中是否存在这个对象的引用,最后结果都会存放有这个引用。

3.该方法可能不会创建新的对象。

2.通过new创建String对象。

这里其实只有一句话,无论常量池中是否存在相同值的引用,至少创建一个对象。因为不管别的,new这个语法就一定会创建一个新的对象,然后我们要看构造方法中的字符串,如果常量池中存在与该字符串相同值的引用,那么就不会创建新的对象,反之会创建对象之后,在常量池中存放这个引用。

这样看起来我们的常量池的意义就很明确了,减少重复创建String对象,从而减少不必要的内存消耗。

如果要说他的弊端的话,应该就是牺牲了CPU的计算时间来换取空间吧,因为查找是否有相同内容的引用是CPU耗时计算,但是与前者占用内存相比,这个还是算不了什么的吧(笔者自己观点,没有官方支持哈哈)。

intern()方法使用

最后我们来看一下这个intern()方法,这个方法其实理解为查看常量池中是否存在对应内容的引用。如果有他会返回常量池中的引用,如果没有则会将当前String的引用放入常量池。

我们举几个例子对比下就好:

public static void main(String[] args) {

String str1 = "gfzy";

String str2 = str1.intern();

System.out.println(str1 == str2);

}

他的结果是true。很简单,我们首先通过字面量形式创建了一个“gfzy”对象,此时常量池中没有相同内容引用,所以常量池存放str1的引用。

然后str2为str1的.intern()方法,现在常量池中存在“gfzy”这个内容的引用,所以我们返回这个引用,也就是str1,所以str1和str2指向同一个引用。

public static void main(String[] args) {

String str1 = new String("gfzy");

String str2 = "gfzy";

System.out.println(str1 == str2);

}

这个结果为false,首先我们看到str1是new了一个对象,所以他肯定是在堆内存中一块新的内存,而构造方法中的“gfzy”,首先在常量池中会拿到他的引用,然后返回这个引用。

str2直接拿到了常量池中的引用,所以一个是堆内存新创建的,一个是原来常量池中的引用,两者指向不是一个内存,所以是false。

而如果是这样呢:

public static void main(String[] args) {

String str1 = new String("gfzy").intern();

String str2 = "gfzy";

System.out.println(str1 == str2);

}

这个结果为true。在原来的基础上只是添加了一个inter方法,在new String("gfzy");时候,现在常量池中已经有了这个引用。而现在intern,我们会拿到常量池中的引用,所以str1为常量池中的引用,str2和上面一样,所以返回true。

现在这几个问题都解决完了,我们再返回头看之前的两个问题,第一个问题就很简单了,而我们刚才也说过了。

第二个是看常量池中是否已经存在了对应的引用,如果没有,那么是"a","b","ab","c","abc","d","abcd"七个对象,如果常量池中存在引用,那么只创建了一个“abcd”(这个是编译器优化后的结果,其实笔者这里也是有点懵逼,个人感觉应该是3个额,希望这个问题有读者多多留言,帮我解答一下这个问题)。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

java中字符 的含义 有什么作用_Java中字符串常见题之String相关讲解相关推荐

  1. java中字符流和字节流的区别_java中字节流和字符流有哪些区别

    java中字节流和字符流的区别有:1.定义不同:2.结尾不同:3.处理方式不同:4.缓冲区不同:5.编码方式不同.字节流默认不使用缓冲区,而字符流使用缓冲区.字节流采用ASCII编码,字符流采用uni ...

  2. java中输出时 什么作用_JAVA中输入和输出处理(Java I/O)重点总结

    文件-使用File类操作文件: 什么是文件?  文件可认为是相关记录或放在一起的数据的集合. 文件一般存储在哪里?  储存在存储设备里. Java程序如何访问文件?  Java API:java.io ...

  3. java finally的作用_java中finally关键字的特点和作用是什么

    java中finally关键字的特点和作用是什么 发布时间:2020-09-08 11:12:01 来源:亿速云 阅读:114 作者:小新 小编给大家分享一下java中finally关键字的特点和作用 ...

  4. java throws的作用_Java中throws..throw的使用与说明

    throws语句 throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常.对大多数Exception子类来说,Java 编译器会强迫你声明在一个成员函数中抛出的异常的类型.如果异常的 ...

  5. java中static作用_java中static作用详解

    static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以修饰静态static代码块,但是Java语言中没有全局变量的概念. 被static ...

  6. java的import和python的import对比_Java中的Import和Pacakge作用生动详解(感觉python中的import作用差不多)...

    转自:http://apps.hi.baidu.com/share/detail/6510541 有些人写了一阵子Java,可是对於Java的package跟import还是不太了解很多人以為原始码. ...

  7. java中包的概念及作用_Java中包的概念和使用实战

    一点睛 1 package的声明方法: packagepackage名称[.package名称2.package名称3]; 2 包的导入方法如下: importpackage包名称.类名称 3如果一个 ...

  8. java中静态变量的作用_Java中static变量作用和用法详解

    static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static ...

  9. java域的控制修饰符可分为_Java中的类和方法的修饰符

    java 中的类和方法的修饰符Java程序在定义类时,除了使用class关键字标识之外,还可以在class之前增加若干类的修饰符来修饰限定所定义的类的特性.类的修饰符分为访问控制符和非访问控制符两大类 ...

最新文章

  1. Redis学习资料整理
  2. html点击旋转180,关于点击三角丝滑旋转180度css3 jq处理方法
  3. js 中的五种继承方法
  4. python hello world重复_从hello world开始学Python
  5. SAP Spartacus的发布方式以及语义化版本管理机制
  6. 用计算机算算术平方根顺序是ON然后是什么,第2课时用计算器求一个正数的算术平方根.ppt...
  7. 唯一索引与主键索引的比较
  8. idea 关联jdk源码_[项目源码]ERP进销存系统
  9. 第4章 Selenium2-java WebDriver API (三)
  10. MySQL完全自学手册
  11. Android应用逆向——最好用的两个无源码调试器
  12. UE4 Spline
  13. java练习题-猜数字游戏
  14. 项目组织与团队管理——社会惰化
  15. 【No JSON object could be decoded】问题解决
  16. node.js - 收藏集
  17. 一颗病毒大小的新型分子或可帮助人类找到暗物质
  18. java编程用什么笔记本_程序员都用什么牌子的笔记本,你知道吗?
  19. JS-0-100之间的随机整数
  20. 如何主持计算机教师座谈会,计算机科学与技术学院举办青年教师教学座谈会

热门文章

  1. php搜索所有路线,php包含文件路径查找规则
  2. 使用PyCharm运行第一行python代码
  3. android 标题栏 fragment,切换Fragment 并更换标题栏
  4. python元组和列表的联系_Python | 一文看懂Python列表、元组和字符串操作
  5. 简述流水线基本工作原理 计算机,自动化专业计算机技术基础作业题(50题)
  6. [高级光照]球谐光照
  7. 将现有MFC应用程序迁移到BCGControlBar VC界面库中
  8. 利用StringUtils可以避免空指针问题
  9. curl 模拟表单提交
  10. JSF 与 HTML 标签的联系