- 浏览: 137925 次
文章分类
最新评论
-
qiaolevip:
求源码:qiaole@vip.qq.com
使用JAVA中的动态代理实现数据库连接池 -
qiaolevip:
使用JAVA中的动态代理实现数据库连接池 -
qiaolevip:
:ro ll:
使用JAVA中的动态代理实现数据库连接池 -
qp7711:
那这里是在哪里传参的?
通用分页实现及其OO设计探讨——转载 -
yaoaijia:
源码怎么都没有啊?
使用JAVA中的动态代理实现数据库连接池
String的创建
String s = "hello";
JVM先根据内容"hello"查找对象,如果没有找到,则在heap上创建新对象,并将其赋予s1,否则使用已经存在的对象
String s = new String("hello");
JVM直接在heap上创建新的对象,所以在heap中会出现内容相同,地址不同的String对象
String的比较
"==" 比较地址
"equals" 比较内容
举例:
- String s1 = "hello";
- String s2 = "hello";
- String s3 = new String("hello");
- s1 == s2; // true 地址相同
- s1 == s3; // false 地址不同
- s1.equals(s2); // true 内容相同
- s1.equals(s3); // true 内容相同
intern() 方法
查找内容相同(equals())的字符串
- String s1 = "hello"; // hello不存在,jvm创建新对象 (1)
- String s2 = new String("hello"); // 创举新对象 (2),这时heap中存在两个内容为hello的对象
- s1 == s2; // false // 地址不同
- s1.equals(s2); // true // 内容相同
- s2 = s2.intern(); // true // 找到对象(1) 并赋予s2
- s1 == s2; // true !! // 注意:此时s1,s2同指向(1)
效率:String 与 StringBuffer
情景1:
- (1) String result = "hello" + " world";
- (2) StringBuffer result = new String().append("hello").append(" world");
(1) 的效率好于 (2),不要奇怪,这是因为JVM会做如下处理
编译前 String result = "hello" + " world";
编译后 String result = "hello world";
情景2:
- (1) public String getString(String s1, String s2) {
- return s1 + s2;
- }
- (2) public String getString(String s1, String s2) {
- return new StringBuffer().append(s1).append(s2);
- }
(1) 的效率与 (2) 一样,这是因为JVM会做如下处理
编译前 return s1 + s2;
编译后 return new StringBuffer().append(s1).append(s2);
情景3:
- (1) String s = "s1";
- s += "s2";
- s += "s3";
- (2) StringBuffer s = new StringBuffer().append("s1").append("s2").append("s3");
(2) 的效率好于(1),因为String是不可变对象,每次"+="操作都会造成构造新的String对象
情景4:
- (1) StringBuffer s = new StringBuffer();
- for (int i = 0; i < 50000; i ++) {
- s.append("hello");
- }
- (2) StringBuffer s = new StringBuffer(250000);
- for (int i = 0; i < 50000; i ++) {
- s.append("hello");
- }
(2) 的效率好于 (1),因为StringBuffer内部实现是char数组,默认初始化长度为16,每当字符串长度大于char
数组长度的时候,JVM会构造更大的新数组,并将原先的数组内容复制到新数组,(2)避免了复制数组的开销
关键点
1). 简单的认为 .append() 效率好于 "+" 是错误的!
2). 不要使用 new 创建 String
3). 注意 .intern() 的使用
4). 在编译期能够确定字符串值的情况下,使用"+"效率最高
5). 避免使用 "+=" 来构造字符串
6). 在声明StringBuffer对象的时候,指定合适的capacity,不要使用默认值(18)
7). 注意以下二者的区别不一样
- - String s = "a" + "b";
- - String s = "a";
- s += "b";
String和StringBuffer之概览
创建字符串的较佳途径
滞留字符串带来的优化
连接字符串时的优化技巧
借助StringBuffer的初始化过程的优化技巧
关键点
非可变对象一旦创建之后就不能再被改变,可变对象则可以在创建之后被改变。String对象是非可变对象,StringBuffer对象则是可变对象。为获得更佳的性能你需要根据实际情况小心谨慎地选择到底使用这两者中的某一个。下面的话题会作详细的阐述。(注意:这个章节假设读者已经具备Java的String和StringBuffer的相关基础知识。)
- 1. String s1 = "hello";
- String s2 = "hello";
- 2. String s3 = new String("hello");
- String s4 = new String("hello");
- StringTest1.java
- package com.performance.string;
- /** This class shows the time taken for creation of
- * String literals and String objects.
- */
- public class StringTest1 {
- public static void main(String[] args){
- // create String literals
- long startTime = System.currentTimeMillis();
- for(int i=0;i<50000;i++){
- String s1 = "hello";
- String s2 = "hello";
- }
- long endTime = System.currentTimeMillis();
- System.out.println("Time taken for creation of String literals : "
- + (endTime - startTime) + " milli seconds" );
- // create String objects using 'new' keyword
- long startTime1 = System.currentTimeMillis();
- for(int i=0;i<50000;i++){
- String s3 = new String("hello");
- String s4 = new String("hello");
- }
- long endTime1 = System.currentTimeMillis();
- System.out.println("Time taken for creation of String objects : "
- + (endTime1 - startTime1)+" milli seconds");
- }
- }
这段代码的输出:
- Time taken for creation of String literals : 0 milli seconds
- Time taken for creation of String objects : 170 milli seconds
Java虚拟机会维护一个内部的滞留字符串对象的列表(唯一字符串的池)来避免在堆内存中产生重复的String对象。当JVM从class文件里加载字符串字面量并执行的时候,它会先检查一下当前的字符串是否已经存在于滞留字符串列表,如果已经存在,那就不会再创建一个新的String对象而是将引用指向已经存在的String对象,JVM会在内部为字符串字面量作这种检查,但并不会为通过new关键字创建的String对象作这种检查。当然你可以明确地使用String.intern()方法强制JVM为通过new关键字创建的String对象作这样的检查。这样可以强制JVM检查内部列表而使用已有的String对象。
同一个字符串对象被重复地创建是不必要的,String.intern()方法可以避免这种情况。下图说明了String.intern()方法是如何工作的,String.intern()方法检查字符
- StringTest2.java
- package com.performance.string;
- // This class shows the use of intern() method to improve performance
- public class StringTest2 {
- public static void main(String[] args){
- // create String references like s1,s2,s3...so on..
- String variables[] = new String[50000];
- for( int i=0;i<variables.length;i++){
- variables[i] = "s"+i;
- }
- // create String literals
- long startTime0 = System.currentTimeMillis();
- for(int i=0;i<variables.length;i++){
- variables[i] = "hello";
- }
- long endTime0 = System.currentTimeMillis();
- System.out.println("Time taken for creation of String literals : "
- + (endTime0 - startTime0) + " milli seconds" );
- // create String objects using 'new' keyword
- long startTime1 = System.currentTimeMillis();
- for(int i=0;i<variables.length;i++){
- variables[i] = new String("hello");
- }
- long endTime1 = System.currentTimeMillis();
- System.out.println("Time taken for creation of String objects with 'new' key word : "
- + (endTime1 - startTime1)+" milli seconds");
- // intern String objects with intern() method
- long startTime2 = System.currentTimeMillis();
- for(int i=0;i<variables.length;i++){
- variables[i] = new String("hello");
- variables[i] = variables[i].intern();
- }
- long endTime2 = System.currentTimeMillis();
- System.out.println("Time taken for creation of String objects with intern(): "
- + (endTime2 - startTime2)+" milli seconds");
- }
- }
- Time taken for creation of String literals : 0 milli seconds
- Time taken for creation of String objects with 'new' key word : 160 milli seconds
- Time taken for creation of String objects with intern(): 60 milli seconds
你可以使用+操作符或者String.concat()或者StringBuffer.append()等办法来连接多个字符串,那一种办法具有最佳的性能呢?
请看下面的StringTest3.java代码和输出结果。
- package com.performance.string;
- /** This class shows the time taken by string concatenation at compile time and run time.*/
- public class StringTest3 {
- public static void main(String[] args){
- //Test the String Concatination
- long startTime = System.currentTimeMillis();
- for(int i=0;i<5000;i++){
- String result = "This is"+ "testing the"+ "difference"+ "between"+
- "String"+ "and"+ "StringBuffer";
- }
- long endTime = System.currentTimeMillis();
- System.out.println("Time taken for string concatenation using + operator : "
- + (endTime - startTime)+ " milli seconds");
- //Test the StringBuffer Concatination
- long startTime1 = System.currentTimeMillis();
- for(int i=0;i<5000;i++){
- StringBuffer result = new StringBuffer();
- result.append("This is");
- result.append("testing the");
- result.append("difference");
- result.append("between");
- result.append("String");
- result.append("and");
- result.append("StringBuffer");
- }
- long endTime1 = System.currentTimeMillis();
- System.out.println("Time taken for String concatenation using StringBuffer : "
- + (endTime1 - startTime1)+ " milli seconds");
- }
- }
Time taken for String concatenation using + operator : 0 milli seconds
Time taken for String concatenation using StringBuffer : 50 milli seconds
很有趣地,+操作符居然比StringBuffer.append()方法要快,为什么呢?
- String result = "This is"+"testing the"+"difference"+"between"+"String"+"and"+"StringBuffer";
编译后:
- String result = "This is testing the difference between String and StringBuffer";
这里String对象在编译期就决定了而StringBuffer对象是在运行期决定的。运行期决定需要额外的开销当字符串的值无法预先知道的时候,编译期决定作用于字符串的值可以预先知道的时候,下面是一个例子。
- public String getString(String str1,String str2) {
- return str1+str2;
- }
return new StringBuffer().append(str1).append(str2).toString();
运行期决定需要更多的时间来运行。
看看下面的代码你会发现与情景一相反的结果――连接多个字符串的时候StringBuffer要比String快。
- StringTest4.java
- package com.performance.string;
- /** This class shows the time taken by string concatenation
- using + operator and StringBuffer */
- public class StringTest4 {
- public static void main(String[] args){
- //Test the String Concatenation using + operator
- long startTime = System.currentTimeMillis();
- String result = "hello";
- for(int i=0;i<1500;i++){
- result += "hello";
- }
- long endTime = System.currentTimeMillis();
- System.out.println("Time taken for string concatenation using + operator : "
- + (endTime - startTime)+ " milli seconds");
- //Test the String Concatenation using StringBuffer
- long startTime1 = System.currentTimeMillis();
- StringBuffer result1 = new StringBuffer("hello");
- for(int i=0;i<1500;i++){
- result1.append("hello");
- }
- long endTime1 = System.currentTimeMillis();
- System.out.println("Time taken for string concatenation using StringBuffer : "
- + (endTime1 - startTime1)+ " milli seconds");
- }
- }
- Time taken for string concatenation usi
- ng + operator : 280 milli seconds
- Time taken for String concatenation using StringBuffer : 0 milli seconds
原因是两者都是在运行期决定字符串对象,但是+操作符使用不同于StringBuffer.append()的规则通过String和StringBuffer来完成字符串连接操作。(译注:什么样的规则呢?)
你可以通过StringBuffer的构造函数来设定它的初始化容量,这样可以明显地提升性能。这里提到的构造函数是StringBuffer(int length),length参数表示当前的StringBuffer能保持的字符数量。你也可以使用ensureCapacity(int minimumcapacity)方法在StringBuffer对象创建之后设置它的容量。首先我们看看StringBuffer的缺省行为,然后再找出一条更好的提升性能的途径。
StringBuffer在内部维护一个字符数组,当你使用缺省的构造函数来创建StringBuffer对象的时候,因为没有设置初始化字符长度,StringBuffer的容量被初始化为16个字符,也就是说缺省容量就是16个字符。当StringBuffer达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,也就是(2*旧值+2)。
Time taken for String concatenation using StringBuffer with out setting size: 280 milli seconds
Time taken for String concatenation using StringBuffer with setting size: 0 milli seconds
1. 无论何时只要可能的话使用字符串字面量来常见字符串而不是使用new关键字来创建字符串。
2. 无论何时当你要使用new关键字来创建很多内容重复的字符串的话,请使用String.intern()方法。
3. +操作符会为字符串连接提供最佳的性能――当字符串是在编译期决定的时候。
4. 如果字符串在运行期决定,使用一个合适的初期容量值初始化的StringBuffer会为字符串连接提供最佳的性能。
String类提供了一些方法,用来进行字符串的比较。这个类实现了Object父类的equals()方法,用来比较两种字符串的值是否相等。同时还增加了equalsIgnoreCase()方法可以忽略两个字符串大小写的区别。下面是这两种方法的例子。
【例6-6】
- public class E6_6{
- public static void main(String args[]) {
- String s1="a";
- String s2=new String("a");
- String s3="A";
- System.out.println(s1.equals(s2));
- System.out.println(s1.equals(s3));
- System.out.println(s1.equalsIgnoreCase(s3));
- }
- }
true
flase
true
但是StringBuffer类并没有实现Objcet类的Equals方法,所以不能用这个方法来比较两个StringBuffer类的字符串是否相等,如下例所示。
【例6-7】
- public class E6_7{
- public static void main(String args[]) {
- StringBuffer s1=new StringBuffer("a");
- StringBuffer s2=new StringBuffer("a");
- System.out.println(s1.equals(s2));
- }
- }
程序输出:false
除了用equalse方法来比较两个字符串外,还可以用==来比较字符串。与equalse方法不同的是,==不是比较两个字符串的值是否相等,而是比较几个字符串的引用是否指向同一个实例。如例6-8所示。
【例6-8】
- public class E6_8{
- public static void main(String args[]) {
- String s1="a";
- String s2="a";
- String s3=new String("a");
- String s4=new String("a");
- System.out.println(s1==s2);
- System.out.println(s3==s4);
- System.out.println(s1==s3);
- }
- }
上面的程序段输出:
true
false
false
与上例进行比较,不仅可以看出来==与equals的区别,还可以看到字面量的String的特殊之外。
对于字面量的String,只要字符串的值是相等的,不论有多少个引用都是指向同一块内存,不再另外分配空间。而用new关键字生成的实例则不同,每当用new实例化一次,分配该实例自己的内存空间。上例的存储方式如图所示:
图6-1 s1、s2、s3、s4的区别
下面再通过另一个例子来看String和StringBuffer的区别。
【例6-9】
- public class E6_9{
- public static void main(String args[]) {
- String s1="a";
- StringBuffer sb1=new StringBuffer("a");
- StringBuffer sb2=sb1;
- String s2="a"+"b";
- sb1.append("b");
- System.out.println(s1==s2);
- System.out.println(sb1==sb2);
- }
- }
上例输出的是:
flase
true
上例可以证明这样的结论:String是不可变长的字符串,对String做任何的修改将生成新的字符串,而StringBuffer是可变长的字符串,不论怎么更动还是同一个字符串。
评论
发表评论
-
FileUtils_下载小应用
2009-06-15 13:09 1296FileExportUtils import java.io ... -
Javaz统计中英文个数__解决技巧[20070924]
2009-02-22 21:04 1267import java.util.ArrayList; imp ... -
JAVA模式--看守者模式的小应用
2008-12-03 14:50 1151好久没写了,随便写点东西,不然脑袋都得大掉,还希望 ... -
POI操作excel示例工具类
2008-07-04 09:29 2988由于近期项目要用到excel来转存页面中的表单数据,对poi操 ... -
JAXP解析XML+XSL转换过程
2007-11-21 19:36 15741. 在解析的过程中,此版本用dom4j解析 ... -
通用分页实现及其OO设计探讨——转载
2007-11-10 11:34 1533分页是一种常用的页面数据显示技术,分页能够通过减少页面数据处理 ... -
EJB入门
2007-10-29 18:50 1311java 代码 package com.test ... -
linux下安装jdk和eclipse之java环境
2007-10-18 10:34 41571、去http://java.sun.com/j2se/1.4 ... -
使用JAVA中的动态代理实现数据库连接池
2007-08-16 13:40 1405级别: 初级 刘冬 (winter.lau@163.com), ... -
利用Java动态编译计算数学表达式
2007-08-09 16:03 10255前几天要做一个计算数学表达式的题目,本来计划使用解析表达式的方 ... -
for循环的效率疑问
2007-07-18 13:29 2508编写代码的时候,突然想到 java 代码 java 代码 ...
相关推荐
### JAVA中String与StringBuffer的区别 在Java编程语言中,`String` 和 `StringBuffer` 都是非常重要的类,它们用于处理字符串数据。虽然它们都实现了字符串操作的功能,但它们之间存在一些重要的区别,这些区别...
在Java编程语言中,`String`和`StringBuffer`(在Java 5之后被`StringBuilder`取代,但在多线程环境中仍然使用`StringBuffer`)是处理文本字符串的两个核心类,它们各自有着不同的特性和用途。理解它们的区别对于...
例如,`"yacht1" + "yacht2" + "yacht3" + "yacht4"`在编译时会被合并成一个单独的字符串常量,因此在某些情况下,即使使用`String`也可能达到与`StringBuffer`相近的性能。然而,这种优化并不总是发生,特别是在...
在Java编程语言中,`String`和`StringBuffer`都是用来表示和操作字符串的重要类,但它们在使用场景和性能上有显著的区别。了解这些差异对于编写高效、优化的代码至关重要。 首先,`String`类是不可变的。这意味着...
在Java编程语言中,`String`和`StringBuffer`是用来处理文本字符串的两种不同类,它们各有特点并适用于不同的场景。理解它们之间的区别对于优化代码性能至关重要。 首先,`String`类代表的是不可变的字符串。这意味...
在StringBuilder类的源码中,我们可以看到,它的扩容机制与StringBuffer类相同,也是以16为单位进行扩容的。 String、StringBuffer和StringBuilder的比较 通过上面的分析,我们可以看到,String类的字符串是不可变...
在Java编程语言中,`String`与`StringBuffer`是两个重要的字符串处理类,它们各自具有独特的特性和用途,尤其在面试或笔试中常被提及作为考察应聘者对Java基础知识掌握程度的重要知识点。 ### `String`类:不可变性...
String, StringBuffer 与 StringBuilder 的区别 在 Java 中,String, StringBuffer 和 StringBuilder 三个类都是用于字符操作的,但它们之间有着很大的区别。 首先,String 是不可变类,意味着一旦创建了 String ...
### String与StringBuffer知识点详解 #### 一、String与StringBuffer基本概念 **String**:在Java中,`String`类表示不可变的字符序列,它是最常用的字符串类。一旦创建了一个`String`对象,其内容便无法改变。这...
在Java编程语言中,`String`、`StringBuffer`和`StringBuilder`是处理字符串的三个重要类,它们各自有特定的使用场景和优缺点。理解它们的差异对于编写高效的代码至关重要。 **String类** `String`是不可变的类,...
StringBuffer:字符创变量 StringBuilder:字符创变量 从上面的名字可以看到,String是“字符创常量”,也就是不可改变的对象。对于这句话的理解你可能会产生这样一个疑问 ,比如这段代码:
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据.这个String类提供了数值不可改变的字符串.而这个StringBuffer类提供的字符串进行修改.当你知道字符数据要改变的时候...
StringBuilder 类型是可变的对象,提供了与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。StringBuilder 在大多数实现中比 ...
### String与StringBuffer的区别 在Java编程语言中,`String`和`StringBuffer`是非常重要的两个类,它们分别用于处理不可变(immutable)和可变(mutable)字符串。理解这两个类之间的区别对于有效地管理和操作字符...
从非常细致的角度分析了String和Stringbuffer的主要区别
例如,`str += "hello"`实际上会创建一个新的`String`对象,将原来的`str`与"hello"拼接在一起,而不是在原有基础上进行修改。这种特性使得`String`对象适合于简单的字符串连接和作为常量使用,但频繁的字符串拼接会...
在Java编程语言中,`String`、`StringBuffer`和`StringBuilder`都是用来处理字符串的类,但它们之间存在显著的差异,主要体现在性能、线程安全性和使用场景上。 首先,`String`是最基本的字符串类,它代表的是不可...
在Java编程语言中,String和StringBuffer类都用于处理字符串,但它们在处理字符串拼接时有着显著的区别。本文将详细解析这两个类在拼接字符串时的行为差异。 首先,我们来了解一下String类。String对象在Java中是不...