马士兵课程笔记(续6)

容器

概念

    Java API 所提供的用于在程序中存放对象的一系列类的实例。

    数组其实也是一种容器, 不过其他容器类都不用也不能指定大小。

 

容器API

  • 位于 java.util 包内;
  • 类图结构如下:

马士兵课程笔记(续6)

  • Collection 接口 —— 定义了存取一个一个对象的方法,其子接口 Set 和 List 分别定义了存储方式
    • Set 中的数据对象无序不重复
    • List ... 有序可重复
    • “重复”的定义:互相equals()。
  • Map 接口 —— 定义了存储 "key - value 映射对" 的方法。

 

Collection<E> 接口

方法

int size(); boolean isEmpty();

boolean contains(E element)//依据equals, add(...), remove(...); void clear(); 

boolean containsAll(Collection c), addAll(...), removeAll(...), retainAll(...)//保留交集;

E[] toArray(); Iterator<E> iterator();

 

import java.util.*;
...
Collection c = new ArrayList();    // 父接口引用子类对象
// 可以存入不同类型的对象,但必须是对象,因为基本数据类型位于Stack里随时可被清空
c.add("Hello");
c.add(new Name("f1", "l1"));
c.add(new Integer(200));
System.out.println(c.size());
System.out.println(c);    // ArrayList的toString()方法
...

/** 输出:
 * 3
 * [hello, fi1 l1, 100]
 */
  • 容器类对象在调用 remove、contains 等方法时需要比较对象是否相等,这就涉及到对象类型的 equals 及 hashCode 方法[注1]:对自定义类,需要重写 equals 及 hashCode 方法[注2]以实现自定义的相等规则。
  • 注1:hashCode方法因为同时具有索引的特性,会在 Map 型容器中对key对象的比较中被用到;
  • 注2:equals 为 true,hashCode 也要为相等,好比同一个人不该有多个住址就没法找了。一个住址可以住多人,但是找个人效率会降低,应尽量避免这样,即设计hashCode方法应尽量让hashcode相等的对象也相等;
  • hashCode方法设计比较难,可以调用API类的方法。

Iterator<E>接口

    所有实现了 Collection 接口的容器类都有一个 iterator() 方法用以返回一个实现了 Iterator 接口的对象;

    Iterator 对象称作迭代器,用以方便地实现对容器内元素的遍历操作;

    Iterator 接口内定义了三个方法:

        boolean hasNext(); E next();

        void remove();    // 删除指针前一个元素,(一定有机制保存了前一个元素的引用)所以在执行完 next() 之后只能 remove() 一次(那个保存前一个的引用删掉失效了)。Iterator的remove() 是在迭代过程中删除容器元素(不只是迭代器里的元素)唯一安全方法,此时不能用容器类提供的remove,会产生例外,因为Iterator对象内部对容器对象做了线程锁定。

Tips:JDK5.1增强的for循环

缺陷:1. 不适用数组 —— 不能方便地访问下标

      2. 对于集合 —— 该for结构内部也是调用Iterator,但与Iterator相比却不能方便地删除集合中的元素(原因在上文)

结论:除了简单遍历读取元素外,不建议使用

 

Set<E>接口

对应数学中的“集合”概念

无序,无重复

HashSetTreeSet

Tips:Set 和 List 类都具有以 Collection接口类 为参数的构造方法

 

List<E>接口

有序,可有重复

像数组 —— 元素对应整型的索引,可按索引访问;又不同于数组 —— 不限大小,自动扩容

ArrayList,LinkedList 等

特有方法

get(index); remove(index);

indexOf(E), lastIndexOf(...);

E set(index, element); void add(index, element)

java.util.Collections类 提供了一组静态方法实现基于List容器的常用算法

void sort(List) // 借助于Comparable接口; void shuffle(List); void reverse(List); void filll(List, E); void copy(List dest, List src); int binarySearch(List, E) // 先排序再查找

 

Comparable<T>接口

所有可“排序”的类都实现了 java.lang.Comparable接口

只包含一个方法:public int compareTo(T o); 0: ==, +: this > obj, -: <。

Comparable接口的实现类通过实现 compareTo 方法确定该类对象的排序依据。Note: 实现该方法同重写equals()一样,要先检查类型, SDK1.5引进泛型后就不用了

 

class Name implements Comparable {
    ... ...
    public int compareTo(Object o) {   // 强调:实现/重写的方法头部要copy自接口/父类
        Name n = (Name) o;    // 类型检查或强制转换
        int lastCmp = lastName.compareTo(n.lastName);
        return (lastCmp != 0 ? lastCmp :
                                            firstName.compareTo(n.firstName));
    }
}
  

如何选择*

看应用

Array 读快改慢;

Linked 改快读慢;

Hash 两者之间。

 

Map<K, V>接口

键-值对, key和value都是对象

以Key标识,key不可重复,依据 hashCode 比较

HashMap类(Hash表实现),TreeMap类(红黑树)

特有方法

put(K key, V value);    // 如果发生了替换,返回旧的value

V get(key), V remove(key);    // value对象以Object类型输出,所以要再按原有类型强制转换

boolean containsKey(key), containsValue(value);

int size(); boolean isEmpty(); void clear();

void putAll(Map<K, V> t);

Auto-boxing/unboxing 机制

基础数据类型<->封装类 自动转换(JDK1.5后)

 

import java.util.*
...
Map m1 = new HashMap();
m1.put("one", 1);    // 并不是存在 put(Object, int) 方法,而是自动打包机制将int转换成Integer传给put方法
int i = (Integer) m1.get("one");    // Integer类型的对象可以自动解包成int,但是这里是以Object类型输出的,不强制转换成Integer型就不会启用自动解包机制
...

 

泛型Generic(after JDK1.5)

起因:JDK1.4 以前类型不明确

  • 装入集合的类型都被当成Object对待,从而失去自己的实际类型;
  • 从集合中取出时往往需要转型,效率低,容易出错。

解决办法:在定义集合的时候同时定义集合中对象的类型

格式Collection<E>, Iterator<E>Comparator<T> , Map<K, V>等凡是API中这样定义的接口、类;

使用:把指定的类型填进<>,见TestArgsWords.zip

优点:增强程序的可读性和稳定性

 

Summary —— 一一三六

 

  • 一个图
  • 一个类 —— java.util.Collections
  • 三个知识点
    • 增强for (不好)
    • Generic
    • Auto-boxing / unboxing
  • 六个接口
    • Collection<E>
    • Iterator<E>
    • Set<E>
    • List<E>
    • Map<K, V>
    • Comparable<T>

你可能感兴趣的:(java基础,笔记,马士兵)