菜鸡的Java笔记 第十六 - java 引用传递
referenceDelivery
引用传递是整个java 的精髓,也是所有初学者最难学的地方
引用的本质:同一块堆内存可以被不同的栈内存所指向
下面通过三道程序来进行引用传递分析
范例:第一道引用范例
class Demo{ private int num = 10: public Demo(int num){ this.num = num: } public void setNum(int num){ this.num = num: } public int getNum(){ return this.num: } } public class referenceDelivery{ public static void main(String args[]){ Demo demo = new Demo(100): fun(demo): // Demo temp = demo System.out.println(demo.getNum()): } public static void fun(Demo temp){ temp.setNum(30): } } // 结果: 30
范例:第二道引用传递
public class referenceDelivery{ 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当成引用类型,而只当成基本数据类型
public class referenceDelivery{ public static void main(String args[]){ int str = 10: fun(str): System.out.println(str): } public static void fun(int temp){ temp = 30: } } //结果:10
范例:第三道引用传递
class Demo{ private String msg = "Hello": public Demo(String msg){ this.msg = msg: } public void setMsg(String msg){ this.msg = msg: } public String getMsg(){ rrturn this.msg: } } public class referenceDelivery{ public static void main(String args[]){ Demo demo = new Demo ("world"): fun(demo): System.out.println(demo.getMsg()): } public static void fun(String temp){ temp.setMsg("MLDN"): } } //结果: MLDN
引用传递一定要耐心使用内存分析,String这种类型额数据需要特殊处理
*/
/* Object comparison 对象比较
对象比较的实现以及引用的操作
所谓的对象比较指的就是可以判断两个对象是否相等
实际上现在对象是否相同只能够依靠地址是否相同但是有些时候可能会出现地址不相同
但是内容相同的的情况,就好比String类的“==”与“equals()”的关系
那么我们希望可以实现一个属性自己的对象比较操作
然而要进行对象比较操作那么首先要做的事情就是必须将两个对象中的每个属性内容分别比较
如果属性内容全部相同那么就表示同一个对象,否则就认为不是同一个对象
范例:对象比较的基础实现
class Person{ private String name: private int age: public Person (String name,int age){ this.name: this.age|: } public String getName(){ rrturn this.name: } public int getAge(){ rrturn .this,age: } } public class referenceDelivery{ public static void main(String args[]){ Person perA = new Person("张三",20): Person perB = new Person("李四",20): if(perA.getName(),equals(perB,getName())&&perA,getAge()==perB.getAge()){ System.out.println("是同一个人"): }else{ System.out.println("不是同一个人"): } } //结果: 不是同一个人
现在的功能已经实现了,但是不能够仅仅只是控制在实现的范畴,需要更好的实现,那么以上的代码有什么问题
直接的反映就是代码写在主方法里面那么如果不写在主方法里面该写在哪
class Person{ private String name: private int age: public Person (String name,int age){ this.name: this.age|: } public String getName(){ rrturn this.name: } public int getAge(){ rrturn .this,age: } // 此时需要接收一个要比较的对象(对象的本质就是数据的集合) // 同时在本类方法里面还有一个隐藏的对象:this // 此时的compare()方法接收了自己本类的引用 // 由于此时的person参数对象在Person类中了,所以可以直接访问私有属性 public boolean compare(Person person){ if(person == null){// 就不要比较了 rrturn false: } if(this == person){ // 防止自己与自己比较,地址比较 rrturn true: } if(this.name.equals(person,name)&&this.age == person.age){ rrturn true: } rrturn false: } } public class referenceDelivery{ public static void main(String args[]){ Person perA = new Person("张三",20): Person perB = new Person("李四",20): if(perA.compare(perB)){ System.out.println("是同一个人"): }else{ System.out.println("不是同一个人"): } }
对象比较更多的是在分析层次上使用,而在实际之中,只有String用的比较多
对象比较一定是一个类自己具备的功能,所以一定要在类中写一个比较方法
进行对象比较时一定是将对象中的每一个属性进行逐步判断,所有属性都相同了,就表示对象是相同的,相等的
*/
/* 引用传递实例分析
将程序与生活联系在一起
一直以来一直强调:程序是生活的浓缩。生活的抽象,也就是说日常中的一切概念都可以通过程序来进行描述
下面描述这样的一个程序:一个人有一辆车
在描述以上概念之前希望可以有一个对比,如果说现在你进行数据库的设计,要描述以上的操作形式,你的数据表该如何设计呢?
CREATE TABLE person(
pid NUMBER,
name VARCHAR2(50),
CONSTRAINT pk_pid PRIMARY KEY(pid)
);
CREATE TABLE car(
pid NUMBER,
cname VARCHAR2(50),
CONSTRAINT pk_pid PRIMARY KEY(pid),
COMSTRAINT fk_pid2 FOREIGN KEY(pid)REFERENCES person(pid)
)
如果说现在要是进行类的设计,也需要两个类:Person Car,那么就可以发现两者的关联:
表名称 = 类名称:
表的字段 = 类属性
表的一行记录 = 一个实例化对象
表的多行记录 = 对象数组
标的外键 = 引用设置
正是因为有这样的匹配关系,所以在实际的开发过程之中,简单JAVA类不是凭空设计的,往往都与数据表的结构一一对应
范例:定义类
class Person{ private int pid: private String name: // car 为null了表示这个人没有车 private Car car: // 一个人有一辆车 public Person(int pid,String name){ this.pid = pid: this.name = name: } public String getPersonlnfo(){ return"身份号:"+this.pid+",姓名:"+this.name: } public void setCar(Car car){ this.car = car: } public Car getCar(){ return this.car; } } class Car{ private String cname; // 如果人有车了,那么必须同时修改车与人对的关系 private Person person; // 一辆车属于一个人 public Car(String cname){ this.cname = cname: } public void setPerson(Person person){ this.person = person: } public Person getPerson(){ return this.person: } public String getCarlofo(){ return "汽车名称:"+this.cname: } } public class biji{ public static void main(String args[]){ // 第一步:根据已有的结构设置内容 Person per = new Person(450802,"少爷"): Catr car = new Car("保时捷356A"): per,setCar(car): // 现在人有车了 car.setPerson(per): // 现在车属于一个人了 // 第二步:根据关系取出数据 System.out.println(per,getPersonlnfo()): System.out.println(per,getCar().per,getCarlnfo()): // 代码链 System.out.println(car.getPerson().getPersonlnfo()): } } /* 结果: 身份号:450802,姓名:少爷 汽车名称:保时捷356A 身份号:450802,姓名:少爷 */
此时程序中使用了自定义的数据类型,Person Car都是类。那么随后的操作主要是进行代码的测试
但是测试分为两步:第一步设置内容,第二步取出内容
代码链别看单词,就看每一个方法的返回值是什么东西。如果是一个类的对象则可以继续调用该类的方法
那么也可以针对于此代码进行进一步额扩展。每个人还有孩子,每个孩子也可能有车
实际上这里面需要注意的是每一个人的孩子一定还是人,并且具备有跟人同样的属性信息,那么就可以在Person里面设计一个孩子的属性
class Person{ private int pid: private String name: private Person child: //孩子 // car 为null了表示这个人没有车 private Car car: // 一个人有一辆车 public Person(int pid,String name){ this.pid = pid: this.name = name: } public void setChild(Person child){ this.child = child: } public Person getChild(){ return this.child } public String getPersonlnfo(){ return"身份号:"+this.pid+",姓名:"+this.name: } public void setCar(Car car){ this.car = car: } public Car getCar(){ return this.car; } } class Car{ private String cname; // 如果人有车了,那么必须同时修改车与人对的关系 private Person person; // 一辆车属于一个人 public Car(String cname){ this.cname = cname: } public void setPerson(Person person){ this.person = person: } public Person getPerson(){ return this.person: } public String getCarlnfo(){ return "汽车名称:"+this.cname: } } public class biji{ public static void main(String args[]){ // 第一步:根据已有的结构设置内容 Person per = new Person(450802,"少爷"): Person chd = new Person(450803,"小少爷"): // 有了孩子 Catr car = new Car("保时捷356A"): Car c = new Car("布加迪威龙银河版"): per,setCar(car): // 现在人有车了 car.setPerson(per): // 现在车属于一个人了 per.setChild(chd): // 一个人有一个孩子 chd.setCar(c): // 孩子有车 // 第二步:根据关系取出数据 System.out.println(per.getChild().getPersonlnfo()): // 通过父亲的车找到父亲的信息,再找到父亲的孩子的车的信息 System.out.println(car.getPerson().getChild().getCar().getCarlnfo): } }
结果: 身份号:450803,姓名:小少爷
汽车名称:布加迪威龙银河版
引用的关系可以描述出不同类之间的引用关系
在现实的生活中这样的设计实际上并不麻烦了,理论上任何的事物都可以进行这样的整合
范例:抽象出衣服
class 袖子{}
class 衣领{}
class 衣服{
private 袖子 左:
private 袖子 右:
private 衣领 对象:
}
范例:抽象电脑
class cpu{}
class 内存{}
class 显卡{}
class 硬盘{}
class 主板{
private CPU 对象 :
private 内存 对象[]:
private 硬盘 对象[]:
private 显卡 对象:
}
class 键盘{}
class 鼠标{}
class 主机{
private 主板 对象:
private 鼠标 对象;
private 键盘 对象:
}
此处也同样属于引用。这样的形式的代码在设计模式上讲称为合成设计模式
1.不要把程序只当程序
2.引用传递除了进行数据的分析之外,还需要掌握类与类的联系使用
3.代码链的使用必须熟练