出了一个面试题,如下:
请写出下面代码的运行结果,并解释为什么?
using System;
public class Test1
{
    public static void Main()
    {
        int num = 0;
        Person p = new Person("Li");
        A1(p, num);
        Console.WriteLine("{0},{1}", p.name, num);
    }
    static void A1(Person p, int num)
    {
        p = new Person("Wang");
        num = 1;
    }
}
public class Person
{
    public string name;
    public Person(string name)
    {
        this.name = name;
    }
}
10个人面试,10个人都回答错误,难道这题很难?
这是我在实际开发中遇到过的问题,所以列入了面试题中
你也来回答看看
并说说有没有必要面试这种题目

解决方案 »

  1.   

    Person p = new Person("Li");   int num = 0;
    输出的是这两个..不可能10个人都回答错误.
      

  2.   

    调用A1的时候
    两个p都引用Li那个对象,后来,第二个p引用了Wang,这对第一个p不会影响
    两个num存储在不同位置,更不会相互影响了
    所以,Li 0
      

  3.   

    这个不难吧?
    Li,0关键是分析这个函数:A1(Person p, int num)
    P是以引用形式传进来的,num是以值形式传进来的,所以在Al()中对num的修改不会返回到调用Al()的函数中;
    Al()函数中的p是引用,所以对P的修改会影响p的值,但引用也是复制后传到Al()函数中的,所以对P的副本重新赋值不会影响到p,但对p副本的属性赋值会影响到p,这大概就是引用;
      

  4.   

        int num = 0;
            Person p = new Person("Li");
            A1(p, num);
           
    这句话打印的变量是局部的,更上面A1(p,num)没有关系。
     Console.WriteLine("{0},{1}", p.name, num);
      

  5.   


    using System;
    public class Test1
    {
        public static void Main()
        {
            int num = 0;
            Person p = new Person("Li");
            A1(p, num);
            Console.WriteLine("{0},{1}", p.name, num);
        }
        static void A1(Person p, int num)
        {
            p.name = "Wang";
            num = 1;
        }
    }
    public class Person
    {
        public string name;
        public Person(string name)
        {
            this.name = name;
        }
    }
    就不同了
      

  6.   

    悄悄的路过顺便bs一下c#既然学java,就干脆学到底,偏偏关键字改个大小写,这不是吃饱了撑的嘛。。Main:main
    string:String
      

  7.   

    using System;
    public class Test1
    {
        public static void Main()
        {
            int num = 0;
            Person p = new Person("Li");
            A1(p, num);
            Console.WriteLine("{0},{1}", p.name, num);
        }
        static void A1(Person p, int num)
        {
            p.name = "Wang";
            num = 1;
        }
    }
    public class Person
    {
        public string name;
        public Person(string name)
        {
            this.name = name;
        }
    }
    如果改成这样,输出Wang, 0
    此时,A1中引用的是p的地址,所以当p值改变后,Main中的p也变。
      

  8.   

    Main不能小写,但是C#支持String(类名),string只是别名
      

  9.   

    结果是Li,0,因为在main方法里重新赋值了,将原来的wang和1覆盖了
      

  10.   

    就java角度来讲,只有传值,就是将值拷贝一份传给函数。那么,修改拷贝的东西,对原来的东西当然没影响。btw:我的意思是,既然什么都学java,为啥要改main的大小写呢?害得我代码考过去还要修改
      

  11.   

    A1(Person p, int num)
    {
        p = new Person("Wang"); //这里的p指向的是一个新开辟的内存块。呼~其实就这么简单。
      

  12.   

    引用类型变量: p形参是实参引用的复制,开始是指向li。 后来指向新的wang。 没有采用p.Name方式修改,而是开了一个新对象。
     因为是复制的引用,所以没有影响到原来的p (没有采用p.Name方式修改)。所以结果还是第一个对象li。
      

  13.   

    就凭  p.name 这一条,扣他这个月奖金。
      

  14.   

    结果 Wang,0
    对象方法中的对象类型按引用传递,值对象按值传递.
    所以int按值传递,方法中的修改不影响变量本身的值.
    Person p是对象,按引用传递,方法中的操作会影响对象.就这样.
      

  15.   

    lz的理解是错误的,这里哪里来的引用传递?以错考错,都是错...
        public static void Main()
        {
            int num = 0;
            Person p = new Person("Li");//称其为p1...
            A1(p, num);//p1引用的副本,不是p1了...
            Console.WriteLine("{0},{1}", p.name, num);
        }
        static void A1(Person p, int num)//p1引用的副本...
        {
            p = new Person("Wang");//称其为p2...与p1不相干,与p1引用的副本也不相干...
            num = 1;
        }
    知其然不知其所以然...同意39楼的意见...
      

  16.   

    我不是以这种角度考虑的。Person p = new Person("Li");static void A1(Person p, int num)
    {
            p = new Person("Wang");我是以内存块的角度考虑的。这两个new出来的内存块是独立的。其实这个就够了。
      

  17.   

    方法里都new Person()了,
    就不是原来的实例的引用了,构造器会重新分配内存空间存放新实例
    基础知识啊
      

  18.   

    嗯,如果在方法里,发现原变量已经不能再用,为什么不提早释放呢?
    在这个示例里是一个简单类,如果是关键性的东东,比如换另一个数据库连接……
    按你的说法,C#就不应该提供ref out这样的关键字了?
      

  19.   

    我认为答案是wang,1。
    经过A1(P,num)调用后,原p赋值"Li"将更改为"Wang",同时num也会更改为1。
      

  20.   


    其实这不是答题人的问题 是阁下自己都不知道为什么namhyuk其实是理解了意思 但是说法可能欠妥当或者说准确
      

  21.   

    cj205: 其实这不是答题人的问题 是阁下自己都不知道为什么 namhyuk其实是理解了意思 但是说法可能欠妥当或者说准确愿闻其详,请大虾指点
      

  22.   

    难道.NET阵营如此鱼龙混杂真的是.NET门槛太低所致?...回去好好看看书或MSDN...在C#中除非显式以ref或out声明才会按引用传递参数否则全是按值传递!不是说引用类型就会按引用传递!误区!至于后面的值类型...你还是认真学习吧...
      

  23.   

    形参同样是在栈上开辟临时空间对实参进行拷贝,值类型的是拷贝的值,而引用类型是拷贝的地址,被调用的方法中操作的是形参
    如果引用类型得成员被重新赋值了,那么实参的成员也会改变,因为他们操作的是同一个地址,如果形参被new了,那么形参和实参没有了任何关系了
    值类型形参和实参本来就没有关系,当然以上情况强制引用除外
      

  24.   


    首先我声明一下我不是什么大虾
    其次在CSDN里对事不对人 希望LZ不要介意这里,p是一个引用,num是一个值。对p赋值的时候,实际上把一个对象付给了这个引用。但问题是,p本身是值,包含了实参的值,也就是A1(p, num);这个调用中的p的内容(指向Person对象的引用)。如果在函数A1中修改了p的内容,只是修改了参数p的指向,而不是外面调用时的那个实参p。
    至于void A1(ref Person p, ref int num){} 在这种声明下,当调用A1时,编译器会把实参p的地址作为参数传递进去,此时修改参数,改的是实参p的地址内的东西
      

  25.   

    前面的大牛们都说了.
    其实可以这样理解咯:
    对一个引用对象,引用的指针(p1)放在栈,指针所指向的是对象内容放在堆.
    调用一个函数,
    这时,会在栈上把p1复制一份(值复制),形成p2,同样,p2和p1一样也是指向堆中同一个地址的.
    即在
        static void A1(Person p, int num)
        {
            p = new Person("Wang");
            num = 1;
        }
    中,参数Person p,即为p2,
     p2 = new Person("Wang");
    使p2指针指向了一个新申请的堆中的位置.
    结果,p2的值变了.p1的值没有变.
    所以,主函数:
    Console.WriteLine("{0},{1}", p.name, num);
    时,p.name,即为p1所指向的内容.所以是
    li
    不知我理解得对不对?
      

  26.   

    Li 0 是值传递加ref就传地址
      

  27.   

    其实这两个参数都是值传递,num就不用说了,它是值类型,所以传递到方法中的是它的副本,而p是引用类型,但是它没有加ref或者out,所以它是以值传递引用类型,引用类型的变量不直接包含其数据;它包含的是对其数据的引用。当通过值传递引用类型的参数时,有可能更改引用所指向的数据,如某类成员的值。但是无法更改引用本身的值;也就是说,不能使用相同的引用为新类分配内存并使之在块外保持。
    在楼主的示例中,p为引用类型,在未使用 ref 参数的情况下传递给方法A1。在此情况下,将向方法传递指向p的引用的一个副本。但是在A1方法中使用 new 运算符来分配新的内存部分,将使A1中的p引用新的Person,因此,这之后的任何更改都不会影响原始Person p(它是在 Main 内创建的)。实际上,本示例中创建了两个Person对象,一个在 Main 内,一个在 A1 方法内
      

  28.   

    看看这个呢
     
    using System;
        public class Test1
        {
            public static void Main()
            {
                int num = 0;
                Person p = new Person("Li");
                A1(ref p, num);
                Console.WriteLine("{0},{1}", p.name, num);
                Console.Read();
            }
            static void A1(ref Person p, int num)
            {
                p = new Person("Wang");
                num = 1;
            }
        }
        public class Person
        {
            public string name;
            public Person(string name)
            {
                this.name = name;
            }
        }
      

  29.   

    实际上
    A1(Person p)
    {
       p = new Person("Wang");
    }

    A1()
    {
       Person x = new Person("Wang");
    }是一样的。这个意义上,传这个引用变量的人有些弱智。
      

  30.   

    还在这纠缠不清...重申一次...你这个问题和引用类型还是值类型毫无关系...仔细看我在57楼、77楼的答复...还有90楼ojlovecd的答复...
      

  31.   

    void fun(int i)
    fun(ival);
    编译器会把ival复制到栈上,作为参数。这样,i实际上是在栈上,你修改i,只修改了栈上的内容,等到退出函数,栈回滚,i的内容也就消失了
    void fun(int* i)
    fun(&ival)
    此时的参数类型是指针,编译器会把ival的地址作为参数的值压到栈里,这样,参数i实际上就是指向ival的指针,修改这个指针指向的内容可以修改对象(*i=...),但如果只修改i,就是修改了指针的内容,对ival的值没有影响这是从C++上面来理解的 不知道是不是我误会了阁下的说法了
      

  32.   

    传ref p时就有点像C语言里传指针的指针的味道了。