String之常量池小结
1、String 常量池
String使用private final char value[ ]实现字符串的存储,也就是说String创建对象之后不能够再次修改此对象中存储的字符串内容,因而String类型是不可变的(immutable),因而String类是线程安全的。
其中字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享
Note:常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式。常量池是在堆内存中的一块。常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用,比如:类和接口的全限定名、字段的名称和描述符、方法和名称和描述符。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池(-128——127)具体可以参阅http://book.51cto.com/art/201202/317488.htm这里就不展开赘述了。
2、True OR False
首先得看下 几个对象???
相信很多 玩java的都做做类似 String s = new String("abc")这个语句创建了几个对象的题目。 这种题目主要就是为了考察对字符串对象的常量池掌握与否。其实上述的语句中是创建了2个对象:
第一个对象是"abc"字符串存储在常量池中
第二个对象在JAVA Heap中的 String 对象。这里不要混淆了s是放在栈里面的指向了Heap堆中的String对象
下面再看:
String str1 = new String("abc");
String str2 = "abc";
这里是两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。运行时期创建
而第二种是先在栈中创建一个对String类的对象引用变量str2,然后通过符号引用去字符串常量池里找有没有"abc",如果没有,则将"abc"存放进字符串常量池,并令str2指向”abc”,如果已经有”abc” 则直接令str2指向“abc”。编译期间完成
还有几个经常考的面试题:
String s1 = new String("s1") ;
String s2 = new String("s1") ;
上面创建了几个String对象?
答案:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.(用new创建的每new一次就在堆上创建一个对象,用引号创建的如果在常量池中已有就直接指向,不用创建)
比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。
下面就是用几个例子说明来说明一下
例1
String s1 = "sss111";
String s2 = "sss111";
System.out.println(s1 == s2); //结果为true
例2
String s1 = new String("sss111");
String s2 = "sss111";
System.out.println(s1 == s2); //结果为false
例3
String s1 = new String("111");
String s2 = "sss111";
String s3 = "sss" + "111";
String s4 = "sss" + s1;
System.out.println(s2 == s3); //true
System.out.println(s2 == s4); //false
System.out.println(s2 == s4.intern()); //true
结果上面分析,总结如下:
1.单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
2,使用new String("")创建的对象会存储到heap中,是运行期新创建的;
3,使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
4,使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;
3、 令人产生迷惑的intern
上面例子比较简单再看看这个呢?
【例1】
String s1 = new String("sss111");
s1=s1.intern();
String s2 = "sss111";
System.out.println(s1 == s2); //true
(若s1=s1.intern();改为s1.intern则为false,由于仅仅做了查询和存放。)
搞清楚这个问题首先要知道intern是做什么的,当我们声明String常量时池往往有以下俩种方式:
* 直接使用双引号声明出来的String对象会直接存储在常量池中。
* 如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
可以在源码中看到(String.intern方法中看到),这个方法是一个 native 的方法,但注释写的非常明了。“如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回”。
【例2】
来看一段代码:
public static void main(String[] args) {
String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);
}
打印结果是
* jdk6 下false false
* jdk7 下false true
*在第一段代码中,先看 s3和s4字符串。String s3 = new String("1") + new String("1");,这句代码中现在生成了2最终个对象,是字符串常量池中的“1” 和 JAVA Heap 中的 s3引用指向的对象。中间还有2个匿名的new String("1")我们不去讨论它们。此时s3引用对象内容是"11",但此时常量池中是没有 “11”对象的。
接下来s3.intern();这一句代码,是将 s3中的“11”字符串放入 String 常量池中,因为此时常量池中不存在“11”字符串,因此常规做法是在 jdk6 在常量池中生成一个 "11" 的对象从而s指向的是堆中1,s2指向常量池中1,因而为false。关键点是 jdk7 中常量池,可以直接存储堆中的引用。这份引用指向 s3 引用的对象。 也就是说引用地址是相同的因而为true。
String之常量池小结的更多相关文章
- Java中的String与常量池[转帖]
string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...
- Java中的String与常量池
string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...
- 基本数据类型的常量池与String类型常量池解析
抛出样例: Integer a1 = new Integer(123); Integer a2 = new Integer(123); System.out.print ...
- String对象常量池特性对synchronized对象的影响
一 .什么是String的常量池特性 对于字符串对象有两种创建方法,如下: 直接赋值法: String str1="直接赋值创建字符串"; 创建对象法: String str2=n ...
- java 多线程10:synchronized锁机制 之 锁定类静态方法 和锁定类.Class 和 数据String的常量池特性
同步静态方法 synchronized还可以应用在静态方法上,如果这么写,则代表的是对当前.java文件对应的Class类加锁.看一下例子,注意一下printC()并不是一个静态方法: public ...
- 转载:Java中的String与常量池
转载自http://developer.51cto.com/art/201106/266454.htm.感觉总结的不错,自己收藏一下. string是java中的字符串.String类是不可变的,对S ...
- (转)Java中的String与常量池
Java中的String与常量池 转自:http://developer.51cto.com/art/201106/266454.htm string是java中的字符串.String类是不可变的,对 ...
- String与常量池(JDK1.8)
---- 基础知识 String是final类, 并且其方法都被final修饰 String通过char数组来保存字符串 对String对象的任何操作都不会影响到原来的String对象, 所有的改变都 ...
- String与常量池
转自:http://blog.sina.com.cn/s/blog_69dcd5ed0101171h.html 1. 首先String不属于8种基本数据类型,String是一个对象.因为对象的默认值是 ...
随机推荐
- day07 Cookie 和 Session(非常重要)
day07 Cookie 和 Session 1. 会话技术 2. cookie 的方法和 cookie 案例-显示用户上次访问网站的时间 3. cookie 的细节 - 删除 cookie 4. S ...
- 90. Subsets II(中等,编写代码有难度)
Given a collection of integers that might contain duplicates, nums, return all possible subsets. Not ...
- 561. Array Partition I
Given an array of 2n integers, your task is to group these integers into n pairs of integer, say \(( ...
- bootstrap table 和 x-editable 使用方法
最近需要做一些数据表格,有同事推荐EasyUI,但经过比较还是选择了Bootstrap,一款极为强大的表格组件,基于Bootstrap 的 jQuery .本文还将介绍Bootstrap-editab ...
- Android studio安装和问题
一.Android studio的安装 [提示]A.以下Android studio2.2.2版本.(也有新版本) B.以下是用Android studio自带的sdk ①双击安装文件进行安装 ②如果 ...
- C++/C# 开发高级案例资料一次送!关注加群领取哦!
目前C/C++.C#.JAVA等语言开发的在线教育比较火爆,但小编所见的讲解高级案例的非常少,切合市场需求的较少.而且针对铁路.公路.建筑.市政.制造业等所有工业计算机辅助设计的开发技术和案例几乎没有 ...
- 这是一个测试,测试markdown语法
[TOC] 1. chpt1 这是一段话,前面没有空格 前面有4个空格,且在编辑状态下上面没有空行 前面有4个空格,且在编辑状态下上面有一个空行. 前面按了一下tab 1.1 1.1 2 段落1 前面 ...
- 安卓高级EventBus使用详解
我本来想写但是在网上看了下感觉写得不如此作者写得好:http://www.jianshu.com/p/da9e193e8b03 前言:EventBus出来已经有一段时间了,github上面也有很多开源 ...
- nginx+tomcat负载均衡和session复制
本文介绍下传统的tomcat负载均衡和session复制. session复制是基于JVM内存的,当然在当今的互联网大数据时代,有更好的替代方案,如将session数据保存在Redis中. 1.安装n ...
- Sqoop-1.4.6 Merge源码分析与改造使其支持多个merge-key
Sqoop中提供了一个用于合并数据集的工具sqoop-merge.官方文档中的描述可以参考我的另一篇博客Sqoop-1.4.5用户手册. Merge的基本原理是,需要指定新数据集和老数据集的路径,根据 ...