黑马程序员技术交流社区

标题: 一个让人凌乱的输出结果 [打印本页]

作者: 郑明君    时间: 2012-7-20 17:13
标题: 一个让人凌乱的输出结果
  1. public class TestPrimitiveTransfer {
  2.     public static void swap (int a, int b){
  3.         int tmp = a;
  4.         a = b;
  5.         b = tmp;
  6.     }
  7.     publicstatic void main(String[] args){
  8.         int a = 6;
  9.         int b = 9;
  10.         swap(a, b);
  11.         System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);
  12.     }
  13. }
复制代码
为什么输出: 参a的值是6;  参b的值是 9

作者: 夏儒日    时间: 2012-7-20 17:32
呵呵。。。这个结果不凌乱撒。。。你了解了函数的参数传递的一些细节就明白其中的原委了。

01.public class TestPrimitiveTransfer {

02.    public static void swap (int a, int b){

03.        int tmp = a;

04.        a = b;

05.        b = tmp;

06.    }

07.    publicstatic void main(String[] args){

08.        int a = 6;

09.        int b = 9;

10.        swap(a, b);

11.        System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);

12.    }

13.}
当函数的传递参数是基本类型的变量时,改函数一结束,改变量也就被释放,也就是说当基本类型的变量作为实参传递,并不能改变主程序中同名局部变量的值。如你的程序中,在swap()函数里面,a和b的值确实进行了交换,in可以在该函数里面加一句System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);进行验证,只是该swap()一结束,a=9,b=6的内存也就随之释放,故此时输出打印的仍然是主函数中同名局部变量的值,即a=6,b=9.
具体情况更多细节你可以查看:http://bbs.itheima.com/forum.php?mod=viewthread&tid=19871
希望对你有所帮助。
作者: 陈世涛    时间: 2012-7-20 17:34
程序执行的顺序如下:
   程序从主函数开始,
    main函数进栈,
     里面有了a=6,b=9,
     然后调用swap(int a,int b)方法,
      swap(int a,int b)方法就进栈了。
      调用里面的方法,进行a与b 的交换。
      swap(a,b)执行完就结束了。
     那swap(int a,int b)也出栈了,方法运行的结果并没有被调用。
    所有打印输出的a与b还是main函数里的。
作者: 韩爽    时间: 2012-7-20 17:42
public class TestPrimitiveTransfer {

    public static void swap (int a, int b){

        int tmp = a;

        a = b;

        b = tmp;

    }
没有返回值。
正常应该是:
public class TestPrimitiveTransfer {

    public static int  swap (int a, int b){

        int tmp = a;

        a = b;

        b = tmp;

    return a,b;
    }
VOID 没有返回值  只有int,string 等类型才会有返回值。
return.
这个的输出结果是:参a的值是9;  参b的值是 6
作者: 郑明君    时间: 2012-7-20 17:46
韩爽 发表于 2012-7-20 17:42
public class TestPrimitiveTransfer {

    public static void swap (int a, int b){

您说的,我一点都看不懂
作者: 梁小波    时间: 2012-7-20 17:46
这里的是java的一个特性;和c\c++有点区别;
一方面来说:java中的基本数据,即不是对象的那些数据类型;如int,long,double,float,boolean等;是按照值传递的,不是按应用传递;
也就是说,swap中接受的变量是接受了a,b的值,并不知道是a,b变量;所以这种方法是不可以交换变量的;

如果想深一步了解的话:从内存角度来说:基本类型数据是在常量池中存储的;也就是说在程序加载类的时候就加载在内存中了;不是等main开始执行;
而你的swap函数是在java运行时加载swap时加载的,并且加载到了栈中;也就是说在栈中修改了临时变量a,b。但在常量池中的a,b依旧没有改变;而你输出的时候
栈中的swap的数据和内容帧早已变成垃圾;输出的是常量池中的;自然没有改变;

多了解jvm或者是java内存的分配与运行,有助于理解java程序的运行原理;
我推荐刚看到的一篇文章:深度解析Java内存的原型;http://sd.csdn.net/a/20120629/2806999.html
虽然写的内容格式很乱,但很有借鉴意义
作者: 郑明君    时间: 2012-7-20 17:47
夏儒日 发表于 2012-7-20 17:32
呵呵。。。这个结果不凌乱撒。。。你了解了函数的参数传递的一些细节就明白其中的原委了。

01.public clas ...

高见。。
作者: 郑明君    时间: 2012-7-20 17:47
陈世涛 发表于 2012-7-20 17:34
程序执行的顺序如下:
   程序从主函数开始,
    main函数进栈,

高见。too
作者: 韩爽    时间: 2012-7-20 17:49
郑明君 发表于 2012-7-20 17:46
您说的,我一点都看不懂

那看不懂? 传参必须要有返回值.
作者: 苑占丽    时间: 2012-7-20 17:50
咋一看楼主写的代码貌似没错,但仔细看看就发现问题了

public class TestPrimitiveTransfer {

    public static void swap (int a, int b){//这个方法能实现交换功能没错,注意方法的返回类型是void空类型,
                   //即使交换成功了,也不能把交换后的值反馈给调用者呀。所以楼主要想实现输出交换后的a,b的值直接在这个交换方法里写一条输出语句即可

        int tmp = a;

        a = b;

        b = tmp;
System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);//就是这个语句

    }

    publicstatic void main(String[] args){

        int a = 6;

        int b = 9;

        swap(a, b);

    // 把这句注释掉看下运行结果   System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);//它输出的只会是a,b原来的值,因为调用的方法并没有把改变后的值反馈给它。

    }

}

结果如下图:


作者: 郑明君    时间: 2012-7-20 17:51
梁小波 发表于 2012-7-20 17:46
这里的是java的一个特性;和c\c++有点区别;
一方面来说:java中的基本数据,即不是对象的那些数据类型;如 ...

必须有借鉴意义。恩,,, 一看这手笔,就很老道。。呵呵。谢谢
作者: 苑占丽    时间: 2012-7-20 17:55
韩爽 发表于 2012-7-20 17:49
那看不懂? 传参必须要有返回值.

不见得把,传参也可以不用有返回值呀,直接void,写一条输出语句,输出交换后的值,然后调用者调用这个方法的时候同样能达到一样的效果呀。
作者: 京鱼龙    时间: 2012-7-20 17:55
本帖最后由 罗京雨 于 2012-7-20 17:57 编辑

public class TestPrimitiveTransfer {
    public static void swap (int a, int b){
        int tmp = a;
        a = b;
        b = tmp; //在这里运行完的数值和主函数一点关系都没有,直接弹栈了
    }
    publicstatic void main(String[] args){
        int a = 6;
        int b = 9;
        swap(a, b);    //这句话是迷惑性的,相当于废话
        System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b); //所以输出的还是你定义的a=6,b=9的值。
    }
}

弹栈.JPG (47.04 KB, 下载次数: 31)

弹栈.JPG

作者: 郑明君    时间: 2012-7-20 18:00
苑占丽 发表于 2012-7-20 17:50
咋一看楼主写的代码貌似没错,但仔细看看就发现问题了

public class TestPrimitiveTransfer {

你搞错我的意图了。要是真想要输出结果达到交换状态,那么我写的代码和你一样。但是我就想写这么个例子,问问底层JVM是怎么实现的。
作者: 郑明君    时间: 2012-7-20 18:05
韩爽 发表于 2012-7-20 17:49
那看不懂? 传参必须要有返回值.

也可以没有的。:lol:victory:
作者: 郑明君    时间: 2012-7-20 18:07
罗京雨 发表于 2012-7-20 17:55
public class TestPrimitiveTransfer {
    public static void swap (int a, int b){
        int tmp = a ...

恩。。很详细。还有图解,真是个大好人呢~~
作者: 陌花╮有意、    时间: 2012-7-20 18:12
public class TestPrimitiveTransfer {
    public static void swap (int a, int b){
        int tmp = a;
        a = b;
        b = tmp;
    }
    publicstatic void main(String[] args){
        int a = 6;
        int b = 9;
        swap(a, b);
        System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);
    }
}

由于传的是基本数据类型,所以swap()函数中参与运算的变量丝毫不影响主函数,函数结束相应变量就释放
如果传入一个引用数据类型就不同了,比如说数组

public class TestPrimitiveTransfer {
public static void swap(int[] arr, int a, int b) {
  int tmp = arr[a];
  arr[a] = arr[b];
  arr[b] = tmp;
}
public static void main(String[] args) {
  int arr[] = { 6, 9 };
  int a = 0;
  int b = 1;
  System.out.println("开始数组的值:");
  for (int i = 0; i < arr.length; i++) {
   System.out.println(arr[i]);
  }
  swap(arr, a, b);
  System.out.println("交换结束后的值:");
  for (int i = 0; i < arr.length; i++) {
   System.out.println(arr[i]);
  }
}
}

结果:
开始数组的值:
6
9
交换结束后的值:
9
6

作者: 郑明君    时间: 2012-7-20 18:19
陌花╮有意、 发表于 2012-7-20 18:12
public class TestPrimitiveTransfer {
    public static void swap (int a, int b){
        int tmp = a ...

为什么说引用类型的就不一定了呢。那是一定呢。还是一定不呢? 但是你给的例子证明,引用类型的变量一定被改变了,是吗?
作者: 苑占丽    时间: 2012-7-20 18:20
本帖最后由 苑占丽 于 2012-7-20 18:26 编辑
郑明君 发表于 2012-7-20 18:00
你搞错我的意图了。要是真想要输出结果达到交换状态,那么我写的代码和你一样。但是我就想写这么个例子, ...

那好吧,看到楼上的好多回复,我还想再补充一点:
代码稍微改动了一点
public class TestP {

    public  static int swap (int a, int b){

        int tmp = a;

        a = b;

        b = tmp;
//        System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);
     return a;//不能同时 return a,b;会报错,只能有一个返回值,此时a的值为9
    }

    public static void main(String[] args){

        int a = 6;

        int b = 9;

        swap(a, b);

//        System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);
        System.out.println("交换后a的值变为"+swap(a, b));
    }

}
运行结果是这样的:

写这个,我就是想说明你赞同的楼上的这句话"但在常量池中的a,b依旧没有改变;而你输出的时候
栈中的swap的数据和内容帧早已变成垃圾;输出的是常量池中的;自然没有改变
;"我有异议
在主函数里 swap(a, b);这句话确实是改变了a,b的值,又怎回是没用的呢?通过返回值可以看到,而主函数输出swap的数据的和内容的时候,确实可以的呀

作者: 陌花╮有意、    时间: 2012-7-20 18:31
郑明君 发表于 2012-7-20 18:19
为什么说引用类型的就不一定了呢。那是一定呢。还是一定不呢? 但是你给的例子证明,引用类型的变量一定 ...

值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值。
引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
作者: 郑明君    时间: 2012-7-20 18:33
苑占丽 发表于 2012-7-20 18:20
那好吧,看到楼上的好多回复,我还想再补充一点:
代码稍微改动了一点
public class TestP {

但是我输出的是 a 而不是 带返回值的swap(int a, int b);  你醒 了吗?
作者: 苑占丽    时间: 2012-7-20 18:34
本帖最后由 苑占丽 于 2012-7-20 18:36 编辑
郑明君 发表于 2012-7-20 18:33
但是我输出的是 a 而不是 带返回值的swap(int a, int b);  你醒 了吗?

返回值也是a的值呀

返回值都没有,你怎么可能输出方法里改变的值

其实根本就没有他们说的那么复杂
作者: 郑明君    时间: 2012-7-20 18:38
苑占丽 发表于 2012-7-20 18:34
返回值也是a的值呀

返回值都没有,你怎么可能输出方法里改变的值

咱QQ说吧。我Q252544239
作者: 龚建锋    时间: 2012-7-20 19:18
可以试着这样编写。
class HuHuan
{
        public static void main(String[] args)
        {               int a=22;
                int b=33;
                jiaoHuan(a,b);
               
        }
        public static void jiaoHuan(int a,int b)
        {
             
               
                int temp=a;
                a=b;
                b=temp;
                System.out.println(a+"  "+b);
        }
}

作者: 韩爽    时间: 2012-7-21 19:54
苑占丽 发表于 2012-7-20 17:55
不见得把,传参也可以不用有返回值呀,直接void,写一条输出语句,输出交换后的值,然后调用者调用这个方 ...

是,我明白你的意思,那样输出可以严重是否传参是否传过去了,但是这样是让他多学习是是返回值,以后不能什么都这样直接输出的。你说对不,但是他告诉我理论对,呵呵,我说的她都不懂,我真无语了。
作者: 苑占丽    时间: 2012-7-21 19:57
韩爽 发表于 2012-7-21 19:54
是,我明白你的意思,那样输出可以严重是否传参是否传过去了,但是这样是让他多学习是是返回值,以后不能 ...

呵呵,对。我也表示很无语呀。。。。
作者: 韩爽    时间: 2012-7-21 20:01
苑占丽 发表于 2012-7-21 19:57
呵呵,对。我也表示很无语呀。。。。

他估计是本科生,还是零基础,这个就的这样写,我Q549444333 你也女孩子么?
作者: 苑占丽    时间: 2012-7-21 21:07
韩爽 发表于 2012-7-21 20:01
他估计是本科生,还是零基础,这个就的这样写,我Q549444333 你也女孩子么? ...

是呀,我是女生
作者: 封明川    时间: 2012-7-21 21:27
public class TestPrimitiveTransfer {
    public static void swap (int a, int b){
        int tmp = a;
        a = b;
        b = tmp;
    }
    publicstatic void main(String[] args){
        int a = 6;
        int b = 9;
        swap(a, b);
        System.out.println("交换结束后,参a的值是" + a + ": 参b的值是" + b);
    }
}

为什么输出: 参a的值是6;  参b的值是 9
因为在swap方法中定义了两个局部变量用于计算传入的值,计算后交换的是这两个局部变量的值,所以在main函数中定义的两个变量是没有变的




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2