调用一个有参函数的时候,会把实际参数传递给形式参数。可是,在程序语言中,这个传递过程当中传递的两种状况,即值传递和引用传递java
java中只存在值传递,不存在引用传递apache
对于基本数据类型ide
public class ParamTest { public static void main(String[] args) { ParamTest pt = new ParamTest(); int i = 10; pt.pass(i); System.out.println("print in main , i is " + i); } public void pass(int j) { j = 20; System.out.println("print in pass , j is " + j); } } /* 输出 print in pass , j is 20 print in main , i is 10 */
因而可知,对于基本数据类型,是在栈中从新创建一个引用 j,使其值等于传递的参数值 i,改变 j 并不影响 i函数
对于引用数据类型工具
示例一this
public static void main(String[] args) { ParamTest pt = new ParamTest(); User hello = new User(); hello.setName("Hello"); hello.setGender("Male"); pt.pass(hello); System.out.println("print in main , user is " + hello); } public void pass(User user) { user.setName("HelloChange"); System.out.println("print in pass , user is " + user); } /* 输出 print in pass , user is User{name='HelloChange', gender='Male'} print in main , user is User{name='HelloChange', gender='Male'} */
示例二code
public static void main(String[] args) { ParamTest pt = new ParamTest(); User hello = new User(); hello.setName("Hello"); hello.setGender("Male"); pt.pass(hello); System.out.println("print in main , user is " + hello); } public void pass(User user) { user = new User(); user.setName("HelloChange"); user.setGender("Male"); System.out.println("print in pass , user is " + user); } /* 输出 print in pass , user is User{name='HelloChange', gender='Male'} print in main , user is User{name='Hello', gender='Male'} */
示例一中,调用 User 类方法改变了内存地址上对象的属性,但这并非对传入参数自己的改变,实际上传入 hello 以后,在栈中创建 user 引用,且指向地址与 hello 相同,即指向同一对象,对对象的改变并非对 hello 这个引用的改变,其值一直在栈中指向对象空间地址对象
示例二中,传入 hello 以后,在栈中创建 user 引用并于 hello 等值,但经过 new 对象,使 user 引用指向了新的对象,即 user 在栈中的值改变了,而 hello 的值一直指向原对象并不受影响接口
有时侯咱们须要得到一个新对象,和已经存在的对象彻底相同,但又必须相互独立,若是使用简单的赋值方式,实际上指向的仍是同一内存地址上的对象,操做一个引用可能会影响另外一个,这就须要对象拷贝来获取一个彻底相同的新对象内存
setter/getter
new 新对象后用 set/get 方法设置属性
浅克隆
class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } class Student implements Cloneable { private int number; private Address addr; public Address getAddr() { return addr; } public void setAddr(Address addr) { this.addr = addr; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } @Override public Object clone() { Student stu = null; try { stu = (Student) super.clone(); //浅复制 } catch (CloneNotSupportedException e) { e.printStackTrace(); } return stu; } } public class Test { public static void main(String args[]) { Address addr = new Address(); addr.setAddress("杭州市"); Student stu1 = new Student(); stu1.setNumber(123); stu1.setAddr(addr); Student stu2 = (Student) stu1.clone(); System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAddress()); System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAddress()); stu2.setNumber(124); addr.setAddress("西湖区"); System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAddress()); System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAddress()); } } /* 输出 学生1:123,地址:杭州市 学生2:123,地址:杭州市 学生1:123,地址:西湖区 学生2:124,地址:西湖区 */
经过浅克隆得到新对象,其基本数据类型成员变量获得了复制,修改后不影响原对象
若变量为引用数据类型,则只复制地址引用,仍是指向相同地址,修改时会相互影响
若变量为 String 类型,则拷贝其地址引用。可是在修改时,它会从字符串池中从新生成一个新的字符串,原有字符串对象保持不变
深克隆
class Address implements Cloneable { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public Object clone()//Address 类可复制化 { Address addr = null; try { addr = (Address) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return addr; } } class Student implements Cloneable { private int number; private Address addr; public Address getAddr() { return addr; } public void setAddr(Address addr) { this.addr = addr; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } @Override public Object clone() { Student stu = null; try { stu = (Student) super.clone(); //浅复制 } catch (CloneNotSupportedException e) { e.printStackTrace(); } stu.addr = (Address) addr.clone(); //引用数据类型变量深复制 return stu; } } public class Test { public static void main(String args[]) { Address addr = new Address(); addr.setAddress("杭州市"); Student stu1 = new Student(); stu1.setNumber(123); stu1.setAddr(addr); Student stu2 = (Student) stu1.clone(); System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAddress()); System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAddress()); stu2.setNumber(124); addr.setAddress("西湖区"); System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAddress()); System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAddress()); } } /* 输出 学生1:123,地址:杭州市 学生2:123,地址:杭州市 学生1:123,地址:西湖区 学生2:124,地址:杭州市 */
工具类
org.apache.commons 组件 BeanUtils 和 PropertyUtils,静态方法 copyProperties(Object o1,Object o2)
序列化
序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。经过序列化实现的拷贝不只能够复制对象自己,并且能够复制其引用的成员对象,所以经过序列化将对象写到一个流中,再从流里将其读出来,能够实现深克隆。须要注意的是可以实现序列化的对象其类必须实现Serializable接口,不然没法实现序列化操做
class Professor implements Serializable { String name; int age; Professor(String name, int age) { this.name = name; this.age = age; } } class Student implements Serializable { String name;//常量对象 int age; Professor p;//引用数据类型 Student(String name, int age, Professor p) { this.name = name; this.age = age; this.p = p; } //深克隆 public Object deepClone() throws IOException, ClassNotFoundException { //将对象写到流里 ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); //从流里读出来 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (oi.readObject()); } } public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException { Professor p = new Professor("wangwu", 50); Student s1 = new Student("zhangsan", 18, p); Student s2 = (Student) s1.deepClone(); s2.p.name = "lisi"; s2.p.age = 30; System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); //学生1的教授不改变 } }