关于如何在工程里得到一个唯一的值
在项目开发的时候,有时会遇到需要定义一个值作为id来使用的情况。这个值的具体数值无所谓,对它的要求只有一个:全局唯一。
全局唯一意味着前无古人后无来者,要做到这点,不容易。
-
用随机数生成器随机生成一个。
直觉上,随机的方式产生的数碰撞的概率低,但并非全局唯一,在这点上,并不能符合要求。这种方式直接pass。 -
用值生成器生成。
这个法子定义了一个值生成器,用来生成和管理全球唯一的值。需要值的地方,跟它申请就可以了。这一定程度上满足了我们的要求。但它的作用范围有限,只能局限于我们自己的项目,第三方依赖里的id,由于不在我们的管理的范围内,因此我们的id有可能跟对方的id有重叠。另外,由于值是运行时生成的,因此无法在switch代码块里作为条件分支使用。同样的,由于值是运行时生成的,值不固定,不同进程各自有用一个值生成器,规则一样的情况下,存在碰撞的可能性。另外,由于值是动态分配的,可能在进程A它代表含义1,进程B代表含义2,这个值在进程间传递的话,会出现问题。 -
用字符串.hashCode
hashCode是Java类所具有的一个方法,用来返回一个对象具有的特征。特征的计算方式,可以使用Object自带的默认算法,子类也可以覆盖这个方法,用自己的方法算出特征。我们可以借用String类的hashCode的默认实现,来得到一个代表特征的hashCode,作为全局唯一的id使用。这个方法其实和值生成器差不多,本质上是一个固定了值生成算法的生成器。好处是字符串可以在编码时确定,可以作为条件分支在switch里使用。同时由于编码时固定了值,因此在不同进程里,值也是一致的,进程间传递也不用担心含义指代不一致的问题。但依然只能在自己的项目里使用,无法管理第三方依赖里的id,依然存在id重叠的可能,当然,我们可以通过添加前缀后缀之类的方式,来保证尽可能不重叠,只是这种保证不是强制的,所以有用也有限。同时,hashCode的算法,也只无法完全规避生成hashCode的碰撞问题。md5这类摘要算法可行吗?是可以,但还是有碰撞可能,虽然说可能性是非常非常低了。
同时,hashCode是和对象的内容相关的,这里选用字符串而不是其他的对象类型就是因为这样的顾虑。String对象内的内容一旦确定,无法更改。任意对象的hashCode实现则有各种可能,因而也不推荐直接使用任意对象的hashCode。 -
使用R.id.xxx
Android项目里的id,是由编译工具生成的,全局唯一,即便在不同的模块,他们的id也会在编译时,整合在一起,赋予一个唯一值。只要保证这个id在各自的模块定义里是name唯一的,那么它的值,就不会一样。这个等价于一个值生成器,这个生成器在编译时工作,而非运行时。好处是不需要关心值,而只需要确定id是唯一的。由于这个值是在编译apk包时才确定,对于module来说,他们实际上是没有具体的值的,因此module中他们不能在switch中作为条件分支来使用。由于编码的时候固定了值(实际上是id的索引名是固定的),在不同进程,id一致,可以传递使用,对于第三方依赖,可以通过索引查询到当前已经定义了的id索引名,所以在命名的时候,可以避免用了第三方的id,但第三方和第三方之间由于没有直接的关联,因此他们存在重叠的可能。碰撞的可能则不存在了,因为值是编译过程中生成指定,所以不同的id之间,值肯定不一样。相对来说,这算是利用了平台的特性,实现了全局唯一。(虽然略有缺陷)