最近看书。
对于java来说,一切对象的创建都是在堆空间里,而在栈空间进行引用但是对于特殊的基本类型来说,它是在栈空间直接赋值并进行操作,所以对于int i=23;这样的语言可以解释为:
1。栈空间里面要求对类型的生命周期有明确指定,所以必须在int类型初始化
2。这也正好对应拉java的后期绑定的机制,因为要对小数值的基本类型进行更加行之有效的操作,所以把他放在栈空间,而在栈空间,自然不能应用到后期绑定,也就是说int类型的对象也一样是在堆空间创建。而在栈空间只是一个指针直接操作。我的疑问是,对于
Integer i=new Integer(23);
这个语句的理解是不是说先在栈空间进行整数int=23的初始化,然后又在堆空间创建一个Integer类型(是否在堆空间也划分拉值为23的内存空间?),再在栈空间对堆空间的Integer进行引用(如果是以上,为什么一开始直接在堆空间划分空间就好拉?还要多一步在栈空间的操作?)。这样进行
栈空间操作-》堆空间操作-》栈空间引用 不是有点感觉多此一举么?因为在栈空间划分拉内存,又在堆空间又划分一块值一样的内存。
而对于字符串 string="fejaio" 直接进行初始化这样,它是在栈空间进行的么,但是它不属于基本类型啊?
又对于String s=new String("fejaio") 这里创建的2个对象:pool对象和heap对象。那么最初的pool对象根据一切对象都在堆空间内,那么是不是说常量池也是在堆空间里的呢?那何必再创建一个heap对象,它本身不就是heap对象喽?而如果常量池不是在堆空间里,那么所谓的pool对象不是跟一切对象都在堆空间里相冲突?
对于java来说,一切对象的创建都是在堆空间里,而在栈空间进行引用但是对于特殊的基本类型来说,它是在栈空间直接赋值并进行操作,所以对于int i=23;这样的语言可以解释为:
1。栈空间里面要求对类型的生命周期有明确指定,所以必须在int类型初始化
2。这也正好对应拉java的后期绑定的机制,因为要对小数值的基本类型进行更加行之有效的操作,所以把他放在栈空间,而在栈空间,自然不能应用到后期绑定,也就是说int类型的对象也一样是在堆空间创建。而在栈空间只是一个指针直接操作。我的疑问是,对于
Integer i=new Integer(23);
这个语句的理解是不是说先在栈空间进行整数int=23的初始化,然后又在堆空间创建一个Integer类型(是否在堆空间也划分拉值为23的内存空间?),再在栈空间对堆空间的Integer进行引用(如果是以上,为什么一开始直接在堆空间划分空间就好拉?还要多一步在栈空间的操作?)。这样进行
栈空间操作-》堆空间操作-》栈空间引用 不是有点感觉多此一举么?因为在栈空间划分拉内存,又在堆空间又划分一块值一样的内存。
而对于字符串 string="fejaio" 直接进行初始化这样,它是在栈空间进行的么,但是它不属于基本类型啊?
又对于String s=new String("fejaio") 这里创建的2个对象:pool对象和heap对象。那么最初的pool对象根据一切对象都在堆空间内,那么是不是说常量池也是在堆空间里的呢?那何必再创建一个heap对象,它本身不就是heap对象喽?而如果常量池不是在堆空间里,那么所谓的pool对象不是跟一切对象都在堆空间里相冲突?
fejaio" 直接进行初始化这样,它是在栈空间进行的么,但是它不属于基本类型啊?
我的理解是一堆的字符,但我觉得 string="fejaio" 中的"fejaio" 是在堆中
对于第二个问题,java中的String类型比较特殊,String string="fejaio";JVM会先定义一个名为string的String类的对象引用变量,然后在栈中查找有没有存放值为"fejaio"的地址,如果没有,则开辟一个存放字面值为"fejaio"的地址,接着创建一个新的String类的对象string。
对于第三个问题,String s=new String("fejaio")这是一定会在堆中创建对象,与fejaio是否在栈空间中就没有关系了
不过测起来很简单嘛,把jvm的栈和堆内存都设合理一点,然后生成大量数据,看看是栈溢出还是堆溢出不就行了
认为是堆,就把堆设小点,栈设大点,
认为是栈,就把栈设小点,堆设大点。
实践出真知撒
对于第二个问题,我是不是可以认为String是在栈空间开辟,并给值,而在堆空间创建对象,那堆空间创建对象,是不是还要重复开辟内存给值呢
int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。 这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。 要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。 String是一个特殊的包装类数据。可以用:
String str = new String("abc");
String str = "abc";
两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。 比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
可以看出str1和str2是指向同一个对象的。
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new的方式是生成不同的对象。每一次生成一个。 因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。 另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。 由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
栈 ┊ 堆
┈┈┈┈┈┈┈┈┊┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
┌─────┐ ┊ ┌────────────┐
│Integer i ┼───┼→ new Integer │
└─────┘ ┊ ├────────────┤
┊ │ private int value = 23;│
┊ │ │
┊ └────────────┘
┌─────┐ ┊
│int i = 23│ ┊
└─────┘ ┊
┊
int[] a={1,2,3,4}
这个a是放在堆中还是在栈中?
int[] b=new int[5];这个b又是放在哪里?
一个array怎么能在栈中呢。
StringPool ┊ 栈 ┊ 堆
┈┈┈┈┈┈┈┈┈┈┈┊┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
┌──────┐ ┊ ┌─────┐ ┊
│"fejaio" ←┼────┼ String t │ ┊
├──────┤ ┊ └─────┘ ┊
├──────┤ ┊ ┌─────┐ ┊ ┌───────────────┐
├──────┤ ┊ │ String s ┼───┼→ new String │
├──────┤ ┊ └─────┘ ┊ ├───────────────┤
├──────┤ ┊ ┊ │private char[] value = { │
├──────┤ ┊ ┊ │ 'f', 'e', 'j', 'a', 'i', 'o'│
┊ ...... ┊ ┊ ┊ │}; │
┊ ┊ └───────────────┘
┊ ┊
String s = new String("fejaio");
String str1 =new String ("abc");
String str2 =new String ("abc");
既如上有共同的pool对象"abc",但被复制到堆空间2次,创建拉2个String,在这里想问下,这个常量池是位于哪里?
String t = "fejaio";
String s = new String("fejaio");
这里是两步:
1:栈指针指向pool里面的pool对象"fejaio"
2:栈指针指向堆空间里面的String对象
3: 堆空间里面存放的String对象复制于pool里面的pool对象。并且是以char[]的形式(在这里,对应8楼的
“字面常量在栈空间存值,在堆空间创建对象,但不会重复开辟内存,只是定义一个对象引用指向栈空间的字面常量”
这一句我有不同看法,既然是复制pool里面的对象到堆里面,所谓复制,应该是把值也复制过来吧。既然有值,难道在堆里面没有再次开辟内存么?)
String t = "fejaio";
我想拉想,觉得由上面这句,好象可以推断pool是位于栈空间的,进一步来说,常量池是位于栈空间
,主要是觉得:
:有明确的数据大小
那么,是不是说栈空间里面包含拉常量池这样
|------------| |__________|
|栈空间——————>| |
| | | | 堆空间 |
| V | | |
|-------| | |__________|
|常量池 | |
| | |
|-------| |
| |
|------------|
public class StringTest {
public static void main(String[] args)
{
//有关字符串new 的解释:new String("abc"),首先会在String pool中查找值为"abc"的字符串,如果没有找到,则将在String pool中创建一个对象,然后在String堆中创建一个对象,此时,共产生了两个对象,分别指向不同的内存地址(String pool 和 String 堆)
//如果在String pool中找到有"abc"这个值存在,则不会再在String pool中创建对象,而只在String堆中创建对象
//此时s指向的是String堆中的对象,也就是String堆中的值为"abc"的对象的引用,s的值也就是String堆中的值为"abc"的对象的内存地址
String s = new String("abc");
//s1指向的是String pool中值为"abc"的对象,s1的值也就是String pool中的值为"abc"的对象的内存地址
//此时因为String pool中值为"abc"的对象已经在上面的String s = new String("abc");步骤中被创建了,所以此时并没有创建对象
String s1 = "abc";
//s2指向的是在String堆中新创建的值为"abc"的对象
//此时也就创建了一个对象(String堆中的值为"abc"的对象,因为String pool中值为"abc"的对象已经在上面的String s = new String("abc");步骤中被创建了)
String s2 = new String("abc");
//==比较的永远是两个对象的内存地址
//s、s1、s2都指向的是不同的内存地址对应的对象
System.out.println(s == s1);//false
System.out.println(s == s2);//false
System.out.println(s1 == s2);//false
//String的intern()函数返回的是String pool中对应的对象
//s.intern()返回的是String pool中值为"abc"的对象,而s是指向String堆中的值为"abc"的对象,所以他们的内存地址肯定不同
System.out.println(s == s.intern());//false
System.out.println(s1 == s1.intern());//true
System.out.println(s.intern() == s2.intern());//true
String hello = "hello";
String hel = "hel";
String lo = "lo";
//原型字符串用"+"连接,过程是:字符串连接后("hello"),再去String pool中查找
System.out.println(hello == "hel" + "lo");//true
//原型字符串与字符串对象用"+"连接,过程是:字符串连接后("hello"),在String堆中创建一个新的对象,用于存放这个字符串
System.out.println(hello == "hel" + lo);//false
}
}
答案依次为:
2个对象 没有对象 1个对象
false false false
试题详解:
1.String s = new String("abc")执行此句时,首先在String Pool(String池)中查找有没有字符常量"abc",没有则在String Pool中创建"abc"的对象,当执行new String("abc")时则在java的堆中创建一个"abc"对象,而s则是该对象的引用,因此共计创建2个对象。
2.String s1 = "abc"执行此句时,首先还是在String Pool中查找有没有字符串常量"abc",有则直接将s1作为String Pool中"abc"的一个引用,因此此时没有创建任何对象。
3.String s2 = new String("abc")执行此句时,依旧在String Pool中查找有没有字符串常量"abc",有则不进行再次创建,由于这里用了new关键字(有new就有对象),所有便在java堆中又创建了一个"abc"对象(地址与第一句在堆中创建的地址不同),而s2则是这个对象的引用,因此执行此句时只创建了1个对象。
4.我们知道"=="是判断对象的,因此由于s指向的是java对中的"abc"对象而s1指向的则是String Pool中的"abc"对象,所以输出false。
5.6判断同上。
今天刚在JAVA贴吧找到的一个很不错的帖子,你可以看看,偶看明白了~
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;
}
对应的为:
int --Integer;
String --String ;
float--Float;
double--Double;
^…………
不可变类的对象是不能被改变的
JAVA资料太多?选中想收藏的文字(图片),右键选“收录到易载”,搞定!