问题1:
String aa="bbb"; 有这么一说法,如果前面内存里有bbb,那么本次就是引用,就是指向bbb,如果前面没有就创建bbb。我认为好像是错误的,例如:String aa="ddd"; String bb="ddd"; 我更改aa为oooo 那岂不是bb也要更改其值?
这个问题引申出来的问题就是:
String aa=new String("ddd"); String bb="ddd";创建了几个对象。问题2:
String aa = new String("ddd");为什么是申请了2个对象呢,难道aa也算,引用和这个创建对象没关系吧
String aa="bbb"; 有这么一说法,如果前面内存里有bbb,那么本次就是引用,就是指向bbb,如果前面没有就创建bbb。我认为好像是错误的,例如:String aa="ddd"; String bb="ddd"; 我更改aa为oooo 那岂不是bb也要更改其值?
这个问题引申出来的问题就是:
String aa=new String("ddd"); String bb="ddd";创建了几个对象。问题2:
String aa = new String("ddd");为什么是申请了2个对象呢,难道aa也算,引用和这个创建对象没关系吧
解决方案 »
- 使用FatJar导出jar路径问题
- 用IntlliJ IDEA的帮我看看吧Error:null是怎么回事啊
- 我为什么不能把从数据库读出来的字符串赋值给String的变量String str=rs.getString("name");
- java out of memoryException :java heap space
- javascript跟struts结合问题
- 为什么我的HQL查不出结果?
- Struts+Spring+Hibernate??
- j2sdkee的疑惑
- J2EE是开发工具包还是应用程序服务器?和WEBLOGIC的性质有荷异同?
- 有用java压缩过.gz包的没,求助啊!!!
- JAVA编程中的一个小问题
- 如何使用 java +php 给服务器上传 文件
String 是终态类,每次赋值都重新创建一个对象,然后赋值给aa, String aa="ddd"; String bb="ddd"; 我更改aa为oooo 那岂不是bb也要更改其值 bb的值不会改变,前提: String pool 中不存在 ddd对象
问题1 前面 2,后面 1;
问题2 一个事 ddd 字符串常量对象 ,一个事 new 出来的对象存放在 堆中否则就都减一呵呵,等待高手找错
-------------------------------------------------------------------
将aa改为oooo,使aa指向新的的oooo,而bb还是指向ddd,bb的值怎么会变?
1. 在内存“栈”中建立引用 aa(其实就是一个JAVA的引用,保存内存地址)
2. 查找 内存“栈”中是否 已经含有 "ddd",如果有则直接aa-->"ddd";如果没有“ddd”继续。
3. 栈中没有“ddd”,则在内存栈中创建“ddd”。引申意义:栈中的数据时共享的,已经存在的"ddd",不需要重复建立。如果你使用 aa="oooo" 那么aa-->"oooo" ,bb-->"ddd" 。问题2: String aa = new String("ddd");为什么是申请了2个对象呢,难道aa也算,引用和这个创建对象没关系吧。在java中,使用 String aa = new String("ddd"); 表示,在内存“堆”中创建一个对象“ddd”,使用引用aa-->对象“ddd”,一般我们认为引用也是一个对象。所以共有两个对象。aa 这个引用你可以理解为:电视机的遥控开关,"ddd"你理解为:电视机。当你在房间走中的时候,你可以携带遥控器走动,同时可以操纵电视机。而不需要你抱着电视机到处走动。
1.如果字符对象池中有字符串“ddd”,则只会在堆中创建一个字符串对象aa值为“ddd”
2.如果字符对象池中没有字符串“ddd”,首先会在字符串对象池中创建一个字符串对象值为“ddd”,然后在堆中创建一个字符串对象aa值为“ddd”
有人告诉我应该这么理解:
String是一个类,
new String();算一个,"ddd"算一个,引用不算
两个String(aa、bb)都指向String池中的“bbb”,当楼主把aa赋值成oooo时jvm会在String池里找“oooo”,找不到就又建了一个,把引用地址给aa,此时aa指向“oooo",而bb仍然指向“bbb”。
public String(String original)Initializes a newly created {@code String} object so that it represents
the same sequence of characters as the argument; in other words, the
newly created string is a copy of the argument string. Unless an
explicit copy of {@code original} is needed, use of this constructor is
unnecessary since Strings are immutable.初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。由于 String 是不可变的,所以无需使用此构造方法,除非需要 original 的显式副本。
String是一个类,
new String();算一个,"ddd"算一个,引用不算完全错误。5楼完全正解。
如果无法理解 请多看几遍另外 "一般我们认为引用也是一个对象" 这个说法就是错的 引用是引用 对象是对象 要区分开来
的确,5楼说的不正确
String aa="ddd"与String aa=new String("ddd");是不同的
后者是jvm会在String pool中创建"ddd"对象,然后在堆中创建另一个"ddd"对象由aa引用,这也就是为什么为说String aa=new String("ddd");会创建2个对象的缘故。
前者是直接在string pool中查找是否有符合equals()返回true的String,如果有,那么直接指向string pool而不再在堆中创建"ddd"对象.也就是说
String aa=new String("ddd");//该句创建2个对象
String bb=new String("ddd");//该句由于string pool中已经存在"ddd"那么只会在堆中创建一个"ddd"对象由bb引用
String cc="ddd";//该句由于String pool中已经存在"ddd",则直接指向String pool中的"ddd",不会创建对象,只会创建引用
现在应该明白了吧
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
// The array representing the String is bigger than the new
// String itself. Perhaps this constructor is being called
// in order to trim the baggage, so make a copy of the array.
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off+size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}我觉得楼上对的,上面是String其中一个构造器
当 String aa = "ddd";时
如果静态池中又"ddd"就指向它,如果没有就先创建"ddd"到静态池
所以String aa = "ddd"和String bb = "ddd"他们指向的地址是一样的
如果这个时候aa = "ccc"那就再静态池创建"ccc"然后aa指向"ccc",此时bb还是指向"ddd"
再看string 的两个构造器:------------------------------------------------------------------------------
/**
* Initializes a newly created <code>String</code> object so that it
* represents an empty character sequence. Note that use of this
* constructor is unnecessary since Strings are immutable.
*/
public String() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}
/**
* Initializes a newly created <code>String</code> object so that it
* represents the same sequence of characters as the argument; in other
* words, the newly created string is a copy of the argument string. Unless
* an explicit copy of <code>original</code> is needed, use of this
* constructor is unnecessary since Strings are immutable.
*
* @param original a <code>String</code>.
*/
public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
// The array representing the String is bigger than the new
// String itself. Perhaps this constructor is being called
// in order to trim the baggage, so make a copy of the array.
v = new char[size];
System.arraycopy(originalValue, original.offset, v, 0, size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
------------------------------------------------------------------------------
由存储区域分析:
可见在JAVA里面使用的是char[] 数组存储的String 。(在JAVA中数组也是一种隐式的对象,它存在于"java.unil.Arrays"中),现在问题来了。
1)请问char[]数组存储在什么地方?
2)别告诉我说是存储在String pool 里,请问String pool 位于RAM的哪个区域?
3)String pool是个什么破玩意儿,别"google it,百度之"一些垃圾帖就来误人子弟可以吗?不知道没关系,我告诉你,其实就是:静态存储区。即char[] 中的每一个char都是以二进制的形式存储在 RAM上特定的区域(这个区域不是内存堆也不是内存栈)在这个区域里面,数据是共享的,即:你创建过了"ddd"就没有必要再创建了,直接从这个区域取就可以了,提高程序运行效率。回到刚才的问题:
String aa=new String("ddd"); String bb="ddd"; 创建几个对象?aa是引用-->存储在"内存栈",它指向一个char['d','d','d'](数组是隐式对象)"ddd"-->存储在"静态存储区",理解为:一个char['d','d','d'](数组是隐式对象)new String("ddd")-->既然有new关键字,就在内存堆中开辟一个String "ddd"对象。请问:一共有几个对象,答:两个(1个String对象 ,1个char[]数组(隐式)对象)。
new String("ddd") 内存堆上存储了1个String对象
"ddd" 内存"静态存储区"存了1个char[]数组:1个 (隐式)对象
aa是一个引用 指向"ddd" 它实际上指向一个char['d','d','d']数组隐式对象
PS:引用当然不是对象,但是它指向1个char[]数组:1个 (隐式)对象,你就理解为:引用已经指向了一个对象,加上 new String("ddd"),难道不是两个对象?