Java优秀的面向对象意识成为后续语言不断模仿的对象,而JAVA引用数据传递可谓是无法让初学者能理解的,探寻根本原因背后有数据结构的本质。博主本次采用案例式讲解引用数据传递,文末并附有源码,大家可私下尝试!
代码前的准备
创建一个Book类,类里有它的价格和它的书名。
class Book{
String title;
double price;
public void getInfo() {
System.out.println("图书名称:" + title + ",价格:" + price);
}
}
案例1–声明并实例化对象
案例1主要讲述初学者常用的是这种方式声明并实例化对象,一条语句却有引用的概念。先看这个案例,案例就是初始化一个对象,并设置一个概念,非常直观。这里用到类,代码下方对类做简要介绍。
public void main1(String args[]) {
Book bk = new Book();
bk.title = "Java开发";
bk.price = 89.9;
bk.getInfo();
}
一般的类定义完成后,肯定无法直接使用,如果要使用,必须依靠对象,由于类属于引用数据类型,所以对象的产生格式如下
类名称 对象名称 = new 类名称();
如果分布完成,那就先声明,后实例
声明对象: 类名称 对象名称 = null;
实例化对象: 对象名称 = new 类名称();
案例2–分步实例化对象
public void main2(String args[]) {
Book bk = null;//声明对象 先声明对象用栈内存指向空的堆内存
bk = new Book(); //实例化对象
bk.title = "Java开发";
bk.price = 89.9;
bk.getInfo();
}
这段代码,先声明后实例化,提到了一个栈内存和堆内存的概念。栈内存创建地址,堆内存创建空间。用地址指向空间,可以说是c的指针范畴。画张图加强理解
这也就是分步骤,那么问题来了?如果直接不实例化用代码会怎样,下面看这段代码
案例3–分布但不实例化对象
public void main3(String args[]) {
Book bk = null;//声明对象 先声明对象用栈内存指向空的堆内存
bk = new Book(); //实例化对象
bk.title = "Java开发";
bk.price = 89.9;
bk.getInfo();
}
代码当然会抛异常,这个异常是在使用引用数据类型时没有为其开辟堆内存空间。异常情况怎么样?来张图
案例4–声明并实例化两个对象
一个对象会声明并实例化,两个肯定也会,那就直接用吧
public void main4(String args[]) {
Book bkA = new Book();
Book bkB = new Book();
bkA.title = "Java开发";
bkA.price = 89.9;
bkA.getInfo();
bkB.title = "Web开发";
bkB.price = 19.9;
bkB.getInfo();
}
这段代码也可以认为对第一个对象的copy,只要把title和price改变就行了,问题来了,如果对象产生引用,也就是两个实例化对象相等会发生什么?
案例5–对象之间引用传递
public void main5(String args[]) {
Book bkA = new Book();
Book bkB = null;
bkA.title = "Java开发";
bkA.price = 89.9;
bkB = bkA;
bkB.price = 69.9;
bkA.getInfo();
}
代码运行,b的价格改变A的价格也跟着改变,运行结果如下
为什么?因为同时开辟堆内存,栈内存指向同一个堆内存地址。堆内存改变,地址不发生改变,也就值会一起改变 大家如果不理解,也可以来张图来观察一下
理解了这张图之后,然后再去观察如果两个对象实例化开始不同,结果在中间产生引用传递,一个值改变,那么另一个值肯定改变!再去看最后一个例子
案例6–深入观察
public static void main(String args[]) {
Book bkA = new Book();
Book bkB = new Book();
bkA.title = "Java开发";
bkA.price = 89.9;
bkB.title = "JSP开发";
bkB.price = 19.9;
bkB = bkA;
bkB.price = 100.2;
bkA.getInfo();
}
代码运行效果
引用传递后的,之前开辟的内存就会被垃圾回收器析构,下面这张图加深巩固理解
附完整源码
如果对java不了解,就是每一个案例的代码复制到void main函数运行,因为main函数是入口。我的类名称是Main,大家自己的可以修改哟!
package test;
class Book{
String title;
double price;
public void getInfo() {
System.out.println("图书名称:" + title + ",价格:" + price);
}
}
public class Main {
public void main1(String args[]) {
Book bk = new Book();
bk.title = "Java开发";
bk.price = 89.9;
bk.getInfo();
}
public void main2(String args[]) {
Book bk = null;//声明对象 先声明对象用栈内存指向空的堆内存
bk = new Book(); //实例化对象
bk.title = "Java开发";
bk.price = 89.9;
bk.getInfo();
}
public void main3(String args[]) {
Book bk = null;//声明对象 先声明对象用栈内存指向空的堆内存
//bk = new Book(); //实例化对象
bk.title = "Java开发";
bk.price = 89.9;
bk.getInfo();
}
public void main4(String args[]) {
Book bkA = new Book();
Book bkB = new Book();
bkA.title = "Java开发";
bkA.price = 89.9;
bkA.getInfo();
bkB.title = "Web开发";
bkB.price = 19.9;
bkB.getInfo();
}
public void main5(String args[]) {
Book bkA = new Book();
Book bkB = null;
bkA.title = "Java开发";
bkA.price = 89.9;
bkB = bkA;
bkB.price = 69.9;
bkA.getInfo();
}
public static void main(String args[]) {
Book bkA = new Book();
Book bkB = new Book();
bkA.title = "Java开发";
bkA.price = 89.9;
bkB.title = "JSP开发";
bkB.price = 19.9;
bkB = bkA;
bkB.price = 100.2;
bkA.getInfo();
}
}
总结
本博文采用六个案例,第一个案例是最寻常使用,第二个分步声明实例化对象。第三个分步骤但不实例化的后果大家会看到异常,第四个声明并实例化两个对象,第五个对象之间引用传递,理解堆内存与栈内存的深层次意义,并附图理解,案例六代码垃圾析构器的使用。
希望博文能对大家有帮助!