java中不同数据类型的内存分配方式

点击量:373

首先,在java中一共有两种数据类型,基本类型(primitive types)和引用类型(reference types)。

基本类型
java中的基本类型一共有八种,即byte, int, short, long, float, double, boolean, char。这些类型所申明的变量都是字面值,比如int a = 1,也就是说变量a指向的是1这个值,并没有对象和引用。值得注意的是,为了提高存储的速度,基本类型的变量内存都是存储在栈中的,而栈中的数据是是可以共享的。因此当我们同时声明两个同样字面值的变量时,编译器只会分配同一块内存。这个过程就是先在栈中查找是否存在这样的字面值,如果有则指向那块内存,如果没有就新分配一块内存。因此如果两个变量同时指向一个值,比如:int a = 1;int b = 2;当a的值被改变的时候,b的值并不会被改变,正如前面所说,a的值被改变时会重新去分配一块内存。
引用类型
主要包括一些对基本类型进行封装的类(又称为包装类),比如String,Integer,Double等,还有一些自定义的类。自定义类一般是显式的使用new关键字来告诉编译器创建一个对象,只有在运行时才会动态创建,内存被分配在堆上。但是呢,包装类有些特殊,既可以使用new关键字来声明,也可以直接使用=来直接定义声明。比如:Integer a = 1;Integer b = new Integer(1);那么着两者有什么区别呢?我们来看一下下面的代码:

从上面的示例可以看出,凡是通过等于号直接定义的对象都是指向同一块内存,但是new出来的对象都不是同一块内存。如上一节所说,直接等于的赋值是在中寻找已经存在的该对象的地址,并把这个引用指向这块内存。而new出来的对象是直接分配在上的,所以这两种方式引用所指向的并不是同一个对象,分配的内存区域不一样,数据不会共享。比如:
String str = "xxx";
在编译这段代码时,编译器会先去定义一个String类的引用变量str,但是这个引用指向哪块内存还需要要参考上下文。如果栈中有存放自面值xxx的地址,则指向他。如果没有,则会新创建一个对象O,把O的自面值指向这个自面值xxx,然后把str引用指向这个对象O。所以,当我们看到String str = “xxx”;这种代码时并不能说明有新的string对象被创建(因为栈中的数据是共享的),唯一可以肯定的是一个String类的引用被创建了。

理解了这一点,关于java中一些迷惑性的问题便迎刃而解了。
比如:
1.为什么string类的值不能被改变?
String类和其他原始数据的包装类型都不能改变其内部的值,也就是immutable特性。注意这里的不能改变并不是说你不能改变这个变量的值,而是说当你改变这个变量的值的时候会创建新的对象,与之前的变量毫无关系了
2.为什么String类是线程安全的?
immutable特性,根本不能被更改,更别谈被多线程争抢修改了,所以肯定是线程安全的。
3.为什么String类频繁变更值的时候效率不如StringBuffer/StringBuilder?
因为值在不断变化时编译器会频繁的创建新的对象。
4.java参数传递问题,值传递还是引用传递?
结论是:基本类型的值传递,不会改变原来的值。而对象的传递是引用传递,在方法内部改变它的值,原来的值也会改变,因为指向是同一块内存嘛。
5.为什么检查String类自面值是否相等时需要用equals?(==是检查这个引用指向的地址是否是同一个)
因为引用指向不同的内存区域。
好了,总结一下以上的内容:
1.直接定义的变量都是分配在栈中的,且栈中的数据是共享的,两个不同的变量指向同一块内存。而通过关键字new来创建的对象都是分配在堆中的,这种方式显式的告诉编译器去新分配一块内存。
2.String a = new String(“xxx”);引用a保存在栈中,而对象分配在堆上。

参考文章:
http://6924918.blog.51cto.com/6914918/1283761
http://baike.baidu.com/view/93201.htm

发表评论

电子邮件地址不会被公开。 必填项已用*标注