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