A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 史卜坤 中级黑马   /  2012-7-9 22:37  /  3286 人查看  /  12 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

public class Qcb90 {
   
int a;
   
int b;
   
public void f() {
               a
= 0;
        b
= 0;
        
int[] c = { 0 };
        g(b, c);
        System.out.println(a
+ " " + b + " " + c[0] + " "); //为什么输出的是1 0 1 啊????
    }
   
public void g(int b, int[] c) {
        a
= 1;
        b
= 1;
        c[
0] = 1;
    }
   
public static void main(String args[]) {
        Qcb90 obj
= new Qcb90();
        obj.f();
    }
}
输出结果是101

评分

参与人数 1技术分 +1 收起 理由
刘笑 + 1 赞一个!

查看全部评分

12 个回复

倒序浏览
java 中的 参数传递方式是 传值,基本类型不用多说,对于引用类型传递的是那个对象的引用地址

对于这个程序:g(b, c);  实际上就是g(0,0),而不是把 a b 的引用传进去了,
在方法内部:
public void g(int b, int[] c) {
        a = 1;
        b = 1;
        c[0] = 1;
    }
这里面的  a b c 已经和 类中定义的不一样了,他们只是局部变量,只在这个方法内部有效,

所以你打印的 值 一直都没有改变
回复 使用道具 举报
你的解释说不通啊,其实在g(b,c)传递参数时要考虑形参和实参、参数类型和参数顺序问题,
当b被传递时按顺序是应该执行a=1;c原本就是数组类型,所以只有执行c[0]=1;
也就是说g(int b, int[] c)中的b是形参,实参是a,按取值顺序取得是a=2;,  g(b, c)= g(a=2, c[0] = 1);
回复 使用道具 举报
本帖最后由 万宝东 于 2012-7-9 23:47 编辑

先运行一下这个程序:  
public class Qcb90 {

    int a;
    int b;
    public void f() {   //第三步:将 a b赋值 定义 c数组
        a = 0;
        b = 0;
        int[] c = { 0 };
        g(b, c);     //第四步:调用g()方法
        System.out.println(a + " " + b + " " + c[0] + " "); //为什么输出的是1 0 1 啊????
     }
    public void g(int b, int[] c) {    //程序执行到这里重点来了 ,首先调用g方法将a的值变为1,然后g(int b, int[] c)这里面的 b 和 c 是形参,与 f方法中的b c (这2个是实参)不是一个东西,参数传递时,对于int型传递的是值,这里强调一下,
                                                 //只是把b的值传进来,没有把b传进来,
                                                   //此时g方法中将b的值变为1,但是这只是在g方法中有效,如果在g方法中打印b的值,b的值是1,但是对于成员变量b的值没有影响,所以b的值不变,依然是0.接下来是c数组,由于数组传递的是引用,他们指向的
                                                    //都是同一个对象,所以在g方法中利用 c[0] = 1; 将数组的值改变了 ,改变了对象的内容,原数组的引用还是指向这个对象,所以他的值也会跟着变化,变为1.所以最后打印的是101

        a = 1;
        b = 1;
        c[0] = 1;
    }
    public static void main(String args[]) {
        Qcb90 obj = new Qcb90();   //第一步:new一个对象
        obj.f();     //第二步,调用飞f()方法
    }
}
对于值传递需要明白
java的函数参数传递有两种情况:
1,基本数据类型是传递值,包括String
2,object和其他自定义的数据类型或者对象,是传递引用的,也就是可以修改值,然后返回

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
我把你的代码稍微修整了一下,加了几个this,这样比较容易理解
public class Qcb90 {
    int a;   //成员变量,在对内存中
    int b;   //成员变量,同上

    public void f() {
        this.a = 0;   //访问的是成员变量a
        this.b = 0;   //访问的是成员变量b
        int[] c = { 0 };  //这里是一个局部变量int[] c
        g(b, c);          //注意这里是b是值传递,而c是引用传递
        System.out.println(a + " " + b + " " + c[0] + " ");
    }

    public void g(int b, int[] c) {  //这里的int[] c 和f()中的指向的是同一个
        this.a = 1;   //这里访问的也是成员变量a
        b = 1;        //注意,这里访问的是参数中的局部变量b,处于栈内存中,成员变量b不是同一个
        c[0] = 1;     //修改了 f()中的那个int[] c 中的 c[0]
    }

    public static void main(String args[]) {
        Qcb90 obj = new Qcb90();
        obj.f();
    }
}
再附上两张图:


1.PNG (22.64 KB, 下载次数: 62)

1.PNG

2.PNG (31.71 KB, 下载次数: 68)

2.PNG

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 陈冲 于 2012-7-10 00:01 编辑
  1. public class Qcb90
  2. {
  3.     int a;
  4.     int b;
  5.     public void f()
  6.     {
  7.         a = 0;
  8.         b = 0;
  9.         int[] c = { 0 };
  10.         g(b, c);//此处调用g()方法,此处的b只是将b=0的值传入,而不是访问定义的方法f()中定义的变量b
  11.         System.out.println(a + " " + b + " " + c[0] + " "); //为什么输出的是1 0 1 啊????
  12.     }
  13.     public void g(int b, int[] c)//在调用该方法时,该方法进入栈内存,其内部定义的变量也入栈
  14.     {                      //在方法调用结束时,该方法出栈,局部变量b=1也出栈,所以b的值没有变化
  15.         a = 1;
  16.         b = 1;
  17.         c[0] = 1;
  18.     }
  19.     public static void main(String args[])
  20.     {
  21.         Qcb90 obj = new Qcb90();
  22.         obj.f();
  23.     }
  24. }
复制代码
回复 使用道具 举报
这大哥源码都上来了
回复 使用道具 举报
上面很详细了
回复 使用道具 举报
高原 发表于 2012-7-9 23:43
我把你的代码稍微修整了一下,加了几个this,这样比较容易理解
public class Qcb90 {
    int a;   //成员 ...

哥们,你真强。示意图都画出来了。
回复 使用道具 举报

public class Qcb90
{
    int a; //定义全局变量a、整个程序都可访问
    int b; //定义全局变量b、整个程序都可访问
    public void f()
   {
        a = 0; //对a进行赋值
        b = 0;  //对b进行赋值
        int[] c = { 0 };
        g(b, c);// 调用g函数
        System.out.println(a + " " + b + " " + c[0] + " "); //所以这里打印的是1 0 1
    }
    public void g(int b, int[] c)//b为值传递,c为地址传递
    {
        a = 1; //因为a为全局变量所以这里可以访问。即可从新赋值
        b = 1; //因为b为值传递所以这里对b从新赋值不会影响到函数f里面b的值。
        c[0] = 1;// 因为c为地址传递所以这里对c[0]进行从新赋值会影响到函数f里面的c[0]的值
    }
    public static void main(String args[])
    {
        Qcb90 obj = new Qcb90();
        obj.f();
    }
}

这个问题牵扯到两个知识点:1.成员变量与局部变量的问题    2调用函数时的值传递,地址传递的问题。这两个问题明确了就能解决这个疑问了。
首先成员变量与局部变量:局部变量指在程序中,只在特定过程或函数中可以访问的变量,是相对与成员变量而言的。成员变量也称外部变量,是在函数外部定义的,作用域为从变量定义处开始,到本程序文件的末尾。全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。

再有调用函数时参数的传递:(1)按值传递参数时,是将实参变量的值复制一个到临时存储单元中,如果在调用过程中改变了形参的值,不会影响实参变量本身,即实参变量保持                    调用前的值不变。(2)按地址传递参数时,把实参变量的地址传送给被调用过程,形参和实参共用内存的同一地址。在被调用过程中,形参的值一旦改变,相应实参的值也跟着改变。
回复 使用道具 举报
java和C一样,传参都是值传递的,g(int b,int[] c)的两个形参,在参数传递时,将值传递过去,数组传递的是数组的首地址,在方法体中,当局部变量与成员变量同名时,直接使用变量是指的局部变量,引用成员变量的方法是this.变量名(在static方法中不能使用this关键字).
回复 使用道具 举报
java和C一样,传参都是值传递的,g(int b,int[] c)的两个形参,在参数传递时,将值传递过去,数组传递的是数组的首地址,在方法体中,当局部变量与成员变量同名时,直接使用变量是指的局部变量,引用成员变量的方法是this.变量名(在static方法中不能使用this关键字).
回复 使用道具 举报
public class Qcb90 {
    int a;   //定义了成员变量a,在堆内存中,并且可以作用于Qcb90类中。
    int b;   //同上。

    public void f() {
        a = 0;   //由于a在f()方法外定义了成员变量,所以这里定义的a可以访问到成员变量a。
        b = 0;   //同上。
        int[] c = { 0 };  //这里是定义了一个int型的数组c并明确了数组中的元素为0.并且作用于f()方法的区间内。不能被外部访问。
        g(b, c);          //注意这里的是b是实际参数的传递,而int[] c是引用型变量,所以是引用传递。
        System.out.println(a + " " + b + " " + c[0] + " ");
    }

    public void g(int b, int[] c) {  
        a = 1;      //访问的是成员变量a,那么a的值就改变为了1.
        b = 1;     //这里访问的是参数中的局部变量b,因为b是传值,而这个"值"是b的一个拷贝,b的值在传递后的改变只是改变了b的拷贝的内容,并没有改变真正的b的值
        c[0] = 1;  //都是同一个对象,所以在g方法中利用 c[0] = 1; 将数组的值改变了 ,改变了对象的内容,原数组的引用还是指向这个对象,所以他的值也会跟着变化。
    }

    public static void main(String args[]) {
        Qcb90 obj = new Qcb90();//创建对象。
        obj.f();
    }
}
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马