JAVA方法参数传递的是值还是引用

// 先看案例一:

publicclass TestMain{

 

       public static voidmain(String[] args) {

               List<Integer>list= new ArrayList<Integer>();

              for (int i= 0; i< 10; i++) {

                       list.add(i);

              }

               add(list);

              for (Integer j :list) {

                       System.err.print(j+",");;

              }

               System.err.println("");

               System.err.println("*********************");

               String a="A";

               append(a);

               System.err.println(a);

              int num=5;

               addNum(num);

               System.err.println(num);

       }

       

       static voidadd(List<Integer> list){

               list.add(100);

       }

       

       static voidappend(String str){

               str+="is a";

       }

       static voidaddNum(int a){

               a=a+10;

       }

}

打印出来的结果是:
0,1,2,3,4,5,6,7,8,9,100,

*********************
A
5


//  案例二

public class TestFinal {

/**
* @param args
*/
static int num1= 5;
int num4 = 0;
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
add(list);
for (Integer j : list) {
System.err.print(j+",");;
}
System.err.println("");
System.err.println("*********************");
String a="A";
append(a);
System.err.println(a);
//分析 static的加载时机问题
int num2 = 5;
addNum(num1);
addNum(num2);
//在类加载时加载,故这里打印  5,因为 addNun()调用是在类加载时进行的,加载时直接将 5传入方法中
System.err.println("-----------num1 = "+num1);//  5
System.err.println("-----------num2 = "+num2);//  5

//区分 下面情况
TestFinal t = new TestFinal();
int num3 = 5;
t.addNum3(num3);
//这里num3跟addNum3(num3)中的num3不是同一个变量,如果addNum3()有返回int值,那么这里就会
//返回重新赋值给原num3,这时就会打印 15
System.out.println("-----------num3 = "+num3+"-----------");// 5  
t.num4 = 5;
t.addNum3(t.num4);
System.out.println("-----------t.num4 = "+t.num4+"-----------");// 5
}

static void addNum(int a){
System.out.println("addNum : "+a);
a += 10;
System.out.println("addNum : "+a);
}

public void addNum3(int n){
System.out.println("addNum3 : "+n);
n += 10;
System.out.println("addNum3 : "+n);
}
static void add(List<Integer> list){
System.out.println("说明:static 加载时机");
list.add(100);
}

static void append(String str){
str+="is a";
}
/**
* 打印结果:
0,1,2,3,4,5,6,5
15
7,8,9,100,
*********************
A
-----------5
*/
}


分析原因:



参数传递基本上就是赋值操作

java中方法参数传递方式是按值传递。

如果参数是基本类型,传递的是基本类型的字面量值的拷贝。

如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。

值传递与引用传递,在计算机领域是专有名词,如果你没有专门了解过,一般很难自行悟出其含义。而且在理解下面的解释时,请不要把任何概念往你所熟悉的语言功能上套。很容易产生误解。比如Reference,请当个全新的概念,它和C#引用类型中的引用,和C++的&,一点儿关系都没有。

 

值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递的内容的类型(内容指:是值类型还是引用类型,是值还是指针)。值类型/引用类型,是用于区分两种内存分配方式,值类型在调用栈上分配,引用类型在堆上分配。(不要问我引用类型里定义个值类型成员或反之会发生什么,这不在这个本文的讨论范畴内,而且你看完之后,你应该可以自己想明白)。一个描述内存分配方式,一个描述参数求值策略,两者之间无任何依赖或约束关系。


第一个例子:基本类型

void foo(int value) {

    value = 100;

}

foo(num); // num 没有被改变

 

第二个例子:没有提供改变自身方法的引用类型

void foo(String text) {

    text ="windows";

}

foo(str); // str 也没有被改变

 

第三个例子:提供了改变自身方法的引用类型

StringBuilder sb = new StringBuilder("iphone");

void foo(StringBuilder builder) {

   builder.append("4");

}

foo(sb); // sb 被改变了,变成了"iphone4"。

 

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。

StringBuilder sb = new StringBuilder("iphone");

void foo(StringBuilder builder) {

    builder = newStringBuilder("ipad");

}

foo(sb); // sb 没有被改变,还是 "iphone"。





”java程序设计语言总是采用值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。“

Java总是采用call by value
方法参数有2种类型:
1.基本数据类型(int,double,....)
2.对象引用
如果说你是call by reference 那么下面的代码将会交换A , B2个对象
void swap( test A , test B ) {
test C = A;
A = B;
B = C;
}
然而 你可以去试一下 并没有交换。 交换的只是拷贝出来的2个test对象。
总结来看
1.一个方法不能修改一个基本数据类型的参数
2.一个方法可以改变一个对象参数的状态
3.一个方法不能让对象参数引用一个新的对象

PS:来源Java 核心技术卷I


附上Java类加载机制部分会更容易理解

1.Personp=new Person("zhangsan",20);
该句话所做的事情:
1.
在栈内存中,开辟main函数的空间,建立main函数的变量 p
2.
加载类文件:因为new要用到Person.class,所以要先从硬盘中找到Person.class类文件,并加载到内存中。
加载类文件时,除了非静态成员变量(对象的特有属性)不会被加载,其它的都会被加载。
记住:加载,是将类文件中的一行行内容存放到了内存当中,并不会执行任何语句。---->加载时期,即使有输出语句也不会执行。
静态成员变量(类变量)  ----->方法区的静态部分
静态方法             ----->方法区的静态部分
非静态方法(包括构造函数)  ----->方法区的非静态部分
静态代码块 ----->方法区的静态部分
构造代码块 ----->方法区的静态部分

注意:在Person.class文件加载时,静态方法和非静态方法都会加载到方法区中,只不过要调用到非静态方法时需要先实例化一个对象,对象才能调用非静态方法。如果让类中所有的非静态方法都随着对象的实例化而建立一次,那么会大量消耗内存资源,
所以才会让所有对象共享这些非静态方法,然后用this关键字指向调用非静态方法的对象


3.
执行类中的静态代码块:如果有的话,对Person.class类进行初始化。
4.
开辟空间:在堆内存中开辟空间,分配内存地址。
5.
默认初始化:在堆内存中建立对象的特有属性,并进行默认初始化。
6.
显示初始化:对属性进行显示初始化。
7.
构造代码块:执行类中的构造代码块,对对象进行构造代码块初始化。
8.
构造函数初始化:对对象进行对应的构造函数初始化。
9.
将内存地址赋值给栈内存中的变量p
2.p.setName("lisi");
1.
在栈内存中开辟setName方法的空间,里面有:对象的引用this,临时变量name
2.
p的值赋值给this,this就指向了堆中调用该方法的对象
3.
"lisi" 赋值给临时变量name
4.
将临时变量的值赋值给thisname
3.Person.showCountry();
1.
在栈内存中,开辟showCountry()方法的空间,里面有:类名的引用Person
2.Person
指向方法区中Person类的静态方法区的地址。
3.
调用静态方法区中的country,并输出。
 
注意:要想使用类中的成员,必须调用。通过什么调用?有:类名、thissuper



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值