云栖问答

找不到答案?去提问题

Java核心技术 2018-10-30 00:04:30

[@倚贤][¥20]什么是值传递和引用传递?

什么是值传递和引用传递?

3个回答

0

倚贤

在 C/C++ 中,区分点是传值和传址。传值很好理解,就是把一个变量的值传递给另外一个变量。那变量的本质是什么,变量是指代一个内存的区域。值就是这个内存区域里的值。那凭什么变量能指代这个内存区域呢?这是编译器帮我们搞定的,编译期其实变量就会变成一个指向内存区域的地址。变量其实是一个地址。好,那传址是啥意思呢?就是把一个变量所指代的地址赋值给另外一个变量。注意是变量所指代的地址,不是地址对应内存区域的值。

理解了传值和传址的区别,我们再来看 java 里的传引用。传值和传址在汇编层面就有的功能,其实是底层机器码就支持的。C/C++ 只是向上保留了这个功能。那 Java 凭什么又多出来了一个传引用。其实本质上传引用就是传址。只是 Java 做了个阉割,变量所指代的地址不能取出来赋给另外一个变量做为值。有没有发现 Java 中没有指针型变量?Java 的原生类型都是值变量,只能传值。对象型变量都是一维指针。不允许出现高维指针。因为都是一维指针,那也没有必要加个 * 号特别标记是指针变量了。

0

禅师

"值传递"和"引用传递"这个称谓,一般是 .NET 平台(C#, F#, VB.NET 等等) 使用的术语。

  1. 默认对于 class 类型变量传参是引用传递 - 传递的参数实例的引用;
  2. 对于 struct 类型变量的传参是值传递,也可以在加在 ref 声明,指定使用为引用传递;
  3. 注意 string 类有那第一点点不寻常,虽然也是按引用传递,但对 string 参数的赋值实际上是将其指向了另一个 string 实例,所以表现起来比较像是按值传递,而实例是按引用传递。
using System;

namespace Demo
{
    public struct Student
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }

    public class Contact
    {
        public string Name { get; set; }
        public string Email { get; set; }
    }

    public static class Program
    {

        public static void TestStruct(Student student, int number) // 默认按值传递
        {
            student.Name = "student name";  //  此修改不会影响到方法调用者中的 stuct
            ++number;
        }

        public static void TestStructByRef(ref Student student, ref int number) // ref 强制改为按引用传递
        {
            student.Name = "student name";  //  此修改*会*影响到方法调用者中的 student
            ++number;
        }

        public static void TestClass(Contact contact) // 默认按引用传递
        {
            contact.Name = "contact name";  //  此修改*会*影响到方法调用者中的 contact
        }

        public static void TestString(String hello) // 默认按引用传递
        {
            hello = "hello, world";   //  此修改不会影响到方法调用者中的 hello
            Console.WriteLine(hello); //  will print "hello, world;
        }

        public static void TestStringOut(out String hello) // 默认按引用传递
        {
            hello = "hello, world";   //  此修改不会影响到方法调用者中的 hello
            Console.WriteLine(hello); //  will print "hello, world;
        }

        static void Main(string[] args)
        {
            Student student = new Student();
            student.Name = "new student";
            Console.WriteLine(student.Name);

            int number = 0;
            TestStruct(student, number);     // struct 默认按值传递
            Console.WriteLine(student.Name); // will write "new student" ##
            Console.WriteLine(number);       // will write 0
            Console.WriteLine();

            number = 0;
            TestStructByRef(ref student, ref number);
            Console.WriteLine(student.Name); // will write "student name" ##
            Console.WriteLine(number);       // will write 1
            Console.WriteLine();

            Contact contact = new Contact();
            contact.Name = "new contract";
            Console.WriteLine(contact.Name); // will write "new contact"

            TestClass(contact);              // class 默认按引用传递
            Console.WriteLine(contact.Name); // will write "contact name" ##
            Console.WriteLine();

            String hello = "hello";
            TestString(hello);
            Console.WriteLine(hello);        // will write "hello";

            hello = "hello";
            TestStringOut(out hello);
            Console.WriteLine(hello);        // will write "hello world";
        }

    }
}

0

janius

这个问题主要体现在方法入参上。
如果方法的入参是基本数据类型,那就是值传递,方法里如果对该入参的值做了变更,方法执行后该入参保持原来的值不便。
如果方法的入参是对象,则反之。

1
GO
815
浏览
0
收藏
邀请他人回答
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本...

RDS是一种稳定可靠、可弹性伸缩的在线数据库服务。支持MySQL、SQL Server、PostgreSQL、高...