java编程思想阅读笔记(三)

来源:互联网 发布:拳皇出招优化 编辑:程序博客网 时间:2024/05/16 20:30

final 方法

之所以要使用final 方法,可能是出于对两方面理由的考虑。第一个是为方法“上锁”,防止任何继承类改变它的本来含义。设计程序时,若希望一个方法的行为在继承期间保持变,而且不可被覆盖或改写,就可以采取这种做法。 采用 final 方法的第二个理由是程序执行的效率。将一个方法设成 final 后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个 final 方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能受到到不到嵌入代码所带来的任何性能提升。因为任何提升都被花在方法内部的时间抵消了。Java 编译器能自动侦测这些情况,并颇为“明智”地决定是否嵌入一个 final 方法。然而,最好还是不要完全相信编译器能正确地作出所有判断。通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。 
类内所有private 方法都自动成为final。由于我们不能访问一个private 方法,所以它绝对不会被其他方法覆盖(若强行这样做,编译器会给出错误提示)。可为一个private 方法添加 final 指示符,但却不能为那个方法提供任何额外的含义。 

final类是无法继承的,同时也有出于效率的嫌疑。

集合


集合库考虑到了“容纳自己对象”的问题,并将其分割成两个明确的概念: 
(1) 集合(Collection):一组单独的元素,通常应用了某种规则。在这里,一个 List(列表)必须按特定的顺序容纳元素,而一个Set(集)不可包含任何重复的元素。相反,“包”(Bag)的概念未在新的集合库中实现,因为“列表”已提供了类似的功能。 
(2) 映射(Map):一系列“键-值”对(这已在散列表身上得到了充分的体现)。从表面看,这似乎应该成为一个“键-值”对的“集合”,但假若试图按那种方式实现它,就会发现实现过程相当笨拙。这进一步证明了应该分离成单独的概念。另一方面,可以方便地查看 Map 的某个部分。只需创建一个集合,然后用它表示那一部分即可。这样一来,Map 就可以返回自己键的一个Set、一个包含自己值的List 或者包含自己“键-值”对的一个List。和数组相似,Map 可方便扩充到多个“维”,毋需涉及任何新概念。只需简单地在一个Map 里包含其他 Map(后者又可以包含更多的Map,以此类推)。 

集合能做的所有事情(亦可对 Set 和List 做同样的事情,尽管 List 还提供了一些额外的功能)。Map 不是从 Collection 继承的,所以要单独对待。 

List(接口) 顺序是 List 最重要的特性;它可保证元素按照规定的顺序排列。List 为 Collection 添加了大量方法,以便我们在 List 中部插入和删除元素(只推荐对LinkedList 这样做)。List 也会生成一个ListIterator(列表反复器),利用它可在一个列表里朝两个方向遍历,同时插入和删除位于列表中部的元素(同样地,只建议对 LinkedList 这样做) ArrayList* 由一个数组后推得到的 List。作为一个常规用途的对象容器使用,用于替换原先的Vector。允许我们快速访问元素,但在从列表中部插入和删除元素时,速度却嫌稍慢。一般只应该用ListIterator 对一个ArrayList 进行向前和向后遍历,不要用它删除和插入元素;与 LinkedList 相比,它的效率要低许多 LinkedList 提供优化的顺序访性能,同时可以高效率地在列表中部进行插入和删除操作。但在进行随机访问时,速度却相当慢,此时应换用 ArrayList。也提供了 addFirst(),addLast(),getFirst(),getLast(),removeFirst() 以及removeLast()(未在任何接口或基础类中定义),以便将其作为一个规格、队列以及一个双向队列使用 。

Set(接口) 添加到 Set 的每个元素都必须是独一无二的;否则Set 就不会添加重复的元素。添加到 Set 里的对象必须定义equals(),从而建立对象的唯一性。Set 拥有与 Collection 完全相同的接口。一个 Set不能保证自己可按任何特定的顺序维持自己的元素 HashSet* 用于除非常小的以外的所有Set。对象也必须定义 hashCode() ArraySet 由一个数组后推得到的 Set。面向非常小的Set 设计,特别是那些需要频繁创建和删除的对于小Set,与HashSet 相比,ArraySet 创建和反复所需付出的代价都要小得多。但随着 Set 的增大,它的性能也会大打折扣。不需要HashCode() 。TreeSet 由一个“红黑树”后推得到的顺序 Set(注释⑦)。这样一来,我们就可以从一个Set 里提到一个顺序集合。(可是我发现好像没有arrayset啊)

Map(接口) 维持“键-值”对应关系(对),以便通过一个键查找相应的值 HashMap* 基于一个散列表实现(用它代替Hashtable)。针对“键-值”对的插入和检索,这种形式具有最稳定的性能。可通过构建器对这一性能进行调整,以便设置散列表的“能力”和“装载因子” ArrayMap 由一个 ArrayList 后推得到的 Map。对反复的顺序提供了精确的控制。面向非常小的 Map 设计,特别是那些需要经常创建和删除的。对于非常小的Map,创建和反复所付出的代价要比 HashMap 低得多。但在Map 变大以后,性能也会相应地大幅度降低 TreeMap 在一个“红-黑”树的基础上实现。查看键或者“键-值”对时,它们会按固定的顺序排列(取决于Comparable 或Comparator,稍后即会讲到)。TreeMap 最大的好处就是我们得到的是已排好序的结果。TreeMap 是含有 subMap()方法的唯一一种Map,利用它可以返回树的一部分 

选择

list

在ArrayList 中进行随机访问(即get())以及循环反复是最划得来的;但对于LinkedList 却是一个不小的开销。但另一方面,在列表中部进行插入和删除操作对于 LinkedList 来说却比ArrayList 划算得多。我们最好的做法也许是先选择一个ArrayList 作为自己的默认起点。以后若发现由于大量的插入和删除造成了性能的降低,再考虑换成LinkedList 不迟。

遍历list:

Iterator it = list.iterator();        while(it.hasNext()){//            it.next();            System.out.println(it.next());        }

map

ArrayMap 的性能也要比HashMap 差——除反复循环时以外。而在使用 Map 时,反复的作用通常并不重要(get()通常是我们时间花得最多的地方)。TreeMap 提供了出色的 put()以及反复时间,但 get()的性能并不佳。但是,我们为什么仍然需要使用TreeMap 呢?这样一来,我们可以不把它作为Map 使用,而作为创建顺序列表的一种途径。树的本质在于它总是顺序排列的,不必特别进行排序(它的排序方式马上就要讲到)。一旦填充了一个TreeMap,就可以调用 keySet()来获得键的一个Set“景象”。然后用 toArray() 253
产生包含了那些键的一个数组。随后,可用static 方法Array.binarySearch()快速查找排好序的数组中的内容。当然,也许只有在HashMap 的行为不可接受的时候,才需要采用这种做法。因为HashMap 的设计宗旨就是进行快速的检索操作。最后,当我们使用 Map 时,首要的选择应该是 HashMap。只有在极少数情况下才需要考虑其他方法。 

典型的遍历map方法:

for(Map.Entry<String,String> entry : map.entrySet()){                    };

Java中Comparable和Comparator区别小结




原创粉丝点击