Java中String不是基本类型,但是有些时候和基本类型差不多,如String b = "tao" ; 可以对变量直接赋值,而不用 new 一个对象(当然也可以用 new)。所以String这个类型值得好好研究下。

Java中的变量和基本类型的值存放于栈内存,而new出来的对象本身存放于堆内存,指向对象的引用还是存放在栈内存。例如如下的代码:

int  i=1;

String s =  new  String( "Hello World" );

变量i和s以及1存放在栈内存,而s指向的对象”Hello World”存放于堆内存。

栈内存的一个特点是数据共享,这样设计是为了减小内存消耗,前面定义了i=1,i和1都在栈内存内,如果再定义一个j=1,此时将j放入栈内存,然后查找栈内存中是否有1,如果有则j指向1。如果再给j赋值2,则在栈内存中查找是否有2,如果没有就在栈内存中放一个2,然后j指向2。也就是如果常量在栈内存中,就将变量指向该常量,如果没有就在该栈内存增加一个该常量,并将变量指向该常量。

如果j++,这时指向的变量并不会改变,而是在栈内寻找新的常量(比原来的常量大1),如果栈内存有则指向它,如果没有就在栈内存中加入此常量并将j指向它。这种基本类型之间比较大小和我们逻辑上判断大小是一致的。如定义i和j是都赋值1,则i==j结果为true。==用于判断两个变量指向的地址是否一样。i==j就是判断i指向的1和j指向的1是同一个吗?当然是了。对于直接赋值的字符串常量(如String s=“Hello World”;中的Hello World)也是存放在栈内存中,而new出来的字符串对象(即String对象)是存放在堆内存中。如果定义String s=“Hello World”和String w=“Hello World”,s==w吗?肯定是true,因为他们指向的是同一个Hello World。

堆内存没有数据共享的特点,前面定义的String s =  new  String( "Hello World" );后,变量s在栈内存内,Hello World 这个String对象在堆内存内。如果定义String w = new  String( "Hello World" );,则会在堆内存创建一个新的String对象,变量w存放在栈内存,w指向这个新的String对象。堆内存中不同对象(指同一类型的不同对象)的比较如果用==则结果肯定都是false,比如s==w?当然不等,s和w指向堆内存中不同的String对象。如果判断两个String对象相等呢?用equals方法。

说了这么多只是说了这道题的铺垫知识,还没进入主题,下面分析这道题。 MESSAGE 成员变量及其指向的字符串常量肯定都是在栈内存里的,变量 a 运算完也是指向一个字符串“ taobao ”啊?是不是同一个呢?这涉及到编译器优化问题。对于字符串常量的相加,在编译时直接将字符串合并,而不是等到运行时再合并。也就是说

String a =  "tao" + "bao" ;和String a =  "taobao" ;编译出的字节码是一样的。所以等到运行时,根据上面说的栈内存是数据共享原则,a和MESSAGE指向的是同一个字符串。而对于后面的(b+c)又是什么情况呢?b+c只能等到运行时才能判定是什么字符串,编译器不会优化,想想这也是有道理的,编译器怕你对b的值改变,所以编译器不会优化。运行时b+c计算出来的"taobao"和栈内存里已经有的"taobao"是一个吗?不是。b+c计算出来的"taobao"应该是放在堆内存中的String对象。这可以通过System. out .println( (b+c)==MESSAGE );的结果为false来证明这一点。如果计算出来的b+c也是在栈内存,那结果应该是true。Java对String的相加是通过StringBuffer实现的,先构造一个StringBuffer里面存放”tao”,然后调用append()方法追加”bao”,然后将值为”taobao”的StringBuffer转化成String对象。StringBuffer对象在堆内存中,那转换成的String对象理所应当的也是在堆内存中。下面改造一下这个语句System. out.println( (b+c).intern()== MESSAGE );结果是true, intern() 方法会先检查 String 池 ( 或者说成栈内存 ) 中是否存在相同的字符串常量,如果有就返回。所以 intern()返回的就是MESSAGE指向的"taobao"。再把变量b和c的定义改一下,

final  String b =  "tao" ;

final  String c =  "bao" ;

System. out .println( (b+c)== MESSAGE );

现在b和c不可能再次赋值了,所以编译器将b+c编译成了”taobao”。因此,这时的结果是true。

在字符串相加中,只要有一个是非final类型的变量,编译器就不会优化,因为这样的变量可能发生改变,所以编译器不可能将这样的变量替换成常量。例如将变量b的final去掉,结果又变成了false。这也就意味着会用到StringBuffer对象,计算的结果在堆内存中。

如果对指向堆内存中的对象的String变量调用intern()会怎么样呢?实际上这个问题已经说过了,(b+c).intern(),b+c的结果就是在堆内存中。对于指向栈内存中字符串常量的变量调用intern()返回的还是它自己,没有多大意义。它会根据堆内存中对象的值,去查找String池中是否有相同的字符串,如果有就将变量指向这个string池中的变量。

String a = "tao"+"bao";

String b = new String("taobao");

System.out.println(a==MESSAGE); //true

System.out.println(b==MESSAGE);  //false

b = b.intern();

System.out.println(b==MESSAGE); //true

System. out .println(a==a.intern());  //true

转载于:https://www.cnblogs.com/nxjblog/p/10574550.html

String类型的认识以及编译器优化相关推荐

  1. java中字符串的创建_【转载】 Java中String类型的两种创建方式

    本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...

  2. 深入理解JVM虚拟机(八):编译器优化

    本博客从编译期源码实现的层次上让我们了解了Java源代码编译为字节码的过程,分析了Java语言中泛型.主动装箱/拆箱.条件编译等多种语法糖的前因后果. 1. 概述 java语言的"编译期&q ...

  3. String类型的学习

    一 :关于两个string类型变量是否相等: 请运行以下示例代码StringPool.java,查看其输出结果.如何解释这样的输出结果?从中你能总结出什么? 分析: 首先为s0开辟空间,然后给s1开辟 ...

  4. C#编译器优化那点事

    使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...

  5. 对于String类型的深刻理解

    1."abc"与new String("abc"); 经常会问到的面试题:String s = new String("abc");创建了几 ...

  6. 从自定义string类型理解右值引用

    理解右值引用 前言 问题复现 自定义string(CMyString) 遇到问题 图示理解 右值引用 什么是右值 添加右值引用参数的成员方法 结果对比 解决遗留问题 前言 在之前,我写过一篇: 通过自 ...

  7. #linux# gcc编译器优化选项的详细信息

    Table of Contents 优化选项-O0 优化选项-O1 优化选项-O2 优化选项-O3 优化选项-OS 支持CPU类型target gcc编译器优化选项O0, O1, O2, O3, Os ...

  8. 关于string类型的字符串是否以\0结尾

    今天在带大一学生C++上机时,涉及到一个string类型的字符串是否以\0结尾的问题,本来我很坚定string类型结尾并没有\0,C风格的字符数组才会那样.但是程序运行结果却说明string类型的字符 ...

  9. 2019-05-21 Java学习日记之String类型Demo

    String类的构造方法: public String():空构造 public String(byte[ ] bytes):把字节数组转成字符串 public String(byte[ ] byte ...

最新文章

  1. STM32外设有哪些?外设在总线上是怎么挂载的?
  2. 通过Python实现马尔科夫链蒙特卡罗方法的入门级应用
  3. Opencv打印显示Mat方法
  4. 人工学院2卡顿_浙大宁波理工学院就业率怎么样 | 就业情况 | 前景好的专业
  5. 如何在原生微信小程序中实现数据双向绑定
  6. 设计模式之三:装饰者模式(简单实现(星巴兹咖啡))
  7. 抽取、转换和装载介绍(五)抽取数据
  8. c51单片机时钟程序汇编语言,51单片机时钟汇编程序
  9. 2020年,抖音赚钱全攻略,做抖音,看这就够了!
  10. 程序员怎样才能写出一篇好的博客或者技术文章
  11. php用户权限分配方法,php – 在Laravel 5中使用Entrust为用户分配权限,而不是角色...
  12. 关于vs在.cpp提取头文件运行的时候一直报错“xx函数主体重定义”
  13. 笨办法学python 粗略笔记(learn python the hard way)
  14. 计算机提示无法访问手机tf卡,内存卡在电脑上无法显示
  15. kali linux 命令
  16. 行之有效:第一章观后有感
  17. MBA-day12数学-植树问题
  18. Iframe根据src页面高度实时调整高度
  19. Hack TheGame 11关通关攻略
  20. HDMI接口的计算机外接DP接口的显示器

热门文章

  1. 【原】Linux设备网络硬件管理
  2. 微博预计要火一阵的SleepSort之Shell及C实现
  3. word2013标题编号变成黑框
  4. java-基础-ArrayList剖析
  5. openstack 之 控制节点物理机备份
  6. 静态存储区、堆和栈的区别
  7. Centos7 安装 tomcat9 后访问慢且 shutdown.sh 报错,提示 8005 端口未启用
  8. CSS clear 清除浮动,兼容各浏览器
  9. 2018年最新的single-cell-RNA-seq analysis repositories
  10. eclipse调试报错,无法进入类的解决办法