调用一个有参函数的时候,会把实际参数传递给形式参数。但是,在程序语言中,这个传递过程中传递的两种情况,即值传递和引用传递
java中只存在值传递,不存在引用传递
对于基本数据类型
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
对于引用数据类型
示例一
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'}
*/
示例二
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的教授不改变
}
}