在前几天的帖子《Java性能优化[1]:基本类型 vs 引用类型》里,俺大概介绍了“引用类型”与“基本类型”在存储上的区别。昨天有网友在评论中批评说“引用类型变量和它所引用的对象”没区分清楚,容易混淆。所以今天专门来说一下引用类型的相关细节。
  另外,顺便也把原先的帖子中,关于“两种类型的存储方式”这节补充了一下,加点插图,有助于大伙儿的理解。
  其实,引用类型的变量非常类似于 C/C++ 的指针。为了形象起见,也为了打字方便,本文后面的内容,都把“引用类型的变量”称为【指针】。所以,如果你原先有 C/C++ 背景,今天讲的内容对你来说应该很好理解;否则的话,可能要多琢磨琢磨了。

★创建问题

  假设咱们在【函数中】写了如下这个简单的语句:

StringBuffer str = new StringBuffer("Hello world");

  别看这个语句简单,其实包含了如下三个步骤:
  首先,new 操作符会在【堆】(Heap)里申请了一坨内存,把创建好的 StringBuffer 对象放进去。
  其次,StringBuffer str 声明了一个指针。这个指针本身是存储在【栈】(Stack)上的(因为前面俺说了:此语句写在【函数中】),用来指向某个 StringBuffer 类型的对象。或者换一种说法,这个指针可以用来保存某个 StringBuffer 对象的地址。
  最后,当中这个 等于号(赋值符号)把两者关联起来,也就是把刚申请的那一坨内存的地址保存成 str 的值。

  为了加深列位看官的印象,把上次那篇帖子的图片再拿出来秀一下:

★引用对象之间的赋值、判相等

  通过上述的图解,大伙儿应该明白指针变量和该指针变量指向的【对象】是一个什么关系了吧?
  还是接着刚才的例子,再来看赋值的问题。对于如下语句:

StringBuffer str2 = str;

  这个赋值语句是啥意思捏?实际上就是把 str 的地址复制给 str2;记住,是地址的复制,StringBuffer 对象本身并【没有】复制。所以两个指针指向的是同一个东东。
  再搞一张示意图,如下(今天画这些图可把俺累坏了):

  明白了赋值,判断相等的问题(就是==操作符)也就简单了。当我们写如下语句时,只是判断两个指针的【值】(也就是对象的地址)是否相等,并【不是】判断“被指向的对象”是否内容相同。

if(str2 == str)

  实际上两个指针的值相同,则肯定是指向同一个对象(所以对象内容必定相同)。但是两个内容相同的对象,它们的地址可能不一样(比如克隆出来的多个对象之间,地址就不同)。

★final 常量的问题

  针对引用类型变量的 final 修饰符也是很多人搞混淆的地方。实际上 final 只是修饰指针的值(也就是限定指针保存的地址不能变)。至于该指针指向的对象,内容是否能变,那就管不着了。所以,对于如下语句:

final StringBuffer strConst = new StringBuffer();

  你可以修改它指向的对象的【内容】,比如:

strConst.append("hello world");

  但是【不能】修改它的【值】,比如:

strConst = null;

★传参的问题

  引用类型(在函数调用中)的传参问题,是一个相当扯的问题。有些书上说是传值,有些书上说是传引用。搞得 Java 程序员都快成神经分裂了。所以,我们最后来谈一下“引用类型参数传递”的问题。
  还是拿刚才的例子,假设现在要把刚才创建的那一坨字符串打印出来,我们会使用如下语句:

System.out.println(str);

  这个语句又是什么意思捏?这时候就两说了。
  第一种理解:
  可以认为传进函数的是 str 这个指针,指针说白了就是一个地址的值,说得再白一点,就是个整数。按照这种理解,就是传值的方式。也就是说,参数传递的是指针本身,所以是传值的。
  第二种理解:
  可以认为传进去的是 StringBuffer 对象,按照这种理解,就是传引用方式了。因为我们确实是把对象的地址(也就是引用)给传了进去。
  费了这么多口水,其实不论是“传引用”还是“传值”,都可以讲得通,关键取决于你是【如何看待】参数所传递的【东西】。这就好比量子力学中“光的波粒二象性”,如果你以粒子的方式去测量它,它看起来像粒子;如果你以波动的方式去观测它,它看起来像波动。假如你不太懂量子力学,前面这话就当我没说 :-)

Java 新手进阶:细说引用类型的更多相关文章

  1. 【搞定 Java 并发面试】面试最常问的 Java 并发进阶常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.觉得内容不错 ...

  2. Java 新手的通病

    一:对算法和数据结构不熟悉 为什么我先拿“数据结构和算法”说事捏?这玩意是写程序最最基本的东东.不管你使用 Java 还是其它的什么语言,都离不开它.而且这玩意是跨语言的,学好之后不管在哪门语言中都能 ...

  3. 3.Java异常进阶

    3.JAVA异常进阶 1.Run函数中抛出的异常 1.run函数不会抛出异常 2.run函数的异常会交给UncaughtExceptionhandler处理 3.默认的UncaughtExceptio ...

  4. 史上最全的 Java 新手问题汇总

    史上最全的 Java 新手问题汇总   Java是目前最流行的编程语言之一——它可以用来编写Windows程序或者是Web应用,移动应用,网络程序,消费电子产品,机顶盒设备,它无处不在. 有超过30亿 ...

  5. java中四种引用类型

    java中四种引用类型  今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在 ...

  6. Java字符串进阶

    Java字符串进阶 前言 最常用的对字符串操作的类有三个,分别是String,StringBuilder,StringBuffer,下面将会详细的说说这三个类...... String String类 ...

  7. java 新手必看大全

    背景:c#开发人员 学习java 新手一枚.只适合新手 1:配置java环境 (win10环境参考本目录java环境配置) 2:IDEA 熟悉开发工具 (当初没学java 很大的一个原因就是工具e文 ...

  8. 总结:Java 集合进阶精讲2-ArrayList

    知识点:Java 集合框架图 总结:Java 集合进阶精讲1 总结:Java 集合进阶精讲2-ArrayList 初探: ArrayList底层结构是数组,是List接口的 可变数组的实现,所以会占用 ...

  9. Java 控制类的引用类型,合理使用内存

    Java提供了 java.lang.ref包,该包下的类均与垃圾回收机制相关 先介绍Java对象的集中引用类型 1.强引用 强引用是最常见的,创建对象就是强引用,如 String a = new St ...

随机推荐

  1. Jarvis OJ-Level3-x64

    linux64位ROP技术 #!/usr/bin/env python from pwn import * elf = ELF('level3_x64') Io = remote('pwn2.jarv ...

  2. iOS开发遇到的坑之一: 开发遇见如下错误:Undefined symbols for architecture arm64

    博客处女作,写得不好望谅解! “for architecture arm64”就是说没有支持arm64,在Build settings里architecture相关的几项需要配置正确 在最近升级coc ...

  3. 【Gradle】Downloading https://services.gradle.org/distributions/gradle-3.3-bin.zip 失败

    提示连接超时 Downloading https://services.gradle.org/distributions/gradle-3.3-bin.zip 失败 这时候需要单独去官网下载包,然后放 ...

  4. Springboot(二)-application.yml默认的配置项以及读取自定义配置

    写在前面 ===== spring-boot 版本:2.0.0.RELEASE ===== 读取自定义配置 1.配置文件:sys.properties supply.place=云南 supply.c ...

  5. python爬虫(爬取视频)

    爬虫爬视频 爬取步骤 第一步:获取视频所在的网页 第二步:F12中找到视频真正所在的链接 第三步:获取链接并转换成机械语言 第四部:保存 保存步骤代码 import re import request ...

  6. python 游戏(滑动拼图Slide_Puzzle)

    1. 游戏功能和流程图 实现16宫格滑动拼图,实现3个按钮(重置用户操作,重新开始游戏,解密游戏),后续难度,额外添加重置一次的按钮,解密算法的植入,数字改变为图片植入 游戏流程图 2. 游戏配置 配 ...

  7. 避免使用aireplay-ng指令时出现AP通道不对的方法

    本方法搜集网络:具体使用为在调试网卡为监听模式,使用airodump-ng指令扫描wifi后,需要先执行"airmon-ng stop wlan0"指令,然后再进行一系列抓包等操作 ...

  8. 洛谷 P4961

    目录 题目 思路 Code 题目 戳 为了小埋A了这道题. 思路 读入原来的矩阵,将不是雷的格子更新为数字(数字就是该格子周围八格的雷的个数)将是雷的格子赋值为inf.然后就按照题目要求计算周围八格没 ...

  9. grunt与requirejs结合使用

    // 多个js压缩成一个js // Project configuration. module.exports = function(grunt) { // 使用严格模式 'use strict'; ...

  10. 用openrowset函数操作远程数据库

    OPENROWSET 包含访问 OLE DB 数据源中的远程数据所需的全部连接信息.当访问链接服务器中的表时,这种方法是一种替代方法,并且是一种使用 OLE DB 连接并访问远程数据的一次性的.特殊的 ...