相信绝大多数的人不会去用String类的intern方法,打开String类的源码发现这是一个本地方法,定义如下:
public native String intern();
文档告诉我们该方法返回一个字符串对象的内部化引用。
众所周知:String类维护一个初始为空的字符串的对象池,当intern方法被调用时,如果对象池中已经包含这一个相等的字符串对象则返回对象池中的实例,否则添加字符串到对象池并返回该字符串的引用。
从程序的角度上怎么来看这个方法呢,我们假设有两个字符串s1,s2,当s1.equals(s2)时,s1.intern()==s2.intern(),也就是说这两个字符串在内存中使用的是同一个实例。
Java语言规范中定义了字符串文字以及更一般的常量表达式的值的字符串是被内部化的,以便它们共享同一个实例。我们试验一下下面代码:
String s1="你好,Java";
String s2="你好,"+"Java";
System.out.println(s1==s2);
System.out.println(s1.intern()==s2.intern());
这段代码将打印两个true,也就是说字符串s1和s2是共享同一个实例。不过前提是尽管使用了表达式,但是表达式中必须都是常量。
了解这个处理机制也可以让我们在用到字符串常量的时候了解如何节省这些字符串所占用的内存。
下面两个例子可以帮你:
其一:
import javax.swing.*; public class StringIntern { public static void main(String args[]) { String s1, s2, s3, s4, output; s1 = new String("hello"); s2 = new String("hello"); if (s1 == s2) output = "s1 and s2 are the same object in memory"; else output = "s1 and s2 are not the same object in memory"; if (s1.equals(s2)) output += "\ns1 and s2 are equal"; else output += "\ns1 and s2 are not equal"; s3 = s1.intern(); s4 = s2.intern(); if (s3 == s4) output += "\ns3 and s4 are the same object in memory"; else output += "\ns3 and s4 are not the same object in memory"; if (s1 == s3) output += "\ns1 and s3 are the same object in memory"; else output += "\ns1 and s3 are not the same object in memory"; if (s2 == s4) output += "\ns2 and s4 are the same object in memory"; else output += "\ns2 and s4 are not the same object in memory"; if (s1 == s4) output += "\ns1 and s4 are the same object in memory"; else output += "\ns1 and s4 are not the same object in memory"; JOptionPane.showMessageDialog(null, output, "Demonstrating String Method intern", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } }
运行结果:
其二:
假定要加载许多数据库数据到内存,这些数据有很多是重复的。在反复测试之后,发现intern() 省了好多内存。
以下是表信息:
mysql> select count(*) from t1;
+------------+
| count(*) |
+------------+
| 8000 |
+------------+
1 row in set (0.01 sec)
mysql> select name From t1 limit 0,1;
+--------------------------------------+
| name |
+--------------------------------------+
| 123456789123456789123456789 |
+--------------------------------------+
1 row in set (0.00 sec)
总共8000行 ,每行的数据都是 "123456789123456789123456789"
下面是类 (连接异常忽略)
public static void a1() throws SQLException {
List list = new ArrayList();
Connection con = DB.getCon();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name FROM t1");
while (rs.next()) {
String s = rs.getString(1);
Po o = new Po();
//o.setName(s); //注释掉
o.setName(s.intern());
list.add(o);
s=null;
o = null;
}
rs.close();
stmt.close();
con.close();
}
public static void a2() throws SQLException {
List list = new ArrayList();
Connection con = DB.getCon();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name FROM t1");
while (rs.next()) {
String s = rs.getString(1);
Po o = new Po();
o.setName(s);
list.add(o);
s=null;
o = null;
}
rs.close();
stmt.close();
con.close();
}
注意:
a1 方法测试 使用内存: 2046544
a2 方法测试 使用内存: 3475000
如果在函数的结尾加上 System.gc(); 去除connection 的影响
a1 方法测试 使用内存: 668856
a2 方法测试 使用内存:2262232
然后再把 写函数 a3() ,把rs.getString(1) 换为 get()
static String get() {
return "123456789123456789123456789123456789123456789";
}
public static void a3() throws SQLException {
List list = new ArrayList();
Connection con = DB.getCon();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name FROM t1");
while (rs.next()) {
String s = get();
Po o = new Po();
o.setName(s);
list.add(o);
s=null;
o = null;
}
rs.close();
stmt.close();
con.close();
}
a3 方法测试 使用内存:666536
a2 (668856)比a3 的内存使用量多了一点点,这个估计就是常量池那一点内存
8000条数据 差别这么大, 数据量再大的话,优势更加明显.建议大家在连接数据库查询出来的数据,用intern();
注:内存使用 用 Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory() 计算
转自: http://www.java3z.com/cwbwebhome/article/article2/21063.html?id=1833 谢谢原作者。
相关推荐
java中String类的intern、split方法的详细讲解。
这篇文章将要讨论 Java 6 中是如何实现 String.intern 方法的,以及这个方法在 Java 7 以及 Java 8 中做了哪些调整。
Java String#intern() 内存模型是 Java 语言中一个重要的概念,.string#intern() 方法是 Java 字符串常量池中一个重要的组件。字符串常量池是一个固定大小的 HashMap,桶的数量默认是 1009,从 Java7u40 开始,该...
关于String.intern()方法,这个问题都被问烂了,有的文章在分析的时候还在用jdk1.7,jdk1.8之后内存模型发生了变化,内存的变化也会影响intern方法的执行,这里有必要写文章分析一下,请大家务必从头开始看,这样...
之前我们提到了,String.intern方法会返回字符串常量池中的字符串对象的引用。 而G1垃圾回收器的字符串去重的功能其实和String.intern有点不一样,G1是让两个字符串的底层指向同一个byte[]数组。 有图为证: 上图中...
pos文件是ProcessOn的源文件,可以导入后直接打开编辑。 内容是:不同jdk版本下对String的intern()的分析
主要给大家介绍了关于C#中字符串优化String.Intern、IsInterned的相关资料,文中通过示例代码介绍的,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
本文主要介绍java 中String 的intern方法,这里主要通过实例来说明不同版本的JDK,intern方法的对比,有需要的小伙伴可以参考下
深入理解JavaString#intern()内存模型Java开发Java经验技巧共4页.pdf.zip
主要给大家介绍了关于java String中intern的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。 在Java中,字符串常量池存在于方法区中。方法...
主要介绍了Java String的intern用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了通过String.intern()方法浅谈堆中常量池,在JDK7之前,字符串常量是存在永久带Perm 区的,JDK7开始在将常量池迁移到堆中,这个变化也导致了String的新特性,下面我们慢慢进行介绍。,需要的朋友可以参考下
大家知道,Java中string.intern()方法调用会先去字符串常量池中查找相应的字符串,如果字符串不存在,会在字符串常量池中创建该字符串然后再返回。 字符串常量池是一个固定大小的HashMap,桶的数量默认是1009, ...
String.intern()是一个Native方法,底层调用C++的 StringTable::intern 方法,源码注释:当调用 intern 方法时,如果常量池中已经该字符串,则返回池中的字符串;否则将此字符串添加到常量池中,并返回字符串的...
A2:当一个String实例调 用 intern() 方法时,Java查找常量池中是否有相同Unicode 的字符串常量,如果有,则返回其的引用,如果没有,则在
intern() 方法用于将 String 对象添加到 String 池中。如果 String 池中已经存在该字符串,则返回该字符串的引用;否则,创建一个新的字符串对象并添加到 String 池中。 Java 中的 Object 对象和 String 对象是两个...