当前位置: 首页 > news >正文

Go语言 和 Java语言对比理解系列一:函数参数传递

文章目录

    • 传对象
      • 对象赋值
        • Go
        • Java
      • 对象字段修改
        • Go
        • Java
        • Go修改字段如何实现类似Java的效果
    • 传数组
    • 总结

Go和Java都是 值传递,传递的是参数的副本。但两者都区分参数是 值类型还是 引用类型

  • 对于Java来说,8中基本数据类型是值类型,数组和对象属于引用类型;
  • 对于Go来说,int,string,float,bool,数组和struct是值类型,指针、slice、map、channel、接口、函数等是引用类型。

Go语言里的struct在感觉上更像是Java中属于引用类型的对象。但事实并不是。

  • Go语言中用于描述对象的struct属于值类型,而Java中的对象属于引用类型;
  • Go语言中的数组属于值类型,而Java中的数组属于引用类型。

下面分别用代码来掩饰他们在传参上的区别。

传对象

对象赋值

Go

// 定义User结构体
type User struct {
   Name string
   Age int
}

// 定义一个全局的user
var guser User = User {
   "yyyy",
   28,
}

// 定义一个函数,参数为User结构体“对象”,将全局guser指向传递过来的User结构体“对象”
func modifyUser(user User) {
   fmt.Printf("参数user的地址 = %p\n",&user) 
   fmt.Printf("guser修改前的地址 = %p\n",&guser)
   fmt.Println("guser修改前 = ",guser)
   // 修改指向
   guser = user
   fmt.Printf("guser修改后的地址 = %p\n",&guser)
   fmt.Println("guser修改后 = ",guser)
}

func main() {
   var u User = User {
      "xxxx",
      29,
   }
   fmt.Printf("将要传递的参数u的地址 = %p\n",&u)
   modifyUser(u)
}

执行结果:

将要传递的参数u的地址 = 0xc0000ac018
参数user的地址 = 0xc0000ac030
guser修改前的地址 = 0x51c080
guser修改前 =  {yyyy 28}
guser修改后的地址 = 0x51c080
guser修改后 =  {xxxx 29}

Java

public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public String print() {
        return "{name = " + name + ",age = " + age + "}";
    }
}

public class Demo {
    private static User guser = new User("yyyy",28);
    public static void modifyUser(User user) {
        System.out.println("参数user的地址 = " + user);
        System.out.println("guser修改前的地址 = " + guser);
        System.out.println("guser修改前 = " + guser.print());
        guser = user;
        System.out.println("guser修改后的地址 = " + guser);
        System.out.println("guser修改后 = " + guser.print());
    }
    public static void main(String[] args) {
        User u = new User("xxxx", 29);
        System.out.println("将要传递的参数u的地址 = " + u);
        modifyUser(u);
    }
}

执行结果:

将要传递的参数u的地址 = com.example.User@7d2ac533
参数user的地址 = com.example.User@7d2ac533
guser修改前的地址 = com.example.User@4ef01483
guser修改前 = {name = yyyy,age = 28}
guser修改后的地址 = com.example.User@7d2ac533
guser修改后 = {name = xxxx,age = 29}

通过上述两个程序的执行结果可以分析出如下结论:

  • Go传入函数参数的是原对象的一个全新的copy(有自己的内存地址);Java传入函数参数的是原对象的引用的copy(指向的是同样的内存地址)。
  • Java对象之间赋值是把对象内存的 内容(字段值等) copy过去,所以才会看到guser修改前后的地址不变,但是对象的内容变了;Java对象之间的赋值是把对象的 引用 copy过去,因为引用指向的地址变了,所以对象的内容也变了。

对象字段修改

Go

// 定义User结构体
type User struct {
   Name string
   Age int
}

// 定义一个函数,参数为User结构体“对象”,修改其Name字段
func modifyName(user User) {
   fmt.Println("修改前user.Name = ",user.Name)
   // 修改Name字段
   user.Name = "yyyy"
   fmt.Println("修改后user.Name = ",user.Name)
}

func main() {
   var u User = User {
      "xxxx",
      29,
   }
   modifyName(u)
   fmt.Println("执行修改函数后参数u.Name = ",u.Name)
}

执行结果:

修改前user.Name =  xxxx
修改后user.Name =  yyyy
执行修改函数后参数u.Name =  xxxx

Java

public class Demo {
    private static User guser = new User("yyyy",28);

    public static void modifyName(User user) {
        System.out.println("修改前user.Name = " + user.getName());
        user.setName("yyyy");
        System.out.println("修改后user.Name = " + user.getName());
    }

    public static void main(String[] args) {
        User u = new User("xxxx", 29);
        modifyName(u);
        System.out.println("执行修改函数后参数u.Name = " + u.getName());
    }
}

执行结果:

修改前user.Name = xxxx
修改后user.Name = yyyy
执行修改函数后参数u.Name = yyyy

基于上面对对象赋值的理解,理解字段修改就更容易了:

  • Go修改的是一个全新对象(有自己的内存地址)的字段值,不影线原来对象,所以会出现函数里修改成功了,但是原来的参数对象还是没变。
  • Java修改的是同一个对象,所以函数里修改成功了,原来的参数对象也跟着变了。

Go修改字段如何实现类似Java的效果

既然Java传递的是引用,那我们也可以让Go传 指针(传递的是对象地址,指向的是同一个对象内存)来实现同样的效果:

// 定义User结构体
type User struct {
   Name string
   Age int
}

// 定义一个函数,参数为User结构体“对象指针”,修改其Name字段
func modifyNameByPointer(user *User) {
   fmt.Println("修改前user.Name = ",(*user).Name)
   // 修改Name字段
   (*user).Name = "yyyy"
   fmt.Println("修改后user.Name = ",(*user).Name)
}

func main() {
   var u User = User {
      "xxxx",
      29,
   }

   modifyNameByPointer(&u)
   fmt.Println("执行修改函数后参数u.Name = ",u.Name)
}

传数组

数组的情况和struct一样,最后的结论也可以参考上面**[传对象]**的结论,这里就不再赘述。感兴趣的也可以参考上面的程序自己验证一下。

总结

  • Go里面struct和数组属于值类型;Java里的对象和数组属于引用类型
  • Go对struct和数组的函数传递赋值操作,是复制一块新的内存,与原有的数据相互独立,互不影响

相关代码请参考:

  • https://gitee.com/xujian01/blogcode/tree/master/src/main/java/parampass
  • https://gitee.com/xujian01/blogcode_go/tree/master/parampass

相关文章:

  • Transformer模型学习笔记
  • 14.Vue3过渡和动画实现
  • SCS【7】单细胞转录组之轨迹分析 (Monocle 3) 聚类、分类和计数细胞
  • EMQX Cloud全托管的 MQTT 消息云服务
  • 【软考 系统架构设计师】操作系统① 操作系统概述
  • ARC113E Rvom and Rsrev
  • Windows与网络基础-26-IP地址概述
  • 模拟用户登录功能的实现以及演示SQL注入现象
  • 天龙八部科举答题问题和答案(全3/8)
  • CH342芯片应用—硬件设计指南
  • 【Android】-- 如何使用按钮和图片(点击事件、长按点击、同时展示文本和图像、ImageView)
  • 什么是文件格式的幻数
  • 【数据结构】绪论
  • C++的4种管理数据内存的方式
  • 中秋节的月亮怎么拍?不用手机和相机,程序员照样能拍出大片的感觉
  • 深入了解以太坊
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • Fabric架构演变之路
  • JavaScript 基本功--面试宝典
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • 闭包,sync使用细节
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 理解在java “”i=i++;”所发生的事情
  • 试着探索高并发下的系统架构面貌
  • 我建了一个叫Hello World的项目
  • Nginx实现动静分离
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # 数论-逆元
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (07)Hive——窗口函数详解
  • (1)(1.13) SiK无线电高级配置(六)
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (笔试题)合法字符串
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • .md即markdown文件的基本常用编写语法
  • .net 怎么循环得到数组里的值_关于js数组
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • ??myeclipse+tomcat
  • @RequestMapping-占位符映射
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [ CTF ]【天格】战队WriteUp- 2022年第三届“网鼎杯”网络安全大赛(青龙组)
  • [ JavaScript ] JSON方法
  • [100天算法】-不同路径 III(day 73)
  • [100天算法】-实现 strStr()(day 52)
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [ACTF2020 新生赛]Include