标签:mtu function 学习java 基础 south 产生 等价 李兴华 water
最近看着李兴华讲师的java视频教程学习java,关于java引用传递方面的知识的总结。
class Person
{
private String name;
private int age;
private static String city = "北京";
// 构造函数
public Person(){}
public Person(String name, int age)
{
this.name = name;
this.age = age;
}
}
public class Test
{
public static void main(String args[])
{
Person person = new Person("张三",20);
}
}
以上产生的person对象的内存关系如下图:
#####直接赋值
public class StringDemo
{
public static void main(String args[])
{
// 直接赋值
String str1 = "Hello";
// 直接赋值
String str2 = "Hello";
// 直接赋值
String str3 = "Hello";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);
}
}
程序运行结果:
true
true
true
由程序执行结果可知:str1、str2、str3 3个字符串的内存地址完全相同,也就是说,实际上只开辟了一段堆内存空间。
内存分析图:
#####构造方法赋值
public class StringDemo
{
public static void main(String args [])
{
// 构造方法赋值
String str1 = new String("Hello");
// 构造方法赋值
String str2 = new String("Hello");
System.out.println(str1 == str2);
}
}
程序结果:
false
由程序执行结果可知:str1、str2、 2 个字符串的内存地址不相同,也就是说,使用构造方法实例化的String类对象内容不会保存在字符串对象池中,即不能狗进行共享数据操作。
构造方法赋值分析
由于每一个字符串都是一个String类的匿名对象,所以首先会在堆内存中开辟一段内存空间保存字符串”Hello”,而后又使用关键字new开辟了另一块内存空间,并把之前定义的字符串常量的内存空间的内容赋给new开辟的空间,而此时之前定义的字符串常量的内存空间将不会有任何栈内存指向,就成成为垃圾,等待垃圾收集器(GC)不定期回收。
内存分析图:
由上述的结论还可以知道:
代码实例分析:
public class TestDemo
{
public static void main(String args [])
{
String str = "Hello ";
String str1 = "Hello ";
String str2 = "Hello ";
// str、 str1指向同一块内存空间
System.out.println(str == str1 && str1 == str2) ;
str += "World";
// str和str2是否仍指向同一块内存空间
System.out.println(str == str1) ;
System.out.println(str1 == str2) ;
System.out.println("str = " + str) ;
System.out.println("str1 = " + str1);
}
}
程序运行结果:
true
false
true
str = Hello World
str1 = Hello
str2 = Hello
由程序执行结果可知,开始str、str1和str2指向同一块堆内存空间,改变str(连接”World”)之后,str指向的堆内存空间发生改变,而原str所指的堆内存空间的内容没有发生改变。
内存分析图
引用传递的本质是:
class Demo
{
private int data = 10;
public Demo(){}
public Demo(int data)
{
this.data = data;
}
public int getData()
{
return this.data;
}
}
public class TestDemo
{
public static void main(String args [])
{
Demo demo = new Demo(100);
fun(demo); // 等价于Demo temp = demo
System.out.println(demo.getData());
}
public static void fun(Demo temp)// 接受引用
{
temp.setData(30);// 修改属性内容
}
}
程序运行结果:
30
结果分析
本程序首先在主方法中实例化了一个Demo对象,同时为类中的data属性赋值为100,之后将类对象传递给fun()方法由于类本身属于引用数据类型,所以fun()方法中的修改直接影响原始对象的内容。
内存关系图
public class TestDemo
{
public static void main(String args [])
{
String str = "Hello"; // 自定义字符串
fun(str); // 引用传递: String temp = str
System.out.println(str);
}
public static void fun(String temp)
{
temp = "World";
}
}
程序运行结果:
Hello
通过程序运行结果可以发现,由于String类的内容不可变,所以当修改字符串数据(temp = “World”;)时就发生一个引用关系的变更,temp将指向新的堆内存空间。由于temp数据是方法的局部变量,所以方法执行完毕后,原始的str对象内容并不会发生任何改变。所以使用String类作为引用操作类型操作,关键是:
可以把String类看成基本数据类型。由于基本数据类型本身不牵扯到内存关系,而且传递时也只是值传递,不是内存地址传递,这样的特点是:方法里不管做何种修改,都不会影响原数据的内容。
内存关系图
class Demo
{
private String data;
public Demo(){}
public Demo(String data)
{
this.data = data;
}
public void setData(String data)
{
this.data = data;
}
public String getData()
{
return this.data;
}
}
public class TestDemo
{
public static void main(String args [])
{
Demo demo = new Demo("Hello"); // 对象实例化
fun(demo); // 引用传递:Demo temp = demo
System.out.println(demo.getData());
}
public static void fun(Demo temp)
{
temp.setData("World");
}
}
程序运行结果:
World
本程序和范例一从本质上将没有本质上的区别,唯一的区别在于本次使用了String作为Demo类的属性。如果把String类看成基本数据类型,可以得到如下内存分析图:
但实际上,更完整的内存关系应该表示为“Demo对象(栈)中包含了String的引用(data是String的名字存储在栈,而字符串的内容则存储在堆),Demo对象的堆内存中保存着data(栈内存)的引用关系”,完整的内存关系图如下:
标签:mtu function 学习java 基础 south 产生 等价 李兴华 water
原文地址:http://blog.csdn.net/lym152898/article/details/54411956