Java与Go:指针

news2024/11/24 10:25:35

在计算机内存中,每个变量都有一个唯一的地址,指针就是用来保存这个地址的变量。通过指针,我们可以间接地访问和修改存储在该地址处的数据。今天我们来聊一聊Java和Go指针,预告一下,我们需要借助C语言做一些小小的比较。

Java

在Java中,不存在直接的指针概念,而是通过引用来访问对象。Java中的对象是通过引用来操作的,这些引用本质上是对对象的引用,而不是指向内存地址的指针。Java的引用是一种高级抽象,它隐藏了底层内存管理的细节,开发者不需要关心对象的内存分配和释放。Java中的引用可以被认为是一种安全的指针,它提供了更高的抽象级别,可以减少内存管理错误的发生。其实大家第一门编程语言应该就是大一学习的C语言编程吧。当时学习指针的时候很懵,尤其是各种指针运算。后来学Java的对象以及引用再回来看就很好理解。

C
 Student *student = (Student*)malloc(sizeof(Student));
 
 Java
 Student student = new Student();

他们的本质是一样的,都是指向堆空间的某一块地址。之后再回去写C语言,就越写越顺,每次创建变量之前都问自己一句,在栈里还是堆里? 然后决定要不要用指针。

话说回来,sun.misc.Unsafe类提供了一种机制来进行一些底层的、不安全的操作,包括直接操作内存和执行不受限制的任意指针算术运算等。

sun.misc.Unsafe类并不是 Java 标准 API 的一部分,因此它并不受到 Java 平台的正式支持,并且可能在未来的 Java 版本中被移除或更改。它主要被用来实现 Java 核心类库和一些 Java 虚拟机的实现。

通过sun.misc.Unsafe类,你可以直接进行一些底层的内存操作,比如:

  • 分配内存
  • 释放内存
  • 修改内存中的值
  • 进行指针算术运算等
    使用sun.misc.Unsafe类需要谨慎,因为它涉及到底层的内存操作,可能会导致不稳定性和不可预测的结果。此外,由于它不是 Java 标准 API 的一部分,因此在不同的 Java 实现中,它的行为可能会有所不同。

在 Java 9 中,sun.misc.Unsafe类的一些方法被标记为不安全,并且在一些场景下会抛出 java.lang.UnsupportedOperationException 异常,这是为了增强 Java 应用程序的安全性。

总的来说,除非你对 Java 的内存模型和底层运行机制非常了解,并且对使用 sun.misc.Unsafe 类的风险有所认识,并且确实需要进行底层的内存操作,否则不建议使用 sun.misc.Unsafe 类。Java部分就到此结束,毕竟不是重点。

Go 中的指针

Go语言支持指针,但是和C语言中的指针还是有些不同。在Go中,指针是一种数据类型,它指向了一个内存地址,允许你直接访问内存中的数据。与C语言不同的是,Go语言的指针是类型安全的,不允许进行指针运算,从而减少了一些常见的指针错误。

在Go中,你可以通过使用操作符来声明指针变量,使用&操作符来获取变量的地址,使用操作符来获取指针指向的值。

依稀记得当时学习C语言的时候老师引出的指针的第一个例子:将两个int数传入一个方法,希望这两个int互换数值。这里我用Go来写:

package main

import "fmt"

// 定义一个交换函数
func swap(x, y int) {
	var i int = x
	x = y
	y = i
}

func main() {
	// 定义两个整数变量
	a, b := 5, 10

	fmt.Println("Before swapping:")
	fmt.Println("a =", a)
	fmt.Println("b =", b)

	// 调用交换函数,并接收返回值
	swap(a, b)

	fmt.Println("After swapping:")
	fmt.Println("a =", a)
	fmt.Println("b =", b)
}

结果显而易见,我们失败了。然后老师开始长篇大论的解释,然后我就睡着了。其实现在回来再想想很简单,x和y的变量在main的栈帧里面,调用swap方法无非就是创建新的栈帧,并把xy的数值复制一边传递出去。抓捕周树人和我鲁迅有什么关系?

那正确写法就是搞一个指向栈内存的指针。

package main

import "fmt"

// 定义一个交换函数
func swap(x, y *int) {
    temp := *x
    *x = *y
    *y = temp
}

func main() {
    // 定义两个整数变量
    a, b := 5, 10

    fmt.Println("Before swapping:")
    fmt.Println("a =", a)
    fmt.Println("b =", b)

    // 调用交换函数
    swap(&a, &b)

    fmt.Println("After swapping:")
    fmt.Println("a =", a)
    fmt.Println("b =", b)
}

接下来我们再看看数组和指针碰到一起会发生什么

指针和数组

指针指向数组中的某一个元素
var arr [5]int
var ptr *int
ptr = &arr[0] // 将指针指向数组的第一个元素
指针指向数组整体
// 声明一个数组
var arr [5]int
// 声明一个指向数组的指针
var ptr *[5]int
// 将指针指向数组
ptr = &arr

这里要注意类型匹配,我们之前说过长度也是类型的一部分,[5]int和[7]int是不一样的。[5]int要配合*[5]int

眼神要好
var ptrArr *[3]int //指向一个数组
var ptrArr [3]*int //每个元素指向一个数
传递数组

之前我们说过,在方法间传递数组其实是复制整个数组传递过去,相当于寻觅另外一个地方盖一座一模一样的房子。如果我们传递指向数组的指针,函数将能够修改原始数组的值。

func modifyArray(arr *[5]int) {
    // 修改数组的值
    (*arr)[0] = 100
}

func main() {
    var arr [5]int
    modifyArray(&arr)
    fmt.Println(arr) // 输出 [100 0 0 0 0]
}

指针和切片

之前我们已经学过,切片其实就是对数组进行包装,内部通过指针对数组进行操作。那么当切片和指针一起使用时,可以实现更灵活和高效的数据操作,比如动态地管理内存和访问数组的部分元素(二级指针嘛,玩C的都懂)。以下是一些示例,演示了切片和指针的结合使用:

package main

import "fmt"

func main() {
    // 创建一个切片
    slice := []int{1, 2, 3, 4, 5}

    // 创建一个指向切片的指针
    var ptr *[]int
    ptr = &slice

    // 修改切片的值
    (*ptr)[0] = 100
    (*ptr)[1] = 200

    // 打印修改后的切片
    fmt.Println(*ptr) // 输出: [100 200 3 4 5]
}

个人觉得切片指针反而比数组用起来更轻松。map也一样道理:

package main

import "fmt"

func modifyMap(m *map[string]int) {
    // 向 map 中添加新的键值对
    (*m)["d"] = 4
    (*m)["e"] = 5

    // 修改已有键的值
    (*m)["a"] = 100
}

func main() {
    // 创建一个 map
    myMap := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
    }

    // 创建指向 map 的指针
    ptr := &myMap

    // 修改 map 内容
    modifyMap(ptr)

    // 打印修改后的 map
    fmt.Println(*ptr)
}

指针和结构体

在 Go 语言中,指向结构体的指针是一种非常常见的用法基本和C语言一样。结构体是一种用户自定义的复合数据类型,它可以包含多个不同类型的字段,而指向结构体的指针则允许我们直接访问结构体的字段,并且可以在函数之间共享结构体的实例,而不需要进行复制。以下是指向结构体的指针如何使用的详细说明:

创建结构体指针
// 定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    // 创建结构体的指针
    var p *Person
    p = &Person{"John", 30}

    // 或者使用 new() 函数创建结构体的指针
    p = new(Person)
    p.Name = "Alice"
    p.Age = 25
}

可以理解这里的new就相当于(*Person)malloc(sizeof(Person));

操作结构体字段
访问结构体字段:
fmt.Println((*p).Name)  // 打印结构体字段 Name
fmt.Println(p.Age)       // 也可以直接使用 p.Age 访问
修改结构体字段:
p.Name = "Bob"  // 直接赋值修改结构体字段
p.Age = 40
传递结构体指针给函数:
func modifyPerson(p *Person) {
  if p != nil {
    p.Age = 50
  }
}

modifyPerson(p) // 调用函数修改结构体的字段值

总的来说,指向结构体的指针在 Go 中是非常常见的用法,它允许我们在函数间共享结构体的实例,并且可以在需要时直接访问和修改结构体的字段。使用指向结构体的指针可以避免结构体的复制,提高程序的性能和效率。

总结

Java中的指针是被隐藏的,程序员无法直接操作内存地址,而Go中的指针是一等公民,允许直接操作内存地址。本文仅仅介绍了指针操作的冰山一角,之后我们会继续介绍指针在面向对象编程中的应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1532741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jmeter Ultimate Thread Group 和 Stepping Thread Group

线程组:使用复杂场景的性能测试 有时候我们做性能测试时,只依靠自带的线程组,显示满足不了性能测试中比较复杂的场景,下面这两种线程组可以帮助你很好的完成复杂的场景 第一种:Stepping Thread Group 在取样器错误后…

详解ThreadLocal

为什么出现ThreadLocal ? 在多线程环境下,如果多个线程同时修改一个公共变量,可能会出现线程安全问题,即该变量的最终结果可能出现异常。为了解决线程安全问题,JDK提供了很多技术手段,比如使用synchronize…

软考高级:软件架构风格-虚拟机风格概念和例题

作者:明明如月学长, CSDN 博客专家,大厂高级 Java 工程师,《性能优化方法论》作者、《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

练习 10 Web [MRCTF2020]你传你呢

和test5一样,文件上传限制为图片,使用.htaccess文件让上传成功图片木马文件进行执行 开屏暴击,差点去世 尝试上传文件 各种过滤,但是能传图片,这里就不写了,我做过的test5遇到过的重复内容 直接尝试在te…

HarmonyOS/OpenHarmony应用开发-DevEco Studio 在MAC上启动报错

报错截图 报错详细内容 ------------------------------------- Translated Report (Full Report Below) -------------------------------------Process: devecostudio [8640] Path: /Applications/DevEco-Studio.app/Contents/MacOS/devecos…

ab (Apache benchmark) - 压力/性能测试工具

Apache benchmark(ab) 安装window安装使用方法 - bin目录运行使用方法 - 任意目录运行 linux安装 基本命令介绍常用参数:输出结果分析: ab的man手册 安装 window安装 官网下载链接:https://www.apachehaus.com/cgi-bin/download…

docker启动卡死问题排查

问题:输入docker ps 或则vession 卡死,无任何输出 排查思路如下: 1、查看docker状态或者日志 journalctl -u docker.service 或者 systemctl status docker 3月 20 18:23:06 dfbpmyy2 dockerd[1114]: time"2024-03-20T18:23:06.7449…

mysql体系结构及主要文件

目录 1.mysql体系结构 2.数据库与数据库实例 3.物理存储结构​编辑 4.mysql主要文件 4.1数据库配置文件 4.2错误日志 4.3表结构定义文件 4.4慢查询日志 4.4.1慢查询相关参数 4.4.2慢查询参数默认值 4.4.3my.cnf中设置慢查询参数 4.4.4slow_query_log参数 4.4.…

【xr806开发板使用】连接wifi例程实现

##开发环境 win10 WSL ##1、环境配置 参考:https://aijishu.com/a/1060000000287513 首先下载安装wsl 和ubuntu https://docs.microsoft.com/zh-cn/windows/wsl/install (1)安装repo: 创建repo安装目录: mkdir ~/…

练习4-权重衰减(李沐函数简要解析)

环境:练习1的环境 代码详解 0.导入库 import torch from torch import nn from d2l import torch as d2l1.初始化数据 这里初始化出train_iter test_iter 可以查一下之前的获取Fashion数据集后的数据格式与此对应 n_train, n_test, num_inputs, batch_size 20, 100, 200, …

基于cnn深度学习的yolov5+pyqt+分类+resnet+骨龄检测系统

往期热门博客项目回顾: 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别-3d姿态识别 深度学习小白学习路线 YOLOv5与骨龄识别 YOLOv5&a…

C语言指针与地址基础学习(取地址运算)

C语言指针与地址基础学习&#xff08;取地址运算&#xff09; 取地址运算&#xff1a;&运算符取得变量的地址代码示例一运算符& 取地址运算&#xff1a;&运算符取得变量的地址 代码示例一 #include<stdio.h> int main() {int a;a 6;printf("sizeof(i…

通过nginx配置文件服务器(浏览器访问下载)

配置服务器端文件下载和展示(Nginx) nginx.conf文件中增加配置&#xff0c;然后浏览器里访问ip:port回车即可 server { listen port; server_name 服务端ip; # 指定文件下载目录的路径 location / { # 使用root指令来设置文件的根目录 # Nginx会在该目录下寻找相对于loca…

【MySQL】-锁的使用

1、锁的粒度分类 1、全局锁 一般用于数据库备份&#xff0c;整个库只读 FLUSH TABLES WITH READ LOCK 2、表级锁 细分为&#xff1a; 1&#xff09;意向锁 Intention 事务A对表加行级锁&#xff0c;这行记录就只能读不能写。 事务B申请增加表级锁&#xff0c;如果他申请…

【Springboot3+Mybatis】文件上传阿里云OSS 基础管理系统CRUD

文章目录 一、需求&开发流程二、环境搭建&数据库准备三、部门管理四、员工管理4.1 分页(条件)查询4.2 批量删除员工 五、文件上传5.1 介绍5.2 本地存储5.3 阿里云OSS1. 开通OSS2. 创建存储空间Bucket 5.4 OSS快速入门5.5 OSS上传显示文件 六、配置文件6.1 yml配置6.2 C…

linux 命令笔记:gpustat

1 命令介绍 gpustat是一个基于Python的命令行工具&#xff0c;它提供了一种快速、简洁的方式来查看GPU的状态和使用情况它是nvidia-smi工具的一个封装&#xff0c;旨在以更友好和易于阅读的格式显示GPU信息。gpustat不仅显示基本的GPU状态&#xff08;如温度、GPU利用率和内存…

Oracle19C静默安装教程

文章目录 一、安装前的准备1、安装Linux操作系统2、配置网络源或者本地源3、hosts文件配置 二、准备安装环境1、安装依赖包2、创建oracle用户组3、配置系统内核参数4、关闭selinux5、配置oracle用户环境6、修改用户的Shell限制 三、静默安装Oracle数据库1、创建oracle安装目录2…

Oracle19C图形界面安装教程

文章目录 一、安装前的准备1、安装Linux操作系统2、配置网络源或者本地源3、hosts文件配置 二、Oracle19c安装过程1、安装相关软件&#xff1a;2、用户与组&#xff1a;3、修改内核参数&#xff1a;4、资源限制&#xff1a;5、配置用户环境变量&#xff1a;6、创建相关文件目录…

[pytorch] detr源码浅析

[pytorch] detr源码浅析 1. backbone部分2. encoder部分3. decoder部分4. 输出预测 为之后SAM的代码分析做铺垫 1. backbone部分 detr.py中的DETR class class DETR(nn.Module):def __init__(self, backbone, transformer, num_classes, num_queries, aux_lossFalse):...def …

21个 JVM 技术点详解(附面试解答)

最近兄弟们面试&#xff0c;都逃不过被 JVM 问题轰炸的命运&#xff0c;为啥面试官喜欢拿 JVM 说事呢&#xff1f;V 哥认为&#xff0c;除了要问倒你&#xff0c;就是要压你薪水&#xff0c;咱绝对不能怂&#xff0c;俗话说的好&#xff1a;兵来将挡&#xff0c;水来土掩&#…