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之常量池小结的更多相关文章

  1. Java中的String与常量池[转帖]

    string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...

  2. Java中的String与常量池

    string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...

  3. 基本数据类型的常量池与String类型常量池解析

    抛出样例: Integer a1  = new Integer(123);        Integer a2  = new Integer(123);        System.out.print ...

  4. String对象常量池特性对synchronized对象的影响

    一 .什么是String的常量池特性 对于字符串对象有两种创建方法,如下: 直接赋值法: String str1="直接赋值创建字符串"; 创建对象法: String str2=n ...

  5. java 多线程10:synchronized锁机制 之 锁定类静态方法 和锁定类.Class 和 数据String的常量池特性

    同步静态方法 synchronized还可以应用在静态方法上,如果这么写,则代表的是对当前.java文件对应的Class类加锁.看一下例子,注意一下printC()并不是一个静态方法: public ...

  6. 转载:Java中的String与常量池

    转载自http://developer.51cto.com/art/201106/266454.htm.感觉总结的不错,自己收藏一下. string是java中的字符串.String类是不可变的,对S ...

  7. (转)Java中的String与常量池

    Java中的String与常量池 转自:http://developer.51cto.com/art/201106/266454.htm string是java中的字符串.String类是不可变的,对 ...

  8. String与常量池(JDK1.8)

    ---- 基础知识 String是final类, 并且其方法都被final修饰 String通过char数组来保存字符串 对String对象的任何操作都不会影响到原来的String对象, 所有的改变都 ...

  9. String与常量池

    转自:http://blog.sina.com.cn/s/blog_69dcd5ed0101171h.html 1. 首先String不属于8种基本数据类型,String是一个对象.因为对象的默认值是 ...

随机推荐

  1. 原生js实现preAll和nextAll方法

    一直以来都在好奇,jquery的prevAll和nextAll方法都是咋实现的,那么厉害,而且还那么方便.不得不说,jquery真的帮我们省去了开发中手写大量js代码带来的开发进度问题,而且很好的解决 ...

  2. delphi 线程教学第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行

    第七节:在多个线程时空中,把各自的代码塞到一个指定的线程时空运行     以 Ado 为例,常见的方法是拖一个 AdoConnection 在窗口上(或 DataModule 中), 再配合 AdoQ ...

  3. ACM Super Jumping! Jumping! Jumping!

    Nowadays, a kind of chess game called "Super Jumping! Jumping! Jumping!" is very popular i ...

  4. MongoDB 连接

    启动 MongoDB服务 在前面的教程中,我们已经讨论了如何启动MongoDB服务,你只需要在MongoDB安装目录的bin目录下执行'mongod'即可. 执行启动操作后,mongodb在输出一些必 ...

  5. Apache ActiveMQ实战(2)-集群

    ActiveMQ的集群 内嵌代理所引发的问题: 消息过载 管理混乱 如何解决这些问题--集群的两种方式: Master slave Broker clusters ActiveMQ的集群有两种方式: ...

  6. TCP发送源码学习(1)--tcp_sendmsg

    一.tcp_sendmsg()函数分析: int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t ...

  7. LauncherModel.Callbacks接口

    public interface Callbacks { //如果Launcher在加载完成之前被强制暂停,那么需要通过这个回调方法通知 //launcher,在它再次显示的时候重新执行加载过程 pu ...

  8. Mac状态栏wifi图标一直闪烁重复连接但是网络正常的解决办法

    本猫的系统是EI(10.11.6),不知从哪个版本开始(至少是升级到EI之后),状态栏上的wifi图标一直闪烁,这应该是表示正在连接网络.但是网络是正常的! 虽说闪烁的wifi图标不影响使用,但是有强 ...

  9. win 8.1 64位彻底删除王码98

    安全模式 C:\Windows\SysWOW64\ 删除:winwb98.IME和winwb98.MB 注册表: 找到王码五笔相关的项.一般在最下面的以字母E开头的文件夹.全部删除. HKEY_LOC ...

  10. linuxsvn源代码版本库建立

    linuxsvn源代码版本库建立 下面就要建立代码的版本库做描述: 1.     安装svn版本服务器端 yum install subversion 从镜像下载安装svn服务器端,我们服务器已经安装 ...