Java的引用到底是什么?和C/C++的指针有什么区别?

[TOC]

点进这篇文章的朋友们,如果对「指针」没有概念,那么请面壁思过。

你不是一个正统的程序员,你是野路子,是faker,在技术这条路上注定走不远。

<img src="https://wanger-article.oss-cn-hangzhou.aliyuncs.com/img/住嘴.jpg" alt="住嘴" style="zoom:33%;" />

闲话少述,正文开始。

1、从操作符说起

要看「引用」和「指针」的区别,首先要看操作符。

  • 在c/c++中,指针相关的操作符有3个:**& -> ***
  • 在Java中,引用相关的操作符有1个:.

What,引用就一个操作符???那我们就来看下,操作符各有什么作用

注:指针使用结构体来举例,便于和引用的对象来比较

1.1、C/C++中指针操作符 & -> * 的作用

  • 定义一个结构体和变量

    typedef stuct {
        int sex;
        int age;
    } student_t;
    
    student_t stu1 = {1, 20};
    
  • 操作符&,将数据地址读取到一个指针

    int* p_addr = &stu1; // 创建一个指针p_addr,p_addr存储了stu1的地址
    
  • 操作符->,读/写一个指针所指向结构体地址成员数据

    int age = p_addr->age;
    p_addr->age = 44;
    
  • 操作符*****,读/写一个指针地址数据

    student_t stu2 = *p_addr; // 将p_addr地址的数据读取到stu2
    *p_addr = {2, 8}; // 将数据写入p_addr地址
    

注:c++中也有引用,但不在本文讨论范围内

1.2、Java中引用操作符 . 的使用

  • 定义一个类和对象

    public class Student{
        public Integer sex;
        public Integer age;
        
        Student(Integer s, Integer a) {
            sex = s;
            age = a;
        }
    }
    Student stu1 = new Student(1, 20); // 创建一个引用stu1,stu1中存储的不是对象的数据,而是是对象的地址,也即引用
                                       // stu1存放在stack,对象存放在heap
    
  • 数据地址读取到一个引用

    Student p_addr = stu1; // 创建一个引用p_addr,把stu1中存储的对象的地址,赋给p_addr
    
  • 读/写一个引用所指向对象地址成员数据

    Integer age = stu.age;
    stu.age = 44;
    

    注:Java只有引用,没有指针,而引用弱化了地址和数据的概念,所以程序员们更要深刻理解引用的本质,写出更健壮的代码。

<img src="https://wanger-article.oss-cn-hangzhou.aliyuncs.com/img/小机灵鬼.jpg" alt="小机灵鬼" style="zoom:33%;" />

如此看来,C/C++指针的操作符 * 能干的活,Java的引用干不了,也就是指针能直接对地址的数据进行读/写,引用则不能

那咱就来看看,具体那些活是指针能干,引用干不了。。。

2、指针能干,引用干不了的活~

2.1、指针可以指向任意一个地址,引用只能指向一个对象

  • 指针可以给用操作符&给其一个数据的地址,也可以直接给其一个地址甚至空地址

    student_t* p_addr = &stu1;
    student_t* p_addr = 0x12000;
    student_t* p_addr = NULL;
    
  • 指针可以对地址进行加减操作,从而修改相邻地址的数据,比如修改一个数组

    int data[4] = {1,2,3,4};
    int* p_addr = data;
    *p_addr = 6;
    p_addr += 1;
    *p_addr = 7;
    p_addr += 1;
    *p_addr = 8;
    p_addr += 1;
    *p_addr = 9;
    // 此时数组内数据为:{6,7,8,9}
    
  • 引用只能指向一个对象,不能直接给其一个地址也不能空引用

    Student stu = new Student();
    Student stu = 0x12000; // 对不起,编译不通过。。。
    

2.1.1、有什么用?

在底层驱动开发时,寄存器的地址是固定的,

  • 想要修改寄存器的数据,需创建一个指针,把寄存器地址赋给指针,然后去修改寄存器。

    // 点亮一个LED
    int* p_led_addr = 0x1233; // LED寄存器地址是0x1233,将其赋给指针p_led_addr
    *p_led_addr = 1; // LED亮
    *p_led_addr = 0; // LED灭
    int state = *p_led_addr; // 读取LED的亮灭状态
    
  • 修改连续地址的多个寄存器

    // 点亮多个LED
    int* p_led_addr = 0x1233; // LED寄存器地址是0x1233,将其赋给指针p_led_addr
    *p_led_addr = 1; // LED亮
    *(p_led_addr+1) = 1; // LED2亮
    *(p_led_addr+2) = 1; // LED3亮
    

显而易见,引用能不能干???干不了!

2.2、指针可以随意修改所指向地址的数据

  • 指针大法

    student_t* p_addr = &stu1; // 创建Student类型的指针,指向一个stu1
    *p_addr = 24242; // 将24242写入stu1的地址
    
  • 引用只能修改所指向对象的固定成员,或者通过所指向对象提供的固定方法来修改数据

  • 有什么用?

    • 好像没啥用。。。

3、指针的缺陷

3.1、野指针

  • 定义
    • 指针在创建时,未初始化,此时指向的地址是随机的!此时指针读写,破坏程序运行!
    • 指针所指向地址的数据已经被释放,此时指针读写,则破坏程序运行!
  • 原因
    • 指针可以指向任意一个地址;而引用必须指向一个确定的对象
    • 指针不能自动解除指向;而引用在指向的对象销毁时,会自动解引用
  • 后果
    • 程序奔溃、不能按预期运行、代码漏洞

3.2、C语言强制类型转换造成的内存误修改

  • 定义
    • 将类型A的变量s,强制转换成类型B,然后将其s的地址赋给指向类型B的指针p,对指针p读写
    • 此时类型B的数据结构可能并不兼容类型A,导致对变量s的误修改
  • 原因
    • C语言强制类型转换的不严格检查,过于粗鲁
    • 这是C++为什么要引入四个转换符的原因
  • 后果
    • 程序奔溃、不能按预期运行、代码漏洞

4、总结

4.1、引用能做到的,指针都能无损的做到——反之则不行

  • 指针的操作符 * 能干的活,引用干不了,也就是指针能直接对地址的数据进行读写,引用则不能

  • 指针可以指向任意一个地址(甚至空地址),引用只能指向一个对象(不可空引用)

    • 指针可以对地址进行加减操作,从而修改相邻地址的数据,比如修改一个数组
    • 指针不能自动解除指向;而引用在指向的对象销毁时,会自动解引用
  • 指针可以随意修改所指向地址的数据

    • 引用只能修改所指向对象的固定成员,或者通过所指向对象提供的固定方法来修改数据

4.2、指针的灵活带来缺陷,引用的不灵活带来安全

引用避免了对地址的直接读写,增强了内存操作的规范,从而增强了语言内存安全性,降低了对开发者的要求。

指针和引用,各有各的用途,我们理解本质后,在不同的场景选择合适的工具即可!

[图片上传失败...(image-d16b87-1649148823549)]

4.3、题外话:C++引用和Java引用的区别

C++中一个引用指向的地址不会改变,改变的是指向地址的内容,然而Java中引用指向的地址在变!

如果非要对比着看,那么Java中的“引用”倒是和C/C++的指针更像一些,和C++的“引用”很不一样。

java去除指针概念,就用引用罗...

你看 java:

A a = new A(1); 
A b = new A(2); 
b = a; 

没有问题,a 和 b引用同一个对象A(2),原来的A(1)成为没有被引用的对象。 垃圾回收机制会在之后的某个时刻把A(1)干掉。

而C++则不然。C++的引用就语义上说是“别名”【本质是个const指针,又叫指针常量】,而并不是指针的另一种用法:

A a = A(1); 
A b = A(2); 
A& c = b; //c 是 b的别名 
c = a; //并不是 c 引用 a,而是拷贝操作 c.operator= ( a ) 

就语言机制来说,java的引用是用来管理和命名对象;

而,C++的引用机制是很纯粹的,就是别名而已,一旦定义就无法修改,即无法再指向其他变量。

每种语言的特性都是整体的有机部分。

我们知道, java的引用机制是一个很复杂的机制。他必须区分“基本对象”和“复合对象”,你可以想象一下,如果其中没有基本对象,那么我们如何完成对象的复制? 唯一的解决方案是提供两个等于号,或者一律用构造函数.... 但是综合来看,他和垃圾回收形成了相当完美的组合方案

而C++ 的引用机制为运算符重载提供了大幅度的支持。C++ 的引用是用类“模拟”基本对象的根本要求。 如果C++使用java那种引用,那么原本漂亮的 operator[]、 proxy class 等就很难实现了。 更进一步, C++ 的运算符重载对 C++ 的模版机制提供了强力的支持

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容