对String类型的认识以及编译器优化
Java中String不是基本类型,但是有些时候和基本类型差不多,如String b = "tao" ; 可以对变量直接赋值,而不用 new 一个对象(当然也可以用 new)。
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方法。
有如下一段代码,请选择其运行结果()
public class StringDemo{
private static final String MESSAGE="taobao";
public static void main(String [] args) {
String a ="tao"+"bao";
String b="tao";
String c="bao";
System.out.println(a==MESSAGE);
System.out.println((b+c)==MESSAGE);
}
}
MESSAGE 成员变量及其指向的字符串常量肯定都是在栈内存里的,变量 a 运算完也是指向一个字符串“ taobao ”啊?是不是同一个呢?这涉及到编译器优化问题。对于字符串常量的相加,在编译时直接将字符串合并,而不是等到运行时再合并。也就是说
String a = "tao" + "bao" ;和String a = "taobao" ;编译出的字节码是一样的。所以等到运行时,根据上面说的栈内存是数据共享原则,a和MESSAGE指向的是同一个字符串。而对于后面的(b+c)又是什么情况呢?b+c只能等到运行时才能判定是什么字符串,编译器不会优化。运行时b+c计算出来的"taobao"和栈内存里已经有的"taobao"是一个吗?不是。b+c计算出来的"taobao"应该是放在堆内存中的String对象。这可以通过System. out .println( (b+c)== MESSAGE );的结果为false来证明这一点。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类型的认识以及编译器优化的更多相关文章
- java中特殊的String类型
Java中String是一个特殊的包装类数据有两种创建形式: String s = "abc"; String s = new String("abc"); 第 ...
- java中的堆、栈、常量池以及String类型的两种声明
参考自http://blog.sina.com.cn/s/blog_798b04f90100ta67.html http://www.cnblogs.com/fguozhu/articles/2661 ...
- java中关于String 类型数据 的存储方式
Constant Pool常量池的概念: 在讲到String的一些特殊情况时,总会提到String Pool或者Constant Pool,但是我想很多人都不太 明白Constant Pool到底是个 ...
- C#编译器优化那点事
使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...
- 【转载】 Java中String类型的两种创建方式
本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...
- 【Java】 String类型的==使用
public class StringDemo { public static void main(String[] args) { String s1 = "abc"; Stri ...
- String类型的学习
一 :关于两个string类型变量是否相等: 请运行以下示例代码StringPool.java,查看其输出结果.如何解释这样的输出结果?从中你能总结出什么? 分析: 首先为s0开辟空间,然后给s1开辟 ...
- C#中特殊的string类型
string C#有string关键字,在翻 ...
- C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理
C#编译器优化那点事 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...
随机推荐
- Struts 2的下载和安装
一.为Web应用增加Struts 2支持 下载和安装Struts 2步骤: 登录http://struts.apache.org/download.cgi站点,下载Struts 2的最新版,下载时有以 ...
- slideshare文档下载
if [ x"$1" = x1 ]; then for i in {1..46}; do url_i="https://image.slidesharecdn.com/b ...
- www.wolframalpha.com
单个查询 http://www.wolframalpha.com/input/?source=nav&i=simplify+radical+sqrt(567) notebook https:/ ...
- PAT Advanced 1051 Pop Sequence (25) [栈模拟]
题目 Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, -, N and ...
- python 并发执行
并发执行, 精简代码. 适用python2 和python3 # -*- encoding:utf-8 -*- from threading import Thread from multiproce ...
- 基于Dijsktra算法的最短路径求解
基于Dijsktra算法的最短路径求解 描述 一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长度已知.给定地图的一个起点城市和终点城市,利用Dijsktra算法求出起点到终点之间 ...
- 启动查看crontab日志服务
方法1: . 修改rsyslog文件,将/etc/rsyslog.d/-default.conf 文件中的#cron.*前的#删掉: . 重启rsyslog服务service rsyslog rest ...
- 基础篇八:log配置
第一:首选查看有哪些日志文件 cd /etc/nginx/ cat nginx.conf cd /var/log/nginx/
- 文件流下载时 axios blob文件大小不正确?
文件流下载时 js blob文件大小不正确? res.data的字节长度 length blob.size匹配不上.. axio请求里必须修改 responseType: 'blob' 参数, 默认是 ...
- K - The Unique MST (最小生成树的唯一性)
Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spann ...