首先明确
(1)堆内存:堆内存可以理解为一个对象的具体信息,每一个对象保存的知识属性信息,每一块堆内存开辟都需要new关键字来完成。
(2)栈内存:可以理解为一个整型变量(只能够保存一个数值),其中保存的是一块(只能保存一块)堆内存空间的内存地址数值,为了方便理解,现在可以假设其保存的是对象的名字。
个人理解,多个栈内存的对象的可以同时指向同一个堆内存中的一部分信息(即多对一),但通过其中一个栈内存的对象修改了堆内存的信息,其他栈内存的对象引用这部分信息时也发生变化了。
1.对象的实例化内存分配操作
class Book //定义类Book
{
String title;
double price;
public void printInfo()
{
System.out.println("title:" + this.title);
System.out.println("price:" + this.price);
}
}
public class TestInstant
{
public static void main(String args[])
{
Book book = null; // 声明对象
book = new Book() ; // 实例化一个对象
book.title = "Java程序设计"; // 设置了类中的title属性
book.price = 39.8; // 设置price属性
book.printInfo(); // 此处的方法使用对象调用,不是直接调用
}
}
此时栈内存中有一个book,通过new将book实例化,然后堆内存中就有book的属性(title和price),然后book就指向了这块堆内存。
2.在函数中传递基本数据类型
public class TestValue
{
public static void change(int i, int j) //交换参数的值
{
int temp = i; //完成两个变量值的交换
i = j;
j = temp;
}
public static void main(String[] args)
{
int a = 3;
int b = 4;
change(a, b); //调用方法
System.out.println("a=" + a);
System.out.println("b=" + b);
}
}
输出:
a=3
b=4
引用数据类型的传递并没有改变数据本身的值。因为参数中传递的是基本类型a和b的备份,在函数中交换的也是那份备份的值而不是数据本身。3.传递引用数据类型
public class TestValue01
{
public static void change(int[] count)
{
count[0]=0;
System.out.println("在方法内部count[0]="+count[0]);
}
public static void main(String[] args)
{
int[] count={1,2,3,4,5};
System.out.println("方法执行前count[0]="+count[0]);
change(count);
System.out.println("方法执行后count[0]="+count[0]);
}
}
输出:
方法执行前count[0]=1
在方法内部count[0]=0
方法执行后count[0]=0
在方法中传递引用数据类型int数组,实际上传递的是其引用count的备份,它们都指向数组对象,在方法中可以改变数组对象的内容。即:对复制的引用所调用的方法更改的是同一个对象。
4.对象的传递引用
class Person
{
String name;
int age;
}
public class TestRefDemo
{
public static void main(String args[])
{
Person p1 = null;//声明对象p1,此对象值为null,尚未实例化
Person p2 = null;//声明对象p2,尚未实例化
p1 = new Person();//实例化对象p1
p1.age = 20;
p1.name = "Kimi";
p2 = p1;//将p1的引用赋给p2
System.out.println("姓名:"+ p2.name);
System.out.println("年龄:"+ p2.age);
p1 = null;
}
}
输出:
姓名:Kimi
年龄:20
p2=p1;这句话将p1指向的堆内存空间,也让p2指向了同样的堆内存空间。即不同的栈内存知指向了同一块堆内存。
5.引用传递的使用
class Book //定义类Book
{
String title;
double price;
public void printInfo()
{
System.out.println("title:" + this.title);
System.out.println("price:" + this.price);
}
}
public class TestRefDemo02
{
public static void main(String args[])
{
Book bookA = new Book() ;// 实例化一个对象
Book bookB = new Book() ;
bookA.title = "Java程序设计" ;// 设置了类中的title属性
bookA.price = 40 ;// 设置price属性
System.out.println("引用传递前对象bookA:");
bookA.printInfo() ;// 对象bookA调用方法printInfo
bookB.title = "Java WEB开发" ;
bookB.price = 60 ;
bookB = bookA ;// 引用传递
bookB.title = "Android开发" ;
System.out.println("引用传递后对象bookA:");
bookA.printInfo() ;// 对象bookA调用方法printInfo
}
}
执行bookB=bookA这个引用传递之前,bookA、bookB是两个用new关键字创建的对象,分别指向各自独立的堆内存,属性值也不同。但执行bookB=bookA这个引用传递后,bookB指向了bookA的堆内存,所以bookB对这块堆内存的属性值设置就是对bookA相应的属性值的修改。
6.再看3个例子
class Message
{
private double salary;
public Message(double salary)
{
this.salary=salary;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
public class EX17_1 {
public static void main(String[] args) {
Message msg=new Message(800.0);
System.out.println(msg.getSalary());
fun(msg);
System.out.println(msg.getSalary());
}
public static void fun(Message temp)//相当于Message temp=msg这样一个引用传递
{
temp.setSalary(2000.0);
}
}
输出:
800.0
2000.0
public class EX17_2 {
public static void main(String[] args) {
String str="Hello";
fun(str);
System.out.println(str);
}
public static void fun(String tmp) //String是基本数据类型,不会改变str的内容
{
tmp="World";
}
}
输出:
Hello
class Msg
{
private String str;
public Msg(String str)
{
this.str=str;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
public class EX17_3 {
public static void main(String[] args) {
Msg msg=new Msg("Hello");
System.out.println(msg.getStr());
fun(msg);
System.out.println(msg.getStr());
}
public static void fun(Msg tmp) //相当于Msg tmp=msg;这样一个引用传递
{
tmp.setStr("World");
}
}
输出:
Hello
World