Java里面对象的引用问题

来源:互联网 发布:自动装修软件 编辑:程序博客网 时间:2024/06/06 08:48


            Java初学者,因为之前学过C,所以对于学Java的时候老是能想起来地址、指针问题,感觉挺纠结。

         

          Java定义实例化的对象时,具体对象数据存在堆中,对象名存在栈中,栈中的对象名可以看做C++中的指针,指向堆中具体的对象数据。并且同一类的两个不同对象之间的赋值,实际上是改变栈中对象名的指向,而不是改变堆中的对象数据,当堆中的对象数据没有对象名指向时,这个数据成为垃圾数据,对应的堆内存由Java的垃圾处理机制(GC)自动回收。


                 Java的基本类型是没有内存关系的,没有变量名指向变量实体这种说法的,相互赋值用法和C++中变量赋值用法是相同的。有一点区别:C++可以使用函数交换两个变量的值(指针传参),而Java实现相同功能只能用函数返回值(返回数组,保存交换完后的两个数值)



       举例三个不同类型的例子说明一下吧:

基本数据类的值传递

public class PersonDemo{public static void main(String args[]){int a = 10;fun(a);System.out.println(a);}public static void fun (int temp) {temp = 100;}}//输出10
        基本数据类型没有内存关系,对于fun函数的传递是值传递,fun函数中temp变量指向了新的数值100,而原本a指向的10不变。fun函数执行完毕后,temp与100均为内存垃圾,被GC回收。


字符串的引用传递

public class PersonDemo{public static void main(String args[]){String str = "hello";fun(str);System.out.println(str);}public static void fun (String temp) {temp = "world";}}//输出hello

        字符串String类型一旦声明赋值则不可改变,此处fun函数的参数传递为引用传递,str与temp均指向堆内存中的“hello”,但是字符串“world”出现时,是在堆内存中重新开辟一个空间(等价于使用string类的new String("world")),赋值“world”,然后temp指向“world”。fun函数执行完毕后,temp与“world”均为内存垃圾,被GC回收。


自定义类的成员变量的引用传递

class Demo {private String msg;public void setMsg(String msg) {this.msg = msg;}public String getMsg() {return this.msg;}}public class PersonDemo{public static void main(String args[]){Demo demo = new Demo();demo.setMsg("hello");fun(demo);System.out.println(demo.getMsg());}public static void fun (Demo temp) {temp.setMsg("world!");}}//输出world

         自定义类的成员对象的内存关系又不太一样:

         1、Demo demo = new Demo(); 是在栈内存开辟两个空间,存两个名字 类型名(demo和msg),然后再堆内存开辟空间,存类实体,此处为可以指向msg地址的值。

         2、demo.setMsg("hello");  在堆内存开辟空间,存字符串“hello”,然后栈内存中的msg指向此处的“hello”。

         3、fun(demo); 在栈内存开辟空,存类型名 temp,然后将demo的指向赋给temp,即引用传递,此时temp指向的堆内存中的空间与demo所指向的是一样的。

         4、temp.setMsg("world!");  此处“world!”与上面的“hello”相同,需要在堆内存重新开辟空间,然后存“world!”;执行setMsg函数时,在temp所指向的类空间中找到栈空间的msg,然后将msg的指向从“hello”转移至“world!”。fun函数执行完毕后,temp和“hello”将成为内存垃圾。


具体内存变化图如下:





总结

1、java基本类型没有内存关系,变量之间的赋值等效于C、C++;


2、java String类型一旦赋值,则在堆内存中不可改变,只能被GC回收;重新赋值需要开辟新的堆内存空间,改变栈内存中变量名的指向;

3、java 可通过外部函数更改类的成员变量的值(引用传递),具体内存变换见上图。

原创粉丝点击