1)可以动态保存任意多个对象,使用比较方便!
2)提供了一系列方便的操作对象的方法:add、remove、set、get等3)使用集合添加,删除新元素的示意代码-简洁了
1)collection实现子类可以存放多个元素,每个元素可以是Object
2)有些Collection的实现类,可以存放重复的元素,有些不可以
3)有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
4)Collection接口没有直接的实现子类,是通过它的子接口Set和 List来实现的
1 )Iterator对象称为迭代器,主要用于遍历 Collection集合中的元素。2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
3)Iterator的结构.[看一张图]
4)Iterator 仅用于遍历集合,Iterator本身并不存放对象。
提示:在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。
List接口是 Collection接口接口
1)List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
2)List集合中的每个元素都有其对应的顺序索引,即支持索引。
3)List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
JDKAPI中List接口的实现类:
List 接口和常用方法
常用的 ArrayList LinkedList和Vector
- boolean addAll(int index, Collection eles):从 index位置开始将 eles 中的所有元素添加
- Object get(int index):获取指定 index 位置的元素
- int indexOf(Object obj):返回 obj 在集合中首次出现的位置
- int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
- Object remove(int index):移除指定 index 位置的元素,并返回此元素
- Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
- List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
注意返回的子集合 fromIndex <= subList < toIndex
List 的三种遍历方式 [ArrayList, LinkedList,Vector]
1) permits all elements, including null , ArrayList 可以加入null,并且多个
2) ArrayList是由数组来实现数据存储的
3) ArrayList 基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码 在多线程情况下,不建议使用ArrayList
1)ArrayList中维护了一个Object类型的数组elementData. transient Object[] elementData; //transient表示瞬间,短暂的,表示该属性不会被序列号
2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
//如果 需要的数组大小 不够用,就扩容 , 扩容的算法
//newCapacity = oldCapacity + ((capacityIncrement > 0) ?
// capacityIncrement : oldCapacity);
//就是扩容两倍.
1)LinkedList底层实现了双向链表和双端队列特点
2)可以添加任意元素(元素可以重复),包括null
3)线程不安全,没有实现同步
1)LinkedList底层维护了一个双向链表
2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点
3)每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.
4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
System.out.println(“=LinkeList 遍历迭代器==”);
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(“next=” + next);
}
1)无序(添加和取出的顺序不一致),没有索引
2)不允许重复元素,所以最多包含一个null
3)JDK APl中Set接口的实现类有:
和List 接口一样, Set 接口也是 Collection的子接口 因此 常用方法和 Collection 接口一样.
可以使用迭代器
增强for
不能使用索引的方式来获取
1)HashSet实现了Set接口
2)HashSet实际上是HashMap,
3)可以存放null值,但是只能有一个null
4)HashSet不保证元素是有序的,取决于hash后,再确定索引的结果.(即,不保证存放元素的顺序和取出顺序一致)
5)不能有重复元素/对象.在前面Set接口使用已经讲过
分析HashSet底层是HashMap, HashMap底层是(数组+链表+红黑树)
>分析HashSet的添加元素底层是如何实现(hash()+equals())
1)LinkedHashSet是 HashSet的子类
2)LinkedHashSet底层是一个 LinkedHashMap,底层维护了一个数组+双向链表
3)LinkedHashSet根据元素的 hashCode值来决定元素的存储位置,同时使用链表维护元素的次序(图),这使得元素看起来是以插入顺序保存的。
注意:这里讲的是JDK8的Map接口特点
1)Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value2)Map中的key和 value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3)Map中的 key不允许重复,原因和HashSet一样,前面分析过源码
4)Map中的value可以重复
5)Map的key可以为 null, value也可以为null,注意 key 为null只能有一个,value为null,可以多个.
6)常用String类作为Map的 key
7)key和 value之间存在单向一对一关系,即通过指定的key总能找到对应的 value
8)Map存放数据的key-value示意图,一对k-v是放在一个HashMap$Node中的,有因为Node实现了 Entry接口,有些书上也说一对k-v就是一个Entry(如图)
remove:根据键删除映射关系
get:根据键获取值
size:获取元素个数
isEmpty:判断个数是否为0
clear:清除 k-v
containsKey:查找键是否存在
System.out.println(“----使用 EntrySet 的 迭代器(第 4 种)----”);
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object entry = iterator3.next();
//System.out.println(next.getClass());//HashMap$Node实现-> Map.Entry (getKey,getValue)
//向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + “-” + m.getValue()
1)Map接口的常用实现类:HashMap、Hashtable和Properties。
2)HashMap是Map接口使用频率最高的实现类。
3) HashMap 是以 key-val 对的方式来存储数据(HashMap$Node类型)
4)key不能重复,但是值可以重复,允许使用null键和null值
5)如果添加相同的key,则会覆盖原来的key-val,等同于修改.(key不会替换,val会替换)6)与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.(jdk8的hashMap底层数组+链表+红黑树)
7)HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized
1) HashMap底层维护了Node类型的数组table,默认为null
2) 当创建对象时,将加载因子(loadfactor)初始化为0.75.
3) 当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key相是否等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。
4) 第1次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)
5) 以后再扩容,则需要扩容table容量为原来的2倍(32)临界值为原来的2倍,即24,依次类推
6) 在Java8中,如果一条链表的元素个数超过 TREEIFY THRESHOLD(默认是8)并且table的大小 >= MIN TREEIFY CAPACITY(默认64),就会进行树化(红黑树)
1) 存放的元素是键值对:即K-V
2) hashtable的键和值都不能为null,否则会抛出NullPointerException3)hashTable使用方法基本上和HashMap一样
4) hashTable 是线程安全的(synchronized), hashMap 是线程不安全的
Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存数据。
他的使用特点和Hashtable类似
Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象并进行读取和修改
1)Collections是一个操作 Set、List和 Map等集合的工具类
2)Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作14.17.2排序操作:(均为static方法)
2.1)reverse(List):反转 List中元素的顺序
2.2)shuffle(List):对 List集合元素进行随机排序
2.3)sort(List):根据元素的自然顺序对指定 List集合元素按升序排序
2.4)sort(List,Comparator)根据指定的 Comparator产生的顺序对 List集合元素进行排序
2.5)swap(List, int, int):将指定 list集合中的i处元素和j处元素进行交换
1)不能对加入到集合ArrayList中的数据类型进行约束(不安全)
2)遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响泛型的理解和好处
1)编译时,检查添加元素的类型,提高了安全性
2)减少了类型转换的次数,提高效率[说明]
3)不再提示编译警告
理解:泛(广泛)型(类型) => Integer, String,Dog
1)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
2)在类声明或实例化时只要指定好需要的具体的类型即可。
3)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
interface 接口{}和 class类
比如:List,ArrayList
1)其中,T,K,V不代表值,而是表示类型。
2)任意字母都可以。常用T表示,是Type的缩写
要在类名后面指定类型参数的值(类型)。
如:
- List strList = new ArrayList()
- List strList = new ArrayList< >()
- Iterator iterator = customers.iterator();
1.interface List{}, public class HashSet{).等等
说明:T,E只能是引用类型
看看下面语句是否正确?:
- List list = new ArrayList(); /OK
- List list2 = new ArrayList();/错误
2.在给泛型指定具体类型后,可以传入该类型或者其子类类型
3.泛型使用形式
- List list1 = new ArrayList();
- List list2 = new ArrayList<>();
3.如果我们这样写 List list3 = new ArrayList();默认给它的泛型是[E就是Object]
class类名
1)普通成员可以使用泛型(属性、方法)
2)使用泛型的数组 不能初始化 因为数组在 new 不能确定 T 的类型就无法在内存开空间
3)静态方法中不能使用类的泛型 因为静态是和类相关的,在类加载时,对象还没有创建所以,如果静态方法和静态属性使用了泛型,JVM 就无法完成初始化
4)泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
5)如果在创建对象时,没有指定类型,默认为Object
如:
Tiger 后面泛型,所以我们把 Tiger 就称为自定义泛型类
T, R, M 泛型的标识符, 一般是单个大写字母
泛型标识符可以有多个
interface接名
1)接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
2)泛型接口的类型,在继承接口或者实现接口时确定
3)没有指定类型,默认为Object
如:
修饰符
泛型方法,可以定义在普通类中,也可以定义在泛型类中
当泛型方法被调用时,类型会确定
public void eat(E e) {},修饰符后没有
1)泛型不具备继承性
List list = new ArrayList();错误示列
2)<?>:支持任意泛型类型
3)<?extends A>:支持A类以及A类的子类,规定了泛型的上限
4)<?super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限