java编程思想(读书笔记):9.持有你的对象

来源:互联网 发布:搜狗输入法 编程皮肤 编辑:程序博客网 时间:2024/06/09 15:14

九、持有你的对象
array(数组):
关于array和其他容器之间的区别,存在两个议题:效率和型别。array是java用来“存储及随机访问一连串对象(尤其是对象的reference)”的各种做法中,最有效率的一种。不过效率带来的牺牲是:当你产生array时,其容量固定且无法动态改变。
其他泛型容器:
包括list,set,,map。他们不会以任何特定的型别来看待它们所持有的对象,一律将持有对象视为Object。只要产生单一容器,便可将任意java对象置于其中(基本性别除外)。基本型别要通过其外覆类进行加载。这引出array比容器好的第二点:当你产生array时,它持有的是特定型别的对象,这意味着编译期的型别检查会防止你将不正确的型别置于array。
array元素的比较:
撰写一份泛型排序码,面临的问题是,排序必须依据对象实际型别来进行比较。当然,为各种不同型别都分别撰写一份排序用的函数,也是一种解决办法,但你应该了解,这种做法无法轻易用在新的型别上。
tips:
程序设计的主要目标,是将“变动的事物和不变得事物隔离开来”。在这里,保持不变的,就是泛用排序算法,会变动的,则是对象的比较法。所以如果你不希望将对象比较动作写死于很多不同的排序函数中,我们可以采用callback技巧。通过callback,“因势而异的程序代码”可被封装于自己的class内,而“永不变动的程序代码”则回头调用前者。通过这个手法,便可让不同的对象各自表述其不同的比较法,并将该比较法喂进同一个排序算法中。
java标准程序库的排序算法,会针对你所排序的型别来进行最佳化。面对基本性别时用的是quicksort,而面对对象则采用stable merge sort。
array排序完毕后,你可以使用Array.binarySearch()快速查找某个元素。但是千万别在未经排序的array身上使用binarySearch,否则结果完全无法预测。
不同容器的基本行为:
list会以元素安插次序来放置元素,不会重新排列或编修。set不接受重复元素,它会使用自己内部的一个排列机制。map也不接受重复元素,重复与否乃是以键值判断的。map排序也是用自己内部的一个机制。
容器的缺点:
如果你在定义容器的时候没有指定容器内存储对象的确切型别,那么你一旦将对象置于容器内,你便损失了他的型别信息。但是当你在定义之初就指定容器存储型别时,它在编译期就可以判断是否型别正确。
例如:

ArrayList<String> list = new ArrayList<String>();list.add(new Integer(5));

它将会报错。
所谓的“迭代器”,可被用来达成这种概念,迭代器是个对象,其职责便是走访以及选择序列中的一连串对象。
调用java iterator,你可以:
1.调用iterator(),要求容器交给你一个iterator。当你第一次调用iterator的next()时,它会返回序列中的第一个元素。
2.调用next()取得序列中的下一个元素。
3.调用hasnext()检查序列中是否还有其他元素。
4.调用remove()移去迭代器最新传回的元素。
map的机能
“在arraylist中查找key”这个动作并不快,而这正是hashmap提高速度的地方。它不会逐一查找某个key,而会使用一种被称为hash code的特殊值。hash code是一种“将对象内的某些信息转换为几乎独一无二”的int,用来代表那个对象。
代码如下:

package test1;import java.util.HashMap;class Counter{    int i = 1;    public String toString(){        return Integer.toString(i);    }}public class Statistics {    public static void main(String[] args) {        HashMap hm = new HashMap<>();        for (int i = 0; i < 1000; i++) {            Integer r = new Integer((int)(Math.random()*20));            if(hm.containsKey(r)){                ((Counter)hm.get(r)).i++;            }else            {                hm.put(r,new Counter());            }        }        System.out.println(hm);    }}

这里为什么不使用外覆类呢?因为,使用java的外覆类时,你只能在初始化时设定其值,而后读取其值。换句话说你没有办法在产生外覆类的对象之后改变其值。
持有reference:
java.lang.ref程序库含有一组classes,这些classes为垃圾回收机制提供更大的弹性。当你拥有很多可能耗尽内存的大型对象时,这些classes格外有用。有三个classes继承自抽象类Reference,SoftReference,WeakReference和PhantomReference。他们都对垃圾回收机制提供不同层级的间接性–如果外界只能通过这些Reference对象才得碰触对象的话。
当你虚妄继续持有某个reference(它所指的对象是你希望碰触的),但你也允许垃圾回收器将它释放(回收),这时候你应该使用Reference对象。于是你得以继续使用该对象,而一旦内存即将耗尽,你也允许它被释放。
(代码未写完,待续)

0 0
原创粉丝点击