List
a.List接口是Collection的子接口,实现List接口的容器类中的元素是有顺序的,并且可以重复。
b.List容器中的每一个元素都对应一个整型的序号,用于记载该元素在容器中的位置,可以根据序号存取元素c.主要的2中List,ArrayList和LinkedList.
d.ArrayList底层是数组实现的,LinkedList底层是链表实现的。
e.很多常用方法都可以在 java.util.Collections类 里面找到,比如排序,分类什么的。
1.ArrayList
有序的,可以重复的。 ArrayList array = new ArrayList();
add(里面是对象)方法:将一个对象增加到list的末尾。比如: array.add("Hello"); 这样就添加了一个字符串进去
get(里面是索引)方法:按照索引取出相应的对象。比如 String s = (String)array.get(0);
// 注意,为什么这个地方要强制类型转换。因为get拿到的是对象,而s是字符对象,所以向下转型
// 注意,get() 如果数组下标越界,会有异常抛出
size()方法:返回ArrayList对象里面的元素个数,整型
clear()方法:清空所有元素
isEmpty()方法:布尔类型,判断容器里面是否有元素
remove(里面可以是索引,也可以是对象)方法(重载方法):清除某个元素,清除了以后,后面的会自动往前移动
// 注意,因为最初我有个想法是假如有2个相同的字符串,然后使用remove,会不会都清除了?还是只清除一个?要是只清除一个的话会清除哪一个?实验以后发现它是一次只清除一个元素,按照索引号最小先被删除的原则。
2.LinkedList
无序的,不能重复。 LinkedList list = new LinkedList();
方法大体都差不多,比起ArrayList多添加了一些方法
总的来说,这两种List各有各的用途,在不考虑效率的情况下都无所谓,任意选取一种来使用就好。
一般来说,如果查找得多,就用 ArrayList,如果修改得多,就用LinkedList,其它的暂时就不管了,等以后真正地非常深入了,或者效率确实很重要了再回来重新深究这个问题。
3.比较
1). ArrayList 读取快,改写慢。
元素之间按顺序连接着,直接根据索引就可以直接找到,读取很快,找哪一个都是一样的,但是呢,如果要删除一个元素,需要把前面和后面的部分都copy下来,构建新的数组,很慢
2).LinkedList 改写快,读取慢。
底层链表,不知道路径,所以假如要找第5000个元素,有可能要找5000次才能找到。但是删除不影响其它的元素
3).Hash 介于二者之间
最佳的方式是将ArrayList作为默认的首选,只有你需要使用额外的功能,或者当程序的性能因为经常从表中间进行插入和删除而变差的时候,再去选择LinkedList。
Set
1.Set接口的Collection的子接口,它没有额外的方法,所以定义Set对象的时候一定使用Collection作为引用。
2.实现Set接口的容器类中的元素是没有顺序的,并且不可以重复。不重复要通过重写equals方法和hashCode方法来实现。
3.其实常用的Set的子类就是HashSet,其它的感觉都很少接触到。它的性能几乎总是比TreeSet好,后者存在的唯一理由就是它可以维持元素的排序状态,所以在迭代的时候可以考虑使用TreeSet。
这里需要尤其注意一个问题,如果你是自己写的类,也就是说是从Object直接继承来的类,那么equals方法和hashCode方法也是Object类自带的。默认的hashCode方法返回的是对象的内存地址,而默认的equals方法比较的也是内存地址(String类已经重写过了)。那么你每new一个对象,按照Object类的比较来说,他们当然是不同的,因为内存地址不一样。这时候如果你往Set里面使用add方法添加,它就会去使用equals方法比较,因为比较的是内存地址,所以即使2个类的所有成员,方法都是相等的,也会都添加进去。于是就造成了重元素,这往往是开发者不愿意看见的。
要解决这个问题很简单,就是你每写一个类,如果你要添加进入Set,重写它的equals方法和hashCode方法。
equals方法很好理解,就是用于比较
hashCode方法,更多的可能是用于查找。试想,set是无序的,如果对无序的容器进行线性查找操作,开销其实很大。解决的方法其实就是hashCode,用一些跟这个类特定相关的信息来重新定义hashCode方法的返回值。对于容器来说,那么里面的每个元素都有一个重新定义的位置。比如String类型的元素,那么如果字符串内容相等,我们在设计的过程中通常就认为它们相等了。那么就使用String的hashCode作为hashCode方法的返回值,这样,将来查找元素的时候,我们就知道,在这样一个容器中,有没有一个内容为所查找的字符串的元素。
Map
简单地说就是简直对,键和值都是对象,不是基本类型。除了使用一些比如检索之类的功能之外,map也可以使用遍历,通过使用Map.Entry,生成一个Set类型的结果,使得可以使用Iterator来进行遍历。通常来说,实现类是HashMap,LinkedHashMap。而因为性能的因素,通常需要的只是HashMap。
HashTable是线程安全的,会有更大的系统开销,所以已经被HashMap替代了。对于线程安全的类,最好还是不要用,可以使用替代的非线程安全的类,然后只是在需要线程同步的时候认为再加同步就是了。
这个对于JSON非常有用,因为JSON的输出就是价值对。很多时候都要实现将数据装到实例化了的map(通常是HashMap)里面。要遍历Map的话,需要做的就是一个entry一个entry的看。
比如
... ...
for(Map.Entry<K,V> entry: HashMap.entrySet()){
然后里面再进行entry.getKey()和entry.getValue()等等操作
}
...
需要在这里赘述一下,就是Iterator遍历返回的顺序未必就是寸进去时的顺序。