java中的String

知识点太混乱,一段一个理解,最后我理解透了



-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

关于 String a=new String(“abc”); 究竟产生几个String对象实例问题的讨论?

首先说明:
问此题的人,其实是草包一个,是半瓶水而已,就像问中国究竟有多少人一样?中国究竟有多少人呢?这问题本身就有问题,你是说中国现在有多少人,还是新中国成立的时候有多少人?还是全球有多少中国人?
问问题之前先要明白环境是什么?上下文是什么?那么java 也一样,你不了解java语言本身,或者jvm 本质很难回答看似简单,其实并非简单的问题。往往简单的问题,比较难回答,为什么呢?因为简单的问题没有环境约束,它没有限制出环境。任何东西脱离了周围环境,就没有它存在的价值,就好比 1+1 等于2 如何证明它一样。怎么证明呢?这个问题,你首先考虑的并不是证明不证明的问题。我们要考虑它是怎么来的?这个还真难考虑。不过怎么去证明它,首先你要知道,1+1 是否是规定就等于2,如果规定的东西,不要证明,我规定了1+1 等于二 那么证明它就显得很苍白,原因很简单规定必证明的优先权高,没有方法啊,你总不能越过规定吧,这是自然规律。首先你要这自然规律的约束下发展其自己,就像你活着地球上一样,你要看清地球本身,你光这地球上是不行的。
好废话少说,开始我们的讨论:
我定义了两个类
类一:StringDemo1
public class StringDemo1 {
public static void main(String[] args) {
String a=new String("abc");
}
}
类二:StringDemo2
public class StringDemo2 {
public static void main(String[] args) {
String b="abc";
String a=new String("abc");
}
}
这是很简单的两个类,没有什么可解释的,唯一不同是StringDemo2 比StringDemo1多加了一行代码 String b="abc"; 换句话说是加了一个上文的环境。
有人就会问我这有什么关系呢?那么请看我下面的分析,很简单,我不会像论坛上的一些人一样,故意那么研究得深刻,把一些不明白的人往火坑里推,显得自己很高深似的。
开始动手:
步骤一:
Javac 编译两个类(各位自己这命令行编译,这里就不列出了了)
步骤二:
javap -c  使用此命令,这个命令可能一般人就没有使用过,自己上网查查,都是jdk命令;此命令使用的例子:javap -c StringDemo1  javap -c StringDemo2  分别这命令行敲上面的两条命令
好,下面的是我cmd 命令行的输出(你自己的输出应该也差不多)
注:我用红色的字体来注释行:

D:\String>javac StringDemo1.java

D:\String>javac StringDemo2.java

D:\String>javap -c StringDemo1
Compiled from "StringDemo1.java"
public class StringDemo1 extends java.lang.Object{
public StringDemo1();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class java/lang/String 此句new 了一个对象,产生了一个对象,毫无疑问
   3:   dup  
   4:   ldc     #3; //String abc  此句将String abc常量值从常量池中推送至栈顶 ,那这算不算对象,当然算了,只不过时创建时间可能不是现在哦 “#” 后面的为索引地址,我们可以从索引地址可以看到,这里有#2,#3,那么String a=new String("abc");
这是一句代码哦,可以看出此题目中这此句产生了两个String 对象。
   6:   invokespecial   #4; //Method java/lang/String."<init>":(Ljava/lang/Strin
g;)V
   9:   astore_1
   10:  return
}

D:\String>javap -c StringDemo2
Compiled from "StringDemo2.java"
public class StringDemo2 extends java.lang.Object{
public StringDemo2();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String abc  此句将String abc常量值从常量池中推送至栈顶
   2:   astore_1 //存储变量,也就是赋值操作
   3:   new     #3; //class java/lang/String  此句产生一个对像
   6:   dup
   7:   ldc     #2; //String abc   这里很有意思哦,我们看到 #2 索引地址已经出现过来,对了,上面 code 0: 就出现过了 他只不过是把地址,引用要过来了,并没有产生String对象,也就是从Stirng常量池里面要了个地址,自己知道地址就知道他的家了哦,
那么这里就有一个问题呀?什么问题?那这样的话,多个Sting变量有可能引用一个Strng实例,那么会产生String共享不安全的问题,多线程的情况下。这个不要担心了,String是线程安全的,因为它是final 类型的,没有办法改变!哦,恍然大悟!原来这样,怪不得sun这样做,有利于减少内存浪费啊(此问题其实还会产生String碎片,那就扯远了和StringBuffere有关系了,暂不讨论)。那么这么说来String a=new String("abc"); 此句产生了一个String对象。
   9:   invokespecial   #4; //Method java/lang/String."<init>":(Ljava/lang/Strin
g;)V
   12:  astore_2
   13:  return
}


总结一下吧:
String a=new String("abc");这样的问题没有什么意义,脱离上下文的环境本身就没有意思了。从上面的分析,我们得出两个结论,第一个结论,也就是StringDemo1 中的请求,此句产生两个对象,其中一个特殊的String对象在String常量池里,另外一个就是对象堆中的(这个普通的Java类一样)
第二个结论,也就是StringDemo2, 那一句只产生了一个对象,只有堆中的一个对象,因为上网已经产生了一个String常量对象,后面就不产生了,直接使用地址索引了。
String 是一个特殊的数据类型,说白了它是从简单到对象类型过渡的一种类型;它既有简单类型那样的快速又有对象类型的特性。对应String的不足,那么String家族里面已经有了补充的类,完善的类,StringBuffere 各位不用担心,StringBuffere完全面向对象了,怎么证明呢?很简单
String a=“abc”; 这样可以直接复制常量值个String类型的。就好像简单类型的可以使用字面量来直接初始化 一样。例如 int a=123;

StringBuffere a=“abc”; 这样就不行啦


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

String a  = "av";  //生成一个字符串对象,放在常量池中。
String b = "av"; //不会在池中生成对象
String c = new String("av"); //生成一个av对象,放在堆中
String d = new String("av"); //又会在堆中生成个对象
String e = st.intern();  //他会从常量池中找字符串对象的值是否等于st这个值,如果有,就返回池中对象,没有就往池中生成一个。程序中,已经有了,所以不会在生成

话说String是一个神奇的东西,又能在常量池中生成对象(String s = "av"),又能在堆中生成对象(String s = new String("av"))

在池中生成对象的时候,还要先看看池中有没值一样的,有就不生成了,直接指向就行,而堆中生成,永远都新生成,绝不含糊。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

String s = new String("av")  生成了几个对象啊?

这个第一段就解释了。总的来说, 要看上下文,也就是看下  av 在池中有木有存在。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

http://rednaxelafx.iteye.com/blog/774673                   这个连接讨论的激烈,评论是亮点。

博主有趣,把String s = new String(“av”)  分得更细,av在类加载的时候就已经生成一个实例,运行时只生成了堆中的那个,所以得出了

String s = new String(“av”) 

String s1 = new String(“av”) 

只生成2个对象的结论。(下段是原话)


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

6 楼 RednaxelaFX 2010-09-29   引用
maomaolingyu 写道
  首先谢谢lz这么细心的讲解,不过我还是想问一句.
1. String s1 = new String("xyz"); 
   2. String s2 = new String("xyz"); 
在运行时这两句只创建2个实例,能讲的简单的吗?
最初我认为是3个,xyz共享一个,s1,s2各一个, 但是太笨还是没看懂只有2个实例的的创建过程..谢谢赐教.wait

“在运行时”要分为两部分看:类加载阶段和实际执行时。

类加载对一个类只会进行一次。"xyz"在类加载时就已经创建并驻留了(如果该类被加载之前已经有"xyz"字符串被驻留过则不需要重复创建用于驻留的"xyz"实例)。驻留的字符串是放在全局共享的字符串常量池里的。

Java代码   收藏代码
  1. String s1 = new String("xyz");  
  2. String s2 = new String("xyz");  

在这段代码后续被执行的时候,"xyz"字面量对应的String实例已经固定了,不会再被重复创建,所以这段代码无论执行多少次都只会在原本的基础上 新创建2个String实例而已。这是从概念上的Java/JVM来说。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值