第2章 Java编程基础 - 引用、指针和句柄的区别

优质
小牛编辑
132浏览
2023-12-01

句柄是一种特殊的智能指针 。当一个应用程序要引用其他系统(如数据库、操作系统)所管理的内存块或对象时,就要使用句柄。

句柄与普通指针的区别在于,指针包含的是引用对象的内存地址,而句柄则是由系统所管理的引用标识,该标识可以被系统重新定位到一个内存地址上。这种间接访问对象的模式增强了系统对引用对象的控制。

句柄就是个数字,一般和当前系统下的整数的位数一样,比如32bit系统下就是4个字节。
这个数字是一个对象的唯一标示,和对象一一对应。
这个对象可以是一个块内存,一个资源,或者一个服务的context(如 socket,thread)等等。
这个数字的来源可以有很多中,只要能保证和它代表的对象保持唯一对应就可以,比如可以用内存地址,也可以用句柄表的序号,或者干脆用一个自增ID,再或者用以上的值去异或一个常数。

传统上操作系统内核和系统服务API都是 C 语言接口的,但是其内部设计理念上又是OO的,所以有对象概念却没有对应的语言语法支持。
句柄的作用就是在 C 语言环境下代替 C++ 的对象指针来用的。
创建句柄就是构造,销毁句柄就是析构,用句柄调用函数相当于传入this指针。
如果有系统API是 C++ 接口的,那么就没有句柄了,而是某个接口指针,IXXXPtr之类的,比如Windows的com ptr。

句柄和指针的区别

当把硬盘上的资源调入内存以后,将有一个句柄指向它,但是句柄只能指向一个资源。而且句柄知道所指的内存有多大。还有指针,指针指向地址,它不知道分配的内存有多大。

句柄是一个32位的整数,实际上是windows在内存中维护的一个对象(窗口等)内存物理地址列表的整数索引。因为windows的内存管理经常会将当前空闲对象的内存释放掉,当需要时访问再重新提交到物理存储,所以对象的物理地址是变化的,不允许程序直接通过物理地址来访问对象。程序将想访问的对象的句柄传递给系统,系统根据句柄检索自己维护的对象列表就能知道程序想访问的对象及其物理地址了。句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各个对象是驻留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象了。但是,如果真这么认为,那么就大错特错了。我们知道windows是一个虚拟内存为基础的操作系统。在这种情况下,windows内存管理器经常在内存中来回移动对象,以此来满足各种应用程序的内存需要,对象被移动意味着它的地址变化了。如果地址总是如此的变化,我们应该去那里找对象呢?为了解决这个问题,windows操作系统为各个应用程序腾出一些内存地址,用来专门登记各个应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。windows内存管理器移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需要记住这个句柄地址就可以间接地知道对象具体在内存中哪个位置了。这个地址是在对象装载(load)时由系统分配的,当系统卸载时又释放给系统。句柄地址(稳定)—–>记载着对象在内存中的地址——–>对象在内存中的地址(不稳定)—–>实际对象。但是必须注意,程序每次重新启动,系统不保证分配跟这个程序的句柄还是原来哪个句柄,而绝大多数情况下的确不一样。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院给我们的门票总是不同的座位是一个道理。

因此,句柄和指针其实是两个截然不同的概念。windows系统用句柄标记系统资源,用句柄隐藏系统信息。你只需要知道有这个东西,然后去调用它就行了,它是32bit的uint。指针则标记某个物理内存的地址,是不同的概念。

指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。当你需要对某个内存进行直接操作时,可以使用GlobalLock锁住这段内存并获得指针来直接进行操作。

句柄是指针的“指针”,使用句柄主要是为了利于windows在进程内存地址空间移动分配的内存块,以防止进程的内存空间被撕的四分五裂而存在过多的碎片。

句柄是一些表的索引也就是指向指针的指针。间接的引用对象,windows可以修改对象的”物理”地址和?描述器的值,但是句柄的值是不变的。

句柄可以在获得窗口的时候使用,指针可以进行调用窗口,两个使用的地方不一样.一个括号外,一个括号内.

隐喻

CSDN上有人说过:牧童遥指杏花村。
牧童的手为指针,杏花村的牌子为句柄,杏花村酒店为对象的实例.
句柄是资源在创建过程中由Windows赋予的,它就是代表这个资源的。

而指针实质上是某个变量或者对象所在内存位置的首地址,是指向对象的。

一个是指向,一个是代表,二者是不同的。

一个是直接找到对象(指针),一个是间接找到对象(句柄)。

例如,杏花村可以搬家(实际上程序运行过程中,资源在内存中的地址是变化的),那么牧童的手的指向也就不同(指针)了,然而即使搬了家,“杏花村”这块牌匾是不变的,通过打听“杏花村”这个名称,还是可以间接找到它的(地址)。

HANDLE的本意是把柄,把手的意思,是你与操作系统打交道的东东。

指针与引用

(1) 指针是对象在内存中的地址;

(2) 引用是对象的别名,其实质就是功能受限但是安全性更高的指针;

(3) 句柄是指针的指针,句柄实际上是一个数据,是一个Long (整长型)的数据。句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样。Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。

引用与指针的区别

常常有人问引用与指针的区别,可能是指针和引用在功能上的相似,而是他们混淆这两个概念, 现在总结以下二者的区别,希望大家能彻底弄清这两个概念根本性的差别:

引用,一个变量的别名,为什么引入别名呢?原因是我们想定义一个变量,他共享另一个变量的 内存空间,使用别名无疑是一个好的选择。变量是什么?是一个内存空间的名字,如果我们给这个 内存空间在起另外一个名字,那就是能够共享这个内存了,引用(别名)的由此而来。

指针,指向另一个内存空间的变量,我们可以通过它来索引另一个内存空间的内容,本身有自己的 内存空间。

二者区别:

  • 引用访问一个变量是直接访问,而指针是间接访问。
  • 引用是一个变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间。
  • 引用在开始的时候就绑定到了一个内存空间(开始必须赋初值),所以他只能是这个 内存空间的名字,而不能改成其他的,当然可以改变这个内存空间的值.

http://www.360doc.com/content/14/0120/15/7591436_346648771.shtml

(1)指针是对象在内存中的地址;

(2)引用是对象的别名,其实质就是功能受限但是安全性更高的指针;

(3)句柄是指针的指针,句柄实际上是一个数据,是一个Long (整长型)的数据。句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样。Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。

Java中有3个数据类型:基本数据类型、引用类型和null类型。其中,引用类型包括类类型(含数组)、接口类型。为了区别引用类型的变量标识符和基本数据类型变量标识符,我们特别的(特意的)使用Handle来称呼引用类型的变量标识符。对象的引用是创建对象时的返回值!引用是new表达式的返回值。new A(); 这里真正创建了一个对象,但我们没有用句柄去持有(hold、拿着、保存)该引用。handle是变量,reference是一种变量值。