V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
sophie2805
V2EX  ›  Java

一道简单的笔试题,可是我有点想不通

  •  
  •   sophie2805 · Jul 13, 2015 · 5032 views
    This topic created in 3942 days ago, the information mentioned may be changed or developed.
    class Value{
    public int i=15;
    }
    public class Test{
    public static void main(String argv[]){
    Test t=new Test( );
    t.first( );
    }

    public void first( ){
    int i=5;
    Value v=new Value( );
    v.i=25;
    second(v,i);
    System.out.println(v.i);
    }

    public void second(Value v,int i){
    i = 0;
    v.i = 20;
    Value val = new Value( );
    v = val;
    System.out.println(v.i+" "+i);
    }
    }
    21 replies    2015-07-13 17:06:58 +08:00
    sophie2805
        1
    sophie2805  
    OP
       Jul 13, 2015
    答案是
    15 0
    20


    为啥不是
    15 0
    15

    second方法调用结束的时候,v此时其实是指向val的对吗?那v.i不就是15吗
    sophie2805
        2
    sophie2805  
    OP
       Jul 13, 2015
    自己也在IDEA里面运行了,单步了,确实是
    15 0
    20

    为啥~~从second结束,回到first方法里面,v.i就变成20了。。。苍天呐,为啥啊
    sampeng
        3
    sampeng  
       Jul 13, 2015   ❤️ 1
    你需要了解函数的参数传值以及对象在内存里面真实结构的相关知识
    传值引用、传址引用
    kalintw
        4
    kalintw  
       Jul 13, 2015   ❤️ 2
    @sophie2805

    原因是second中这行代码:
    v.i = 20;

    java的对象做形式参数,是按对象指针传值的。
    second传参传进来的v是first中v的“值”拷贝。也就是说,这两个v变量本身在内存中是两块地方,是两个对象指针变量。 但是它们指向的地址(也就是对象内容的内存结构)是一样的。就好比你大名如花,小名阿花,指向的都是你。

    second传参传进来的v, 和first中v,指向的都是first中new出来的那个Value对象,同一块内存内容。你在second中通过拷贝v修改了该对象的i为20。然后在first中再通过原来的v访问,当然也是20。
    BuilderQiu
        5
    BuilderQiu  
       Jul 13, 2015   ❤️ 3
    他从来没变过,一直都是20.

    主要搞清这一步:
    Value val = new Value( );
    v = val;

    这个对原来的v没有什么卵用,只是将v指向val的地址了,后续操作v都是操作的val。

    原来:
    v →address1 → Value[i=20] (原来的)
    执行了之后(前面说的要搞清的那一步):
    v →address2 → Value[i=15] (新new的)

    原来的v---address1的指向断了而已,后续操作的是address2的内容。

    最后一个输出的是原来的address1对应的Value的值,所以还是20,没变过。
    gangsta
        6
    gangsta  
       Jul 13, 2015   ❤️ 1
    yuankui
        7
    yuankui  
       Jul 13, 2015   ❤️ 1
    要能区分什么时候传值,什么时候传引用~
    这个道题就很好理解力.
    sophie2805
        8
    sophie2805  
    OP
       Jul 13, 2015
    @kalintw 懂了!

    除了基础类型外,其他类型传的都是引用~

    如果题目改一下,second方法有返回值,且返回值是v, first里面v = second(...)

    这样的话,输出的就应该是
    15 0
    15
    sophie2805
        9
    sophie2805  
    OP
       Jul 13, 2015
    @BuilderQiu 懂了!

    兄台解释的好粗犷,很受用
    zhy
        10
    zhy  
       Jul 13, 2015   ❤️ 1
    传引用就是传引用的值,类似一个指针
    java只有pass by value
    nozama
        11
    nozama  
       Jul 13, 2015   ❤️ 1
    应该加个third, 考装箱拆箱
    suikator
        12
    suikator  
       Jul 13, 2015 via Android   ❤️ 1
    java方法参数传递只有唯一的一种形式,那就是传的所有东西都是拷贝。就算是传引用,传的也是引用的拷贝。但由于是引用,传之前和传之后都指向了同一个对象。

    v=val 在方法体内改变了引用的指向之后,传之前和传之后就指向了不同的对象。

    说错了你来打我呀
    jeansfish
        13
    jeansfish  
       Jul 13, 2015   ❤️ 1
    C#可以加个ref就是楼主想的了
    lujiajing1126
        14
    lujiajing1126  
       Jul 13, 2015 via Android   ❤️ 1
    java只有值传递

    对象的值传递是通过对指针的复制做到的,所以你把复制的指针指向另一个对象,对之前的对象没有影响
    codeyung
        15
    codeyung  
       Jul 13, 2015
    值传递
    upupxjg
        16
    upupxjg  
       Jul 13, 2015
    被代码格式折磨了半天,Format后发现原来真的考的是引用传递和值传递...
    楼主不是单步了吗,看看new Value的时候 v的地址!
    jziwenchen
        17
    jziwenchen  
       Jul 13, 2015
    尼玛 我以为多大的问题 这很基础呀! 对象是按引用传递的.
    codeyung
        18
    codeyung  
       Jul 13, 2015
    这种问题 你那流程工具一搞比我们说的都清楚
    jziwenchen
        19
    jziwenchen  
       Jul 13, 2015
    @BuilderQiu 额 不要用地址(很容易误解为内存的地址)去解释吧? 最好解释成别名.
    vmskipper
        20
    vmskipper  
       Jul 13, 2015
    我们公司最爱考这个题
    ryd994
        21
    ryd994  
       Jul 13, 2015 via Android
    如果这样就是你想要的效果了
    public void second(Value &v,int i)
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3616 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 62ms · UTC 11:08 · PVG 19:08 · LAX 04:08 · JFK 07:08
    ♥ Do have faith in what you're doing.