1.Java参数传递方式
网络上有很多地方都说明java的参数传递方式是值传递,虽然其最终的解释是正确的。但我认为值传递定义为java参数传递方式并不妥。
可以分成两种,便于记忆和理解:1.基本数据类型的值传递 2.对象的引用传递(传址)。
当然这里会有一个问题基本数据类型只能值传递么?如何进行引用传递? 待以后慢慢研究吧
下面用直接用代码来说明一下这两种参数传递方式的区别:
// 基本数据类型是值传递,而非引用传递
public void changeInt(int params) {
params = params * 2 + 1;
}
// java对象是引用传递而非引用传递
public void changeObject(A a) {
a.a = "hello 2013!";
}
@Test
public void changeTest() {
int i = 3;
CloneTest ct = new CloneTest();
ct.changeInt(i);
A a = new A();
a.a = "style!";
ct.changeObject(a);
System.out.println(i);//结果 3
System.out.println(a.a);//结果 hello 2013!
}
---------------------2013年5月2日---------------------------------------------------------
这里需要纠正之前的认识,java的传递只有一种就是值传递。
public void changeList(List<Integer> list){
List<Integer> tlist=new ArrayList<Integer>();
tlist.add(1);
tlist.add(2);
list=tlist;
}
@org.junit.Test
public void testList(){
List<Integer> l =new ArrayList<Integer>();
changeList(l);
System.out.println(l.size());//0
}
我们可以改变赋值对象的内容,但对已对象的赋值是没有任何意义的。因此参数不应该被赋值超过两次。
在参数前加final关键字。
2.对象的拷贝
1.浅拷贝和深拷贝
接下来的问题便是,如果我不想改变原来对象的属性内容,但又想得到对象的属性内容咋办?简言之,如何拷贝对象。
网上有很多地方都提到拷贝会产生风险,其实我们应该能理解,因为引用时无时无刻都存在的,但凡是对象,所以我们在处理拷贝时一定要非常注意。
那这里就会涉及到浅拷贝和深拷贝两个概念。
2.如何拷贝(对自定义类的对象)
在使用中我们经常要对自定义类的对象进行拷贝,因为自定义类中可以包含其他自定义类对象变量,基本数据类型变量或者jdk提供的其他类型的变量(集合,数组等等),
而我们的任务便是将这些属性值进行拷贝。
先来看一下一个最简单的拷贝对象的例子:
Modification Log:
package com.techbirds.lang;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class CloneTest {
@Test
public void cloneTest1() throws CloneNotSupportedException {
C c1 = new C();
c1.c = "c1";
C c2 = new C();
c2 = (C) c1.clone();
System.out.println(c1.c);//c1
System.out.println(c2.c);//c1
System.out.println(c1==c2);//false
System.out.println(c1.c==c2.c);//true
c2.c = "c2";
System.out.println(c1.c);//c1
System.out.println(c2.c);//c2
System.out.println(c1.c==c2.c);//false
}
}
/**
* 实现Cloneable接口,实现浅拷贝
*
*/
class C implements Cloneable {
public String c;
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
C o = null;
try {
o = (C) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
这个例子对于深浅拷贝做了很好的解释,很明显对于拷贝过来的对象中,对于属性c我们只对其进行了浅层拷贝。
那问题就抛向我们:那如何对类变量进行深层拷贝呢?其实很简单:对类变量所在类v也必须进行克隆实现。
@Test
public void testObject1() throws CloneNotSupportedException{
D d1=new D();
d1.d="12";
String[] strs1=new String[]{"1","2"};
d1.ds=strs1;
List<String> l1=new ArrayList<String>();
l1.add("12");
d1.lds=l1;
A a=new A();
a.a="a";
d1.a=a;
D d2=(D) d1.clone();
System.out.println(d1==d2);//false
System.out.println(d1.a.hashCode()+":"+d2.a.hashCode());//20324370:7578443
System.out.println(d1.ds.hashCode()+":"+d2.ds.hashCode());//31822120:31822120
}
class A implements Cloneable{
public String a;
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class D implements Cloneable{
public List<String> lds;
public String[] ds;
public String d;
A a;
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
D o = null;
try {
o = (D) super.clone();
a=(A) o.a.clone();//如果这句话没有-浅层拷贝,有-深层拷贝
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}