java中的参数传值以及别名和克隆机制
java中的值传递和引用传递:
? ??? ??? 值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值。
??? ??? ??? 引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,
??? ??? ??? 对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
下面举例说明:
??? ??? ??? 传值---传递基本数据类型参数
??? ??? ??? public??? class?????????? PassValue{
??? ??? ??? ??? static void exchange(int a, int b){//静态方法,交换a,b的值
??? ??? ??? ??????? int temp;
??? ??? ??? ??????? temp = a;
??? ??? ??? ??????? a = b;
??? ??? ??? ??????? b = temp;
??? ??? ??? ??? }
??? ??? ??? ??? public static void main(String[] args){
??? ??? ??? ?????? int i = 10;
??? ??? ??? ?????? int j = 100;
??? ??? ??? ?????? System.out.println("before call: " + "i=" + i + "\t" + "j = " + j);//调用前
??? ??? ??? ??????? exchange(i, j);??????????????????????????????????????????????????????????????????? //值传递,main方法只能调用静态方法
??? ??? ??? ??????? System.out.println("after call: " + "i=" + i + "\t" + "j = " + j);//调用后
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? 运行结果:
??? ??? ??? ??????? before call: i = 10??????? j = 100
??? ??? ??? ??????? after??? call: i = 10??????? j = 100
??? ??? ??? 说明:调用exchange(i, j)时,实际参数i,j分别把值传递给相应的形式参数a,b,在执行方法exchange()时,形式参数a,b的值的改变不影响实际参数i和j的值,
??? ??? ??? ???? i和j的值在调用前后并没改变。
??? ??? ??? ????
??? ??? ??? 引用传递---对象作为参数
??? ??? ??? ? 先理解下:
??? ??? ??? ????? public class Test {?
??? ??? ??? ??? ??? ??? ??? ? public static void main(String[] args) {?
??? ??? ??? ??? ??? ??? ??? ? StringBuffer a = new StringBuffer("A");?
??? ??? ??? ??? ??? ??? ??? ? StringBuffer b = new StringBuffer("B");?
??? ??? ??? ??? ??? ??? ??? ? operate(a,b);?
??? ??? ??? ??? ??? ??? ??? ? System.out.println(a + "," +b);?
??? ??? ??? ??? ??? ??? ??? }?
??? ??? ??? ??? ??? ??? ??? static void operate(StringBuffer x, StringBuffer y) {?
??? ??? ??? ??? ??? ??? ??? ? x.append(y);?
??? ??? ??? ??? ??? ??? ??? ? y =x;??? //这里或者是否可以理解为: y=x这个操作只是把A的引用复制给了B,而对象并未拷贝
??? ??? ??? ??? ??? ??? ??? ? }?
??? ??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? ??? ???
??? ??? ??? ??? ??? ??? ??? /**
??? ??? ??? ??? ??? ??? ??? ? a的值会发生改变
??? ??? ??? ??? ??? ??? ??? ? b的值不变????
??? ??? ??? ??? ??? ??? ??? */
??? ??? ??? ??? ??? ??? ??? x.append(y); 直接改变了引用x指向的对象的值,也就是实参指向的对象的值(形参实参指向同一对象).
??? ??? ??? ??? ??? ??? ??? y=x; 改变了y指向的对象,让y指向x指向的对象,但实参(是一个引用)并不会因此而指向别的对象.
??? ??? ???
??? ??? ???
??? ??? ??? ??? 如果在方法中把对象(或数组)作为参数,方法调用时,参数传递的是对象的引用(地址),即在方法调用时,
??? ??? ??? ??? 实际参数把对对象的引用(地址)传递给形式参数。这是实际参数与形式参数指向同一个地址,即同一个对象(数组),
??? ??? ??? ??? 方法执行时,对形式参数的改变实际上就是对实际参数的改变,这个结果在调用结束后被保留了下来。
??? ??? ??? ??? class Book{
??? ??? ??? ??? ??? String name;
??? ??? ??? ??? ??? private folat price;
??? ??? ??? ??? ??? Book(String n,??? float ){??????????????? //构造方法
??? ??? ??? ??? ??????? name = n;
??? ??? ??? ??? ??????? price = p;
??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? static? void? change(Book a_book,??? String n,??? float p){??? //静态方法,对象作为参数
??? ??? ??? ??? ??????????? a_book.name = n;
??? ??? ??? ??? ??????????? a_book.price = p;
??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? public void output(){??????? //实例方法,输出对象信息
??? ??? ??? ??? ??????? System.out.println("name: " + name + "\t" + "price: " + price);
??? ??? ??? ??? ??? }
??? ??? ??? ??? }
??? ??? ??? ?public class PassAddr{
??? ??? ??? ??? public static void main(String [] args){
??? ??? ??? ??????? Book b = new Book("java2",32.5f);
??? ??? ??? ??????? System.out.print("before call:\t");??????? //调用前
??? ??? ??? ??????? b.output();
??? ??? ??? ??????? b.change(b,"c++",45.5f);?????????????? //引用传递,传递对象b的引用,修改对象b的值
??? ??? ??? ??????? System.out.print("after call:\t");???? //调用后
??? ??? ??? ??????? b.output();
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? 运行结果:
??? ??? ??? ??????? before????? call:????? name:java2??????? price:32.5
??? ??? ??? ??????? after?????? call:????? name:c++????????? price:45.5
??? ??? ??? 说明:调用change(b,"c++",45.5f)时,对象b作为实际参数,把引用传递给相应的形式参数a_book,实际上a_book也指向同一个对象,
??? ??? ??? 即该对象有两个引用名:b和a_book。在执行方法change()时,对形式参数a_book操作就是对实际参数b的操作。???
???
???
???
???
关于别名:
???
什么是别名?
??? public class Aliases{
??? ??? ? int i;
??? ??? ? public Aliases() {
??? ??? ??? i=1;
??? ??? ? }
??? ??? ? public Aliases(int i) {
??? ??? ?? this.i=i;
??? ??? ? }??
??? ??? ? public static void main(String args[]) {
??? ??? ??? Aliases A=new Aliases();
??? ??? ??? Aliases B=A; //A和B指向了同一个对象,A和B互为别名
??? ??? ??? System.out.println("A.i and B.i:"+A.i+" "+B.i);
??? ??? ??? System.out.println("增加B:");
??? ??? ??? B.i++;
??? ??? ??? System.out.println(("A.i and B.i:"+A.i+" "+B.i);
??? ??? ? }
?}
输出:
A.i and B.i:1 1
增加B:
A.i and B.i:2 2?
很明显,A和B指向了同一个对象,B=A这个操作只是把A的引用复制给了B,而对象并未拷贝。
java是通过Rerference来操作对象的,上面是一个显式别名的例子,当你往函数内传递对象时也会发生别名,如下:
??? ??? public class Aliases{
??? ??? ?? int i;
??? ??? ?? public Aliases() {
??? ??? ???? i=1;
??? ??? ?? }
??? ???
??? ??? ? public Aliases(int i) {
??? ??? ??? this.i=i;
??? ??? ? }
??? ???
??? ??? ?? public Increment(Aliases AS) {
??? ??? ??? AS.i++;
??? ??? ? }
??? ???
??? ??? ?? public static void main(String args[]) {
??? ??? ???? Aliases A=new Aliases();
??? ??? ???? System.out.println("A.i before Increment:"+A.i);
??? ??? ???? Increment(A);
??? ??? ???? System.out.println("A.i after Increment:"+A.i);
??? ??? ? }
??? ??? }
??? ???
??? 你可以看到A在经过函数Increment()的调用后i的值发生了变化。
???
???
??? 在某种情况下,你可能不希望传入的对象发生变化,希望函数内的对象只是传入对象的副本,
??? ??? ??? ??? 对这个副本的改变不至于影响原来的对象,那该如何处理?
??? ??? ??? ???
??? 我们知道C++是通过把参数声明了const,就意味着此参数不可改变,
??? 但是别忘了,C++有所谓的拷贝构造函数,所以在函数中的对象确实是拷贝,而java并未支持拷贝构造函数,
??? 原因很明显,java传递对象的引用,你就算拷贝也只是引用的拷贝而已
??? (所以有人说java本质上只有传值)。那么就没办法了吗?有的,那就是“克隆机制”,在根类Object已经定义了clone()方法,
??? 你所要做的只是实现cloneable接口,并覆写clone()方法,典型的应用如下:
??? class CloneClass implements Cloneable{
?? public int aInt;
?? public Object clone(){
???? CloneClass o = null;
???? try{
??????? o = (CloneClass)super.clone();
??? }catch(CloneNotSupportedException e){
??????? e.printStackTrace();
??? }
??? return o;
?? }
? }
? 调用super.clone()方法,它会为你自动处理存储分配和复制操作,有了clone机制,你就可以在
方法调用内部制造一个对象的副本了,它是局域性,对它的任何操作都不至于影响原对象的状态了。
我个人认为,这点对于编写一个安全的大型程序是非常重要的。
class Book implements Cloneable{
??? String name;
??? public Book(String name){
??? ??? this.name = name;
??? }
??? @Override
??? public String toString() {
??? ??? return name;
??? }
??? @Override
??? protected Object clone() throws CloneNotSupportedException {
??? ??? Book o = null;
??? ??? o = (Book)super.clone();
??? ???
??? ??? return o;
??? }
}
/**
?*
?* @author Administrator
?* @see d401.A
?*
?*/
public class A {
??? /**
??? ?* @param a
??? ?* @param b
??? ?*/
??? static void exchange(int a,int b){
??? ??? int temp;
??? ??? temp = a;
??? ??? a = b;
??? ??? b = temp;
??? ??? System.out.println("函数中值的交换:");
??? ??? System.out.println("a="+a+",b="+b);
??? }
???
??? static void exchange(Book a,Book b,String v1,String v2){
??? ??? a.name = v1;
??? ??? b.name = v2;
??? ??? System.out.println("函数中对象的交换:");
??? ??? System.out.println("a="+a+",b="+b);
??? }
???
??? public static void main(String[] args) {
??? ??? int x = 20;
??? ??? int y = 80;
??? ??? exchange(x,y);
??? ??? System.out.println("x="+x+",y="+y);
??? ??? Book z = new Book("i am z");
??? ??? Book w = new Book("i am w");
??? ??? try{
??? ??? ??? exchange((Book)z.clone(),(Book)w.clone(),"value1","value2");
??? ??? }catch(CloneNotSupportedException e){
??? ??? ??? e.printStackTrace();
??? ??? }
??? ??? System.out.println("z="+z+",w="+w);???
??? }
}
/**
* output:
* 函数中值的交换:
* a=80,b=20
* x=20,y=80
* 函数中对象的交换:
* a=value1,b=value2
* z=i am z,w=i am w
*/
Java动态类载入原理可参考:
Java动态类载入机制? http://lfzhs.iteye.com/blog/346621
?