今天第一次翻看Effective java,在其第一个item中讲静态工厂方法的有点的时候说到“它们每次被调用

的时候,不要非得创建一个新的对象”并在结尾处提到---"String.intern方法以一种有限的形式实现了这

种优化",由于以前没用过intern这个方法,所以去查了查,并把自己的理解写下来供以后参考
首先来看其中文API的描述:

intern

public String intern()
返回字符串对象的规范化表示形式。 
一个初始时为空的字符串池,它由类 String 私有地维护。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。 它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true

总结出来其意思如下:
如果:s.intern()方法的时候,会将共享池中的字符串与外部的字符串(s)进行比较,如果共享池中有与之相等的字符串,则不会将外部的字符串放到共享池中的,返回的只是共享池中的字符串,如果不同则将外部字符串放入共享池中,并返回其字符串的句柄(引用)-- 这样做的好处就是能够节约空间

最后看看这方面的一个很好的例子

在例子之前我们先假设我们在sqlserver2000里面有Test数据库,里面有表如下:
test1
name 
我们通过下面程序向里面添加8000条记录:

import java.sql.*;

public class TestDB {

private static String driverName = "com.microsoft.jdbc.sqlserver.SQLServerDriver";

private static String dbURL =

"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=TEST";

private static String userName = "sa";

private static String userPwd = "";

private static Connection dbConn;

public static void main(String[] args) {

try {
   Class.forName(driverName);
   dbConn = DriverManager.getConnection(dbURL, userName, userPwd);
   Statement stmt = dbConn.createStatement();
   String sql = "insert into test1 values('123456789123456789123456789');";
   for (int i = 0; i < 8000; i++) {
    stmt.executeUpdate(sql);
   }
   System.out.println("Connection Successful!");
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

添加完成以后我们在查询分析器里面执行:
select count(*) from test1;
可以看到结果:8000  表明8000条数据插入正确

假设我们有这样一个类:Po.java
public class Po {
 private String name;

public void setName(String s) {
  name = s;
 }

}

我们执行下面的类:TestStringIntern.java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class TestStringIntern {
 private static String driverName = "com.microsoft.jdbc.sqlserver.SQLServerDriver";

private static String dbURL =

"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=TEST";

private static String userName = "sa";

private static String userPwd = "";

private static Connection dbConn;

private static List<Po> list= new ArrayList<Po>();
 public static void main(String[] args) {

try {
   Class.forName(driverName);
   dbConn = DriverManager.getConnection(dbURL, userName, userPwd);
   Statement stmt = dbConn.createStatement();
   ResultSet rs = stmt.executeQuery("select name from test1");
   while(rs.next()){
    String s = rs.getString(1);;
    Po p = new Po();
    p.setName(s);
    list.add(p);
    s = null;
    p = null;
   }
   long total = Runtime.getRuntime().totalMemory();
   long free = Runtime.getRuntime().freeMemory();
   System.out.println("The busy memory is: " + (total - free));
   rs.close();
   stmt.close();
   dbConn.close();
   System.gc();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}
我们可以看到执行的结果为:The busy memory is: 1252880
注意:如果把p.setName(s)这句换成p.setName(s.intern());
再执行该程序我们可以看到结果:The busy memory is: 515944
我们可以到经过细微的改变我们可以看到其占用的内存不是一个数量级的
那么这个intern()函数做了什么呢?我认为:
在String对象维持的一个私有池里面存放的字符串“123456789123456789123456789”可能只有一个,因为每次比对都是一样,所以是不会将这样的对象重复放到池里面的,所以调用intern()方法就是完成的这个功能,其返回的只是里面的同一个字符串,而没有创建新的字符串,所以不会占用太多的空间

注:以上很多只是个人理解,具体实现细节不太清楚,所以难免会有错的地方,希望指出。

String的intern方法的用处的更多相关文章

  1. java String 中 intern方法的概念

    1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...

  2. String 的intern() 方法说明

    1.说明 Java中string.intern()方法调用会先去字符串常量池中查找相应的字符串,如果字符串不存在,就会在字符串常量池中创建该字符串然后再返回. 2.源码说明 public native ...

  3. String 的 intern() 方法解析

    一.概述 JDK7 之前和之后的版本,String 的 intern() 方法在实现上存在差异,本文的说明环境是 JDK8,会在文末说明 intern() 方法的版本差异性. intern() 方法是 ...

  4. String中intern方法的作用

    前言 读完这篇文章你可以了解,String对象在虚拟机内存中的存放,intern的作用,这么多String对象的创建到底有什么区别,String 创建的对象有几个!! 正题 先科普几个知识点1.常量池 ...

  5. String的intern方法的使用场景

    在讲intern方法前,我们先简单回顾下Java中常量池的分类. 常量池的分类 Java中常量池可以分为Class常量池.运行时常量池和字符串常量池. 1. Class文件常量池 在Class文件中除 ...

  6. String的Intern方法详解

    引言 在 JAVA 语言中有8中基本类型和一种比较特殊的类型String.这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念.常量池就类似一个JAVA系统级别提供的缓存.8种 ...

  7. String的Intern方法

    jdk6 和 jdk7 下 intern 的区别 相信很多 JAVA 程序员都做做类似 String s = new String("abc")这个语句创建了几个对象的题目. 这种 ...

  8. java String的intern()方法

    intern()方法用于将字符串对象加入常量池中. public native String intern(); intern()方法返回的是一个常量池中的String对象(即常量池中某个String ...

  9. Java - 记录String中intern()方法的学习与理解

    intern()方法:把堆中的引用丢入常量池中,然后返回这个引用.当常量池中已经存在这个引用,就直接返回这个引用.(jdk1.8) 由于jdk1.7中将字符串常量池改为存放在堆中,因此intern() ...

随机推荐

  1. easy ui datagrid 设置冻结列

    为了冻结列,您需要定义 frozenColumns 属性.frozenColumn 属性和 columns 属性一样. $('#tt').datagrid({ title:'Frozen Column ...

  2. ios 中定时器:NSTimer, CADisplayLink, GCD

    #import "ViewController.h" #import "RunloopViewController.h" @interface ViewCont ...

  3. c#类库中使用Session

    网站开发中,为了保存用户的信息,有时候需要使用session.如果我们在aspx页面中使用Session,只需要Session["key"]=value就可以,获取时使用int u ...

  4. poj 3207 Ikki's Story IV - Panda's Trick (2-SAT)

    http://poj.org/problem?id=3207 Ikki's Story IV - Panda's Trick Time Limit: 1000MS   Memory Limit: 13 ...

  5. response 返回 带双引号 的字符串解决办法 springmvc

    springmvc json配置 返回的时候给你加上了

  6. c++ deque 双端队列

    双端队列: 函数 描述 c.assign(beg,end)c.assign(n,elem)  将[beg; end)区间中的数据赋值给c.将n个elem的拷贝赋值给c. c.at(idx)  传回索引 ...

  7. 三年PS经验

  8. (转)基于即时通信和LBS技术的位置感知服务(三):搭建Openfire服务器+测试2款IM客户端

    主要包含4个章节: 1. Java 领域的即时通信的解决方案 2. 搭建 Openfire 服务器 3. 使用客户端测试我们搭建的 Openfire 服务器 4. Smack 和 ASmack 一.J ...

  9. hdu 1085

    额    母函数 #include <cstdio> #include <cstring> int a[3],b[3]= {1,2,5}; int c1[10001],c2[1 ...

  10. 【C++基础】 各种“虚”总结(ing...)

    虚基类,虚函数,虚析构函数,纯虚函数,虚函数表(待补充) 一.虚基类——在继承方式(public / private)之前加 virtual class B1: virtual public B0{} ...