引用传递是整个Java的精髓所在,下面将利用三个程序对引用传递做进一步的分析。
引用传递的核心意义:同一块堆内存空间可以被不同的栈内存所指向,不同栈内存可以对同一堆内存进行内容的修改。
范例一:
class Message {
private int num = 10;
public Message(int num) {
this.num = num;
}
public void setNum(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
}
public class MainClass {
public static void main(String[] args) {
Message msg = new Message(30);
fun(msg);
System.out.println(msg.getNum());
}
public static void fun(Message temp) {
temp.setNum(100);
}
}
public class MainClass {
public static void main(String[] args) {
String msg = "Hello";
fun(msg);
System.out.println(msg);
}
public static void fun(String temp) {
temp = "World";
}
}
要注意的只有一点,String类对象的内容一旦声明,对象内容的改变依靠的是引用地址的改变。
class Message {
private String info = "nihao";
public Message(String info) {
this.info = info;
}
public void setInfo(String info) {
this.info = info;
}
public String getInfo() {
return this.info;
}
}
public class MainClass {
public static void main(String[] args) {
Message msg = new Message("Hello");
fun(msg);
System.out.println(msg);
}
public static void fun(Message temp) {
temp.setInfo("World");
}
}
但是以上的内存描述并不严格,因为在程序里面,info也是一个String类的对象,所以如果想要描述清楚,应该使用如下的内存关系图。
虽然String属于类,属于引用类型,但是由于其内容不可改变的特点,很多时候就直接把String当成基本数据类型那样使用。也就是说,每一个String类型只能够保存一个数据。
引用传递的实际应用
假设现有一需求,每个人有一辆车或者没有车,要求设计满足以上数据存储的数据库。创建语句:
应该设计两张表:人员表,汽车表;
CREATE TABLE member (
mid NUMBER ,
name VARCHAR2(50) ,
CONSTRAINT member_pk_mid PRIMARY KEY(mid)
) ;
CREATE TALBE car (
mid NUMBER ,
pname VARCHAR2(50) ,
CONSTRAINT car_fk_mid FOREIGN KEY(mid) REFERENCES member(mid) ,
CONSTRAINT car_pk_mid PRIMARY KEY(mid)
) ;
如果想要定义Java类,那么也应该定义两个类,所有通过分析可以发现。
简单Java类的编写原则:
范例: 代码设计如下
class Member {
private int mid;
private String name;
}
class Car {
private String pname;
}
以上实现了两个类,并且没有外键关系,但是在表中可以通过外键描述关系,那么在类中可以采用引用来描述关系。
class Member {
private int midl;
private String name;
// car有实例化对象表示有车
// car为null表示没有车
private Car car; // 表示属于人的车
}
class Car {
private Member member; // 车属于一个人
private String pname;
}
需要注意的是Member和Car应该都是一个独立的对象,而后通过产生对象发生关系。
class Member {
private int mid;
private String name;
// car有实例化对象表示有车
// car为null表示没有车
private Car car; // 表示属于人的车
public Member(int mid, String name) {
this.mid = mid;
this.name = name;
}
public String getInfo() {
return "mid=" + this.mid + ", name=" + this.name;
}
}
class Car {
private Member member; // 车属于一个人
private String pname;
public Car(String pname) {
this.pname = pname;
}
public String getInfo() {
return "pname=" + this.pname;
}
}
当Member或Car类的对象产生之后,那么就应该为这两个对象设置彼此的关系。
class Member {
private int mid;
private String name;
// car有实例化对象表示有车
// car为null表示没有车
private Car car; // 表示属于人的车
public Member(int mid, String name) {
this.mid = mid;
this.name = name;
}
public String getInfo() {
return "mid=" + this.mid + ", name=" + this.name;
}
public void setCar(Car car) {
this.car = car;
}
public Car getCar() {
return this.car;
}
}
class Car {
private Member member; // 车属于一个人
private String pname;
public Car(String pname) {
this.pname = pname;
}
public String getInfo() {
return "pname=" + this.pname;
}
public void setMember(Member member) {
this.member = member;
}
public Member getMember() {
return this.member;
}
}
以上的程序类完成之后,下面需要对程序进行测试,但是程序的测试要求分两步;
public class MainClass {
public static void main(String[] args) {
// 第一步:设置数据
Member m = new Member(1, "Alpha"); // 独立对象
Car c = new Car("MK14L"); // 独立对象
m.setCar(c); // 一个人有一辆车
c.setMember(m); // 一辆车属于一个人
// 第二步:取出关系
// 通过人找到车的信息
System.out.println(m.getCar().getInfo());
// 通过车找到人的信息
System.out.println(c.getMember().getInfo());
}
}
下面可以进一步设计,例如:每个人都有自己的孩子,孩子还可能有车,那么有两种设计方法:
方法二:一个人的孩子本质还是一个人,与人的类没有区别,可以在Member类里面设计一个属性表示孩子,其类型就是Member。
class Member {
private int mid;
private String name;
private Member child; // 表示孩子
// car有实例化对象表示有车
// car为null表示没有车
private Car car; // 表示属于人的车
public Member(int mid, String name) {
this.mid = mid;
this.name = name;
}
public String getInfo() {
return "mid=" + this.mid + ", name=" + this.name;
}
public void setChild(Member child) {
this.child = child;
}
public Member getChild() {
return this.child;
}
public void setCar(Car car) {
this.car = car;
}
public Car getCar() {
return this.car;
}
}
class Car {
private Member member; // 车属于一个人
private String pname;
public Car(String pname) {
this.pname = pname;
}
public String getInfo() {
return "pname=" + this.pname;
}
public void setMember(Member member) {
this.member = member;
}
public Member getMember() {
return this.member;
}
}
public class MainClass {
public static void main(String[] args) {
// 第一步:设置数据
Member m = new Member(1, "Alpha"); // 独立对象
Member chd = new Member(2, "Beta"); // 一个孩子
Car c = new Car("MK14L"); // 独立对象
Car cc = new Car("K98"); // 一辆车
m.setCar(c); // 一个人有一辆车
c.setMember(m); // 一辆车属于一个人
chd.setCar(cc); //一个孩子有一辆车
cc.setMember(chd); // 一个车属于一个孩子
m.setChild(chd); // 一个人有一个孩子
// 第二步:取出关系
// 通过人找到车的信息
System.out.println(m.getCar().getInfo());
// 通过车找到人的信息
System.out.println(c.getMember().getInfo());
// 通过人找到孩子的信息
System.out.println(m.getChild().getInfo());
// 通过人找打他孩子的车的信息
System.out.println(m.getChild().getCar().getInfo());
}
}
这样的操作在现实中十分常见。我们还可以针对引用做进一步的描述,例如:要求描述电脑,例如电脑由主机、显示器、键盘、CPU、内存、硬盘、显卡组成,那么如何通过代码描述?
class 键盘 {}
class 鼠标 {}
class CPU {}
class 硬盘 {}
class 内存 {}
class 显示器 {}
class 主板 {}
class 主机 {
private CPU[] 对象;
private 硬盘[] 对象;
private 主板 对象;
private 内存 对象;
}
class 电脑 {
private 主机 对象;
private 显示器[] 对象;
private 键盘 对象;
private 鼠标 对象;
}
这样的设计思路在Java之中称为合成设计模式。