- 浏览: 1559011 次
- 性别:
- 来自: 吉林
文章分类
- 全部博客 (624)
- C/C++ (33)
- Java (181)
- 网络相关 (7)
- 我爱篮球 (3)
- 也爱足球 (4)
- 杂谈 (1)
- 系统架构 (3)
- Web Service (14)
- Framework (3)
- 系统命令 (8)
- 管理平台相关 (8)
- 其它 (35)
- Websphere (1)
- Struts2 (24)
- Hibernate (16)
- Spring (23)
- javascript (20)
- jquery (23)
- html/css/div (28)
- 数据库 (40)
- JavaWeb (27)
- 设计模式 (2)
- 文档编写 (3)
- SVN (5)
- Ant (1)
- Maven (13)
- 软件项目管理 (8)
- AOP (1)
- kindeditor (1)
- JSON (2)
- Servlt/JSP (4)
- WordXML (2)
- XML (12)
- 面试相关 (7)
- Tomcat (11)
- 性能与调优 (29)
- 职业发展 (2)
- 操作系统 (7)
- AJAX (2)
- DWR (1)
- Eclipse (12)
- 持续集成 (3)
- 批处理命令 (1)
- Mozilla Rhino (2)
- 新鲜技术 (18)
- Apache mina (2)
- 底层技术 (18)
- Linux (22)
- 新鲜技术,IT历史 (1)
- 敏捷开发 (1)
- 版本控制 (5)
- 较火技术 (7)
- 集群 (2)
- Web前端 (13)
- 报表工具 (3)
- 网站架构 (5)
- 大数据 (8)
- 分布式存储 (5)
- 云计算 (8)
- TCP/IP协议 (1)
- 负载均衡 (3)
- 硬件 (1)
- 表现层技术 (3)
- Velocity (3)
- jvm (6)
- 并发编程 (10)
- hadoop (8)
- 数据结构和算法 (12)
- 计算机原理 (1)
- 测试驱动开发-TDD (3)
- 开发技巧 (1)
- 分词器 (1)
- 项目构建工具 (2)
- JMX (4)
- RMI (1)
- 测试技术 (22)
- 网络完全 (1)
- Git (4)
- apache开源包 (4)
- Java常用 (1)
- mock (2)
- OSGi (2)
- MongoDB (1)
- JBPM (1)
- Storm (3)
- mysql (2)
- telnet (1)
- 正则表达式 (1)
- bootstrap (4)
- Apache ActiveMQ (1)
- redis (9)
- Nginx (2)
- rsync+inotify文件同步 (2)
- testng (1)
- 原型设计工具 (1)
- 工程能力 (1)
- 风险控制 (3)
- ibatis (1)
- 分布式 (4)
- 安全技术 (1)
- 计算机基础 (4)
- 消息中间件 (1)
- UML (2)
最新评论
-
u012236967:
java命令执行jar包(里面的main函数)的方式(包括依赖其它的jar包问题) -
世界尽头没有你:
Selenium自动化测试从入门到精通(Java版)百度网盘地 ...
自动化测试工具 Selenium WebDriver 入门教程(针对主流浏览器) -
小小西芹菜:
我喜欢代码简洁易读,服务稳定的推送服务,前段时间研究了一下go ...
dwr实现Reverse Ajax推送技术的三种方式 -
hellozhouqiao:
楼主,请教一点问题.现在我们需要在excel 的页脚里面加上图 ...
FreeMaker + xml 导出word(处理目录,图片和页眉页脚问题) -
乱在长安:
使用Timer会有各种各样的问题好嘛?!书上推荐使用Sched ...
DelayQueue (ScheduledThreadPoolExecutor调度的实现)
字符串常量池由String实例管理维护,每一个类的.class文件对其进行引用,所以无论在哪一个类中声明相同的字符串常量,使用==操作返回的都是true。
转自:http://topic.csdn.net/u/20090519/18/7b8cf7ef-bc06-4d26-8a2c-692eb0562231.html
作者:zangxt
String类是Java中很重要的一个类,在此总结一下这个类的特别之处。下面的相关资料翻译自《java语言规范》(第三版)和《java虚拟机规范》(第二版),有的直接摘引了原文。下面的代码都是用SUN jdk1.6 javac来编译。
1.String literal,这里将它翻译为字面常量,它由双引号包围的0个或多个字符组成,比如"abc","Hello World"等等。一个String字面常量总是引用相同的String实例,比如"abc","abc"两个常量引用的是同一个对象。
程序测试:
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
另一个包:
package other;
public class Other { static String hello = "Hello"; }
输出:
true true true true false true
结论有六点:
1) 同一个包下,同一个类中的相同的String字面常量表示对同一个String对象的引用。
2) 同一个包下,不同的类中的相同的String字面常量表示对同一个String对象的引用。
3) 不同包下,不同类中的相同String字面常量同样表示对同一个String对象的引用。
4) 通过常量表达式计算的String,计算在编译时进行,并将它作为String字面常量对待。
5) 通过连接操作得到的String(非常量表达式),连接操作是运行时进行的,会新创建对象,所以它们是不同的。
6) 显式的对一个计算得到的String调用intern操作,得到的结果是已经存在的相同内容的String字面常量。
补充说明:
1)像这样的问题,String str = "a"+"b"+"c"+"d";
运行这条语句会产生几个String对象?1个。参考上面第5条,通过常量表达式得到的String 是编译时计算的,因此执行这句话时只有"abcd"着一个String对象存在。
常量表达是的定义可以参考java语言规范。另例:
final String str1 = "a";
String str2 = str1+"b";
执行第二句话会有几个String对象产生?1个。因为str1是常量,所以str1+"b"也是常量表达式,在编译时计算。
遇到这种问题时,不要说它依赖于具体的编译器或者虚拟机实现,因为这就是规范里有的。一般的说,java的编译器实现应该遵守《java语言规范》,而java虚拟机实现应该遵守《java虚拟机规范》。
2)不要这样使用字符串:
String str = new String("abc");
参考文档中的说明:
String
public String(String original)
初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。由于 String 是不可变的,所以无需使用此构造方法,除非需要 original 的显式副本。
参数:
original - 一个 String。
注意:无需使用此构造方法!!!
3)单独的说明第6点:
String str = new String("abc");
str = str.intern();
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串引用。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
很明显,在这个例子中"abc"引用的对象已经在字符串池中了,再调用intern返回的是已经存在池中内容为"abc"的字符换对象的引用。在上面的例子中也说明了这个问题。
2. String类的实例表示表示Unicode字符序列。String字面常量是指向String实例的引用。(字面常量是“引用”!)
3.String转换
对于基本类型先转换为引用类型;引用类型调用toString()方法得到String,如果该引用类型为null,转换得到的字符串为"null"。
4. String链接操作“+”
如果“+”操作的结果不是编译期常量,将会隐式创建一个新的对象。为了提高性能,具体的实现可以采用
StringBuffer,StringBuilder类对多个部分进行连接,最后再转换为String,从而避免生成再丢弃中间的String对象。为
了达到共享实例的目的,编译期常量总是“interned”的。
例子:
String a = "hello ";
String b = a+1+2+"world!";
反汇编结果:
0: ldc #2; //String hello
2: astore_1
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: iconst_1
15: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
18: iconst_2
19: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
22: ldc #7; //String world!
24: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_2
实际就是
String b = new StringBuilder().append(a).append(1).append(2).append("world").toString();
这里就使用StringBuilder来避免中间临时String对象的产生而导致性能下降。
补充例子,下面的两个例子主要是对编译时常量做一个说明:
1)
String c = "c";
String str = "a"+"b"+c;
和
2)
String c = "c";
String str = c+"a"+"b";
1)中,str="a"+"b"+c;编译器分析是会把"a"+"b"作为编译时常量,生成字面常量"ab",所以实际执行这句话时,链接的是"ab"和c。实际相当于执行了
String str = new StringBuilder().append("ab").append(c).toString();
2)中,String str = c+"a"+"b";
编译器分析到c为变量,后面的"a"+"b"就不会作为编译时常量来运算了。
实际运行时相当于执行
String str = new StringBuilder().append(c).append("a").append("b").toString();
5.String对象的创建:
1) 包含String字面常量的类或者接口在加载时创建表示该字面常量的String对象。以下两种情况下不会创建新String对象。
a) 一个相同的字面常量已经出现过。
b) 一个相同内容的字符串已经调用了intern操作(比如经过运算产生的字符串调用intern的情形)。
2) 非常量表达式的字符串连接操作有时会产生表示结果的String对象。
3) String字面常量来自类或接口的二进制表示中(也就是class文件中)的CONSTANT_String_info 结构。CONSTANT_String_info结构给出了构成字符串字面常量的Unicode字符序列。
4) 为了生成字符串字面常量,java虚拟机检查 CONSTANT_String_info结构给出的字符序列:
a) 如果与CONSTANT_String_info结构中给出的字符换内容相同的串实例已经调用过String.intern,得到的字符串字面常量就来自该串的同一实例。
b) 否则,根据CONSTANT_String_info 中的字符序列创建一个新的字符串实例,然后调用intern方法。
例子:一个SCJP题目
11. public String makinStrings() {
12. String s = “Fred”;
13. s = s + “47”;
14. s = s.substring(2, 5);
15. s = s.toUpperCase();
16. return s.toString();
17. }
How many String objects will be created when this method is invoked?
答案是3个。上面已经说明,"Fred","47"是字符串字面常量,它们在在类加载时创建的。这里题目问,方法调用时(!)有多少个String对象被创建,两个字面常量自然不包括在内。3个是:"Fred47","ed4","ED4"。
6.String与基本类型的包装类比较
相同点,它们都是不变类,使用"=="判断时可能会有类似的性质。
在java 5之后,java增加了自动装箱和拆箱功能。因此,就有了这样的性质:
Integer i = 5;
Integer j = 5;
System.out.println(i == j);
结果:true.
这表面上看来是和String相同点,但其实现是极为不同的。这里作为一个不同点来介绍。
众所周知,自动装箱是这样实现的:
Integer i = 5;
相当于
Integer i = Integer.valueOf(5);//注意不是new Integer(5),这就无法满足java语言规范中的约定了,约定见本文最后
而在Integer中,静态的创建了表示从-128~+127之间数据的Integer对象,这个范围之内的数进行装箱操作,只要返回相应的对象即可。因此
Integer i = 5;
Integer j = 5;
我们得到的是同一个对象。这是通过类库的设计来实现的。而String的共享是通过java虚拟机的直接支持来实现的,这是它们本质的不同。
这是Integer类中的部分代码:
private static class IntegerCache {
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
关于基本类型的装箱,Java语言规范中有如下说明:
如果被装箱的变量p为true,false,一个处于\u0000~\u007f之间的byte/char,或一个处于-128~+127之间的int
/short,令r1和r2为对p的任何两个装箱操作的结果,则r1==r2总是成立的。理想的情况下,对一个基本类型变量执行装箱操作,应该总是得到一
个相同的引用。但在实践中,在现存的技术条件下,这是不现实的。上面的规则是一个注重实效的折衷。
最后一点,要理解java的方法调用时的传参模型:java中只有pass by value。(不明确这一点,就有乱七八糟的解释,比如典型的Java既有传值,又有传引用,String很特殊……)
//改变参数的值?
public void test(String str){
str = "Hello";
}
//改变参数的值?
public void test(StringBuffer buffer){
buffer = new StringBuffer("Hello");
}
//交换两个Integer?
public void swap(Integer a,Integer b){
Integer temp = a;
a = b;
b = temp;
}
这三个方法全是没有意义的方法。
发表评论
-
Java SE7新特性之二进制字面量
2016-12-14 22:53 787Java SE 7中, 整数类型(byte, shor ... -
浮点数为什么不精确?为什么银行的金额不能用浮点数计算
2016-12-14 22:52 1941浮点数为什么不精确? 其实这句话本身就不精确, 相对精确一 ... -
计算机是如何计算乘法除法的(实际上都是转换为二进制加法计算)
2016-12-14 22:46 6578http://blog.csdn.net/blues1021 ... -
什么是补码、反码、负数在计算中如何表示
2016-12-14 22:39 868负数在计算机中如何表 ... -
Math.abs()绝对值取到的数不一定是正数
2016-12-14 22:37 1204Math.abs() 注释:Note that if th ... -
用BigInteger实现大素数生成算法
2016-12-06 16:42 1786转自:http://www.cnblogs.co ... -
加密(AES)、公私钥(PKI)、摘要(DIGEST)、签名(SIGNATURE)、证书(CERT)的形象解释和组合用法
2016-09-15 18:19 92671.鲍勃有两把钥匙,一把是公钥,另一把是私钥。 ... -
RSA加密公私钥生成工具(openssl)
2016-09-15 13:00 1131https://www.openssl.org/source/ ... -
RPC原理详解
2016-06-23 20:47 537RPC 功能目标 RPC 的主要功能目标是让构建分布式计算 ... -
Java并发之CountDownLatch、CyclicBarrier和Semaphore
2016-06-23 20:36 1365这次说一下 JUC 中的同步器三个主要的成员:CountDo ... -
线程间协作的两种方式:wait、notify、notifyAll和Condition
2016-06-23 20:35 520在前面我们将了很多关于同步的问题,然而在现实中,需要线程之 ... -
The final local variable xxx cannot be assigned, since it is defined in an enclo
2016-04-24 17:42 1548本文就自己编程时候遇到的一个问题,简要描述一下,并提出解决 ... -
一个奇葩的excel中无法trim的“空格”的问题
2016-03-29 16:21 1873太奇怪了。打印出来的命名是空格,就是 trim() 不管用。 ... -
List深度复制
2016-02-17 09:34 2627昨天弄了一个类似List<Map<String, ... -
Eclipse导入 jar 源码乱码问题
2015-12-15 19:43 829http://blog.csdn.net/laiwenqian ... -
Java高并发编程的各种陷阱
2015-07-25 17:49 965www.iteye.com/blogs/subjects/ja ... -
ASM介绍(java字节码操作利器)
2015-06-10 20:46 4299转自:http://www.ibm.com/de ... -
JDK 7 中的 Fork/Join 模式(并发处理)
2015-06-03 19:47 945转自:http://www.ibm.com/dev ... -
Java常见内存溢出异常分析
2015-06-03 16:36 782转自:http://www.iteye.com/news/3 ... -
dom4j解析带有命名空间的xml
2015-04-09 21:23 5465Element rootEle = resultDoc.g ...
相关推荐
81 话题14 井然有序——运算顺序的详细挖掘 86 话题15 异曲同工——交换变量的3种方式 90 话题16 择木而栖——开关选择表达式switch的类型内幕 95 第3章 String类 103 话题17 来龙去脉——“+”是怎样连接字符串的?...
1.7.5为字符串容器声明常量,不要直接把字符封装在双引号" "里面。... 14 1.7.6 用StringBuilder代替使用字符串连接符 “+”. 14 1.7.7 避免在循环体里声明变量,... 15 1.8 Hashtable. 15 1.8.1 Hashtable机理....
4.2.2 字符串的length()方法与性能优化 4.2.3 tochararray()方法与性能优化 4.2.4 字符串转化为数字 4.3 系统i/o类 4.3.1 java语言中输入/输出流 4.3.2 通过系统缓冲流类提高i/o操作效率 4.3.3 通过自定制缓冲区提高...
6.1 字符串类String 108 实例79 创建字符串类 108 实例80 如何使用charAt()方法计算重复字符 109 实例81 按字母顺序比较大小 110 实例82 首尾相连 111 实例83 字符串间的比较 112 实例84 字符集...
6.1 字符串类String 108 实例79 创建字符串类 108 实例80 如何使用charAt()方法计算重复字符 109 实例81 按字母顺序比较大小 110 实例82 首尾相连 111 实例83 字符串间的比较 112 实例84 字符集的解码方法 113 实例...
6.1 字符串类String 108 实例79 创建字符串类 108 实例80 如何使用charAt()方法计算重复字符 109 实例81 按字母顺序比较大小 110 实例82 首尾相连 111 实例83 字符串间的比较 112 实例84 ...
6.1 字符串类String 108 实例79 创建字符串类 108 实例80 如何使用charAt()方法计算重复字符 109 实例81 按字母顺序比较大小 110 实例82 首尾相连 111 实例83 字符串间的比较 112 实例84 字符集的解码方法 113 实例...
答:String是不可变的对象,每次对String类型进行改变都相当于产生了一个新的对象,StringBuffer是可变的字符序列,所以如果要经常改变某个字符串的话建议使用StringBuffer。 list、set、map问题? 答:set 不允许...
6.1 字符串类String 108 实例79 创建字符串类 108 实例80 如何使用charAt()方法计算重复字符 109 实例81 按字母顺序比较大小 110 实例82 首尾相连 111 实例83 字符串间的比较 112 实例84 字符集的解码方法 ...
6.3 特殊字符串 6.3.1 全限定名 6.3.2 简单名称 6.3.3 描述符 6.4 常量池 6.4.1 constant_utf8_info表 6.4.2 constant_integer_info表 6.4.3 constant_float_info表 6.4.4 constant_long_...
6.3 特殊字符串 6.3.1 全限定名 6.3.2 简单名称 6.3.3 描述符 6.4 常量池 6.4.1 CONSTANT_Utf8_info表 6.4.2 CONSTANT_Integer_info表 6.4.3 CONSTANT_Float_info表 6.4.4 CONSTANT_Long_info表 ...
6.3 特殊字符串 6.3.1 全限定名 6.3.2 简单名称 6.3.3 描述符 6.4 常量池 6.4.1 CONSTANT_Utf8_info表 6.4.2 CONSTANT_Integer_info表 6.4.3 CONSTANT_Float_info表 6.4.4 CONSTANT_Long_...
6.3 特殊字符串 6.3.1 全限定名 6.3.2 简单名称 6.3.3 描述符 6.4 常量池 6.4.1 CONSTANT_Utf8_info表 6.4.2 CONSTANT_Integer_info表 6.4.3 CONSTANT_Float_info表 6.4.4 CONSTANT_Long_...
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要...
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变...
6.7.4 常量池 158 6.7.5 编译指示池 160 6.7.6 函数池 162 6.7.7 指标限度 163 6.8 WMLScript指令集 164 6.8.1 约定规则 164 6.8.2 致命的错误 164 6.8.3 优化 164 6.8.4 符号约定 165 6.8.5 指令 165 6.9 字节码...
1.3.9 字符串常见操作 21 1.3.10 几个常用的数学函数 27 1.4 .NET的面向对象之门 27 1.4.1 继承——“子承父业” 28 1.4.2 委托——“任务书” 35 1.4.3 事件——“年终分红” 42 1.4.4 反射——“解剖” 49 1.5 ...
第5章数组与字符串200 5.1数组200 5.1.1一维数组的声明200 5.1.2一维数组的创建201 5.1.3一维数组的使用202 5.1.4二维数组的声明204 5.1.5二维数组的创建205 5.1.6二维数组的使用207 5.1.7for~each循环208 ...
1.3.9 字符串常见操作 21 1.3.10 几个常用的数学函数 27 1.4 .NET的面向对象之门 27 1.4.1 继承——“子承父业” 28 1.4.2 委托——“任务书” 35 1.4.3 事件——“年终分红” 42 1.4.4 反射——“解剖” 49 1.5 ...