版权声明:提供模块,IoT清道者免费帮你模块级开发,只需你同意清道者将开发过程和源码发布在该微博上,需要的请在下方评论 https://blog.csdn.net/alingbo/article/details/78990854
一. java中为什么会产生容器(集合)这个概念:
1.集合是什么以及要学习集合的什么?
集合的本质是java API(java固有的)中提供的一系列类的实例,用于在程序中存放对象.而且这些类中有很多实用的方法可以让使用者方便的处理这些集合.集合分成很多种类型,不同类型的集合具有不同的特点,不同的使用场景和不同的内存存储方式.所以学习集合完之后要知道处理问题时该定义哪种集合,怎么调用该集合的方法甚至于该怎么自己去实现这个集合以及它的方法.
2.有数组了,为什么还要有集合?
数组可以存对象也具有一些处理对象的方法为什么还需要集合?从两者的特点来看看:
聊聊数组的特点:
- 内部的所有元素类型都是一致的;
- 数组定义之后的长度是固定的(所以数组长度的变化一般是定义一个新的数组把old->new,然后追加);
- 数组内部的元素类型可以是基本数据类型也可以是类.
- 在使用过程之中如果需要包含的数据类型不一致,或者元素数量不固定.会导致有的元素无法加入数组或初始分配数组长度不合适(过短不够用,过长浪费内存,而且需求时常变化难以寻到长度标准);
聊聊集合的特点:
- 而集合只能存储类(集合内部是对象的引用,但可是基本类型的包装类),而且一个集合可存储不同类的类型;
- 集合可以任意的添加删除元素,并且实时自动分配或者释放内存(即使内部用数组实现的也会自动,不用麻烦使用者自己实现);
- 集合的类型很多,不同类型的集合适用于解决不同的问题,可以使得大刀剁肉小刀削水果,而且其丰富的方法为使用者直接调用去"为所欲为".
由上面可知在处理大量对象时候使用集合的意义,也就是java中出现集合概念的意义:
对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定就是用集合容器进行存储.
数量任意 + 使用灵活 + 方法便捷.
二.集合的组织框架以及各类集合的特点:
1.集合的组织框架图:
图1. 集合的组织框架图
图1说明:
- 蓝色的集合Collection中是一个一个的元素,橙色集合Map中的是一对一对的元素(键值对).黑色的是迭代器用于遍历集合.
- Set中的元素无序不可重复,List的元素有序可以重复(重复的标准是两个对象的equals方法返回为true, ==:是引用相等,不改写equals时候,==和该方法都是表明同一个对象才返回true,有序是按照存入的顺序).
- 接口:Collection,Set,List,Map.Iterator(适用于Collection),ListIterator(只适用于List),其余为类.
注意:所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象.
该对象根据Collection具体的集合类型定制了合适的遍历对象,然后返回.
2. 集合的分类及其修饰符:
集合中有接口和类两种概念,且是一个多重继承的体系结构,父类(接口)的方法被子类(接口)继承,可以直接使用.
- Collection接口-定义了一组存取对象的方法,其子接口Set和List分别定义了存储方式,Set中的元素无序不重复,List的元素有序可重复.
- Map接口定义了存储"键(key)-值(value)映射对"的方法.Map的键是Set.
- Array是数组实现(查快),Linked是用链表实现(增删快),Hash是哈希表实现.tree是二叉树实现(排序),Linked和Hash经常一起出现.set(equals,加上hash就再得重写hashCode()).
- List多了一类索引操作.Linked多了一组首尾的操作.
- tree与comparable接口(实现接口重写类的compareTo()),tree与comparator接口(实现接口重写compare()方法.参数形式传入treeset构建时候的实参),set与equals()方法.hash与hashCode(),Comparable接口(对应着对象)与Collection.
注意:关键词与关键词的联系来记忆功能.
三.集合的方法:
1.Collection接口中定义的方法:(接口Set和List以及其子类都可以使用)
增 --增一个
--增一个集合
删 --删一个元素
--删一个集合
--删除全部元素
包含--包含一个元素
--包含一个集合
判断--空
--
获取--长度
注意:集合方法的同级性与包含性:参数为Object和Collection
- int size();//长度
- boolean isEmpty(); //空?
- void clear();//清空元素
- boolean contains(Object element);//包含参数元素?
- boolean add(Object element); //增加元素.
- boolean remove(Object element);//移除元素.
- Iterator iterator();//返回遍历器(因不同的集合遍历方法不同,才会被添加为方法).
- boolean containsAll(Collection c);//包含参数集合?
- boolean addAll(Collection c); //增加c集合中元素.
- boolean removeAll(Collection c);//移除参数集合中元素.
- boolean retainAll(Collection c);//取交集;
- Object[] toArray(); //转化为数组.
2.Iterator接口中定义的方法:(迭代器)
- boolean hasNext();//游标右侧是否还有下一个元素
- Object next();//返回游标右边的元素,并右移游标一个位置.
- void remove();//删除游标左边的元素,在执行完next后该操作只能执行一次.//该方法是在迭代中删除元素的唯一的安全的方法.
3.Set接口中定义的方法: (set对equals(),再hash还得hashCode(),TreeSet只看compareTo())
- 和Collection一样,没有自己添加的方法只是添加入该集合的对象一般重写equals()方法,因为相同的元素不会重复存入。且本身没有按照存入的顺序存储。
- HashSet内部数据结构是哈希表,是不同步的.(线程不安全的),hash表内部还是数组,但hash算法对数据进行了优化,利用参数值带入hash算法值获取存储位置.(hashset是先判断哈希值(hashCode),然后判断内容值(equals()),如果哈希值不同是不需要判断equals()).所以要存入hashSet集合的类需要重写equals()和hashCode(),且两类型同方法返回的值要一致.
- LinkedHashSet集合:按存储顺序的.
- TreeSet:可以排序的,默认时候按自然排序.这个集合只判断对象的compareTo()的值,相等就不加元素认为重复,不相等根据这个排序.
- TreeSet集合的第二种排序方式二:让集合自身具备比较功能.
4.List接口定义的方法:
List中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
List中元素的顺序默认为存入的顺序。
- Object get(int index); //获取索引index处的值。
- Object set(int index ,Object element); //设置index的值,返回的是老的值。
- void add(int index ,Object element); //添加一个别的往后挤。
- Object remove(int indx); //删除指定索引的值。
- int indexOf(Obiect o); //获取值为o的第一个索引。
- int lastIndexOf(Object o);//获取值为o的最后一个索引。
4'ListIterator接口中的方法:(该方法只适用于List集合)
除了具有Iterator的方法(向后)之外还增加了向前的操作,更重要的是增加了以下操作:
- add();
- set();
5.类java.util.Collections提供了一些静态方法实现了基于List容器的一些常用算法:
- void sort(List);//对List集合内的元素排序。
- void sort(list,comparator);//给Collection集合加上比较器.
- void shuffle(List);//对List容器内的对象进行随机排列。
- void revervse(List);//对List集合内的元素进行逆序排列。
- void fill(List ,Object);//用一个特定的对象重写整个List集合。
- void copy(List dest ,List src);//拷贝List集合。
- int binarysearch(List , Object);//对于顺序List容器,用折半查找方法查特定对象.
6.Comparable接口中定义的方法:
java.lang.Comparable接口
其中只有一个方法:
- public int compareTo(Object obj); //返回0时表示this == obj //返回正数表示this > obj //返回负数表示this < obj.
6'.Comparator接口:(与tree)(比较器与上面与同时存在就优先这个)
需要覆盖重写一种方法:compare();
7.Map接口中的方法:(判断可键可值,操作一般是键)
实现Map接口的类用来存储键-值对。
Map接口的实现类有HashMap和TreeMap等.
Map类中存储的键-值对,通过键来标识,所以键值不能重复。
键值必须重写equals()和hashcode(),且一致。
Map集合必须保持键的唯一性.
- Object put(Object key,Object value);//可添加可修改.
- Object get(Object key);//由键获取值.没有返回null.
- Object remove(Object key);//删除指定键值对.
- boolean containsKey(Object key);//是否包含指定的键.
- boolean containsValue(Object value);//是否包含指定的值.
- int size();//集合的大小.
- boolean isEmpty();//判断是否为空.
- void putAll(Map t);//将一个Map类中所有键值对添加进另一个Map中.
- void clear();//清空map集合.
- Set<K> keySet();//返回此映射中所包含的键的Set视图.
- Set<Map.Entry<K,V>> entrySet(); //返回该映射所包含的映射关系的Set视图.
- Collection<V>values();//返回该映射所包含的collection视图.
7'.Map.Entry<K,V>(Map集合接口的内部接口)中的方法:(存的是Map中的结婚证,在遍历时候使用)
- K getKey();
- V getValue();
- V setKey();/setValue();
Map集合的
迭代方法
:
(1)
第一种方法原理:通过keySet()方法
获取map中所有的键所在的Set集合,再通过Set的迭代器获取到每一个键.,再对每一个键获取其对应的值即可.
Set<Integer> keySet = map.keySet();
Iterator<Integer> it = keySet.iterator();
while(it.hasNext()){
Interger key = it.next();
System.out.println(key);
String value = map.get(key);
}
(2)
第二种方法
:通过Map转化为set就可以迭代,找到了另一个方法.
entrySet
:该方法将键和值的映射对象存储在了Set集合中,而这个映射关系的类型就是Map.Entry类型(结婚证).
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer,String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Integer,String>
me = it.next(); //
Map.Entry<Integer,String>该类方法有很多
Integer key = me.getKey();
String value = me.getValue();
String value = map.get(key);
}
11381:个图(
集合框架图),1个类(
Collections类(工具类)),3个知识点(for,Generic(fan),自动装包,解包),7个接口(
Iterator接口(collection),ListIterator接口(List),Comparable接口(Tree中存的对象实现),Comparator接口(tree集合参数),Collection接口,Set接口(无序),List接口(有序),Map接口).
四.集合的附属-泛型
1.泛型的作用:
- jdk1.5出现的安全机制,将运行时期的问题ClassCastException异常转化到编译时期.程序员可以去解决了.
- 避免了强制转化的麻烦.
2.泛型的使用:
(1)什么时候用?
当操作的引用数据类型不确定的时候,就使用<>.将要操作的引用类型传入即可.<>本质就是用来接收具体引用数据类型的参
数范围.在程序中只要是带有<>就需要明确传入的数据类型.
泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全.
运行时,会将泛型去掉,生成的class文件中不带泛型,这个称为泛型的擦除.
(2)泛型使用的表现形式:
- 泛型与集合
- 泛型与类
public class Tool<T>{
//里面就可以使用T这个类型来定义
}
当类中的操作的引用数据类型不确定的时候,就使用泛型来表示.
使用时候:
Tool<Student>tool = new Tool<Student>();
之后不用强制类型转换.
- 泛型与接口
interface Inter<T>{
public void show(T t);
}
实现时候:
class InterImpl implements Inter<String>{
public void show(String t);
}
使用时候和平常一样.
InterImpl in = new InterImpl();
in.show("abc");
后两步或者:
实现时候:
class InterImpl2 <Q>implements Inter<Q><String>{
public void show(Q
t){
//实现方法;
}
}
使用时候:
InterImpl<String> in = new InterImpl<String>();
in.show("abc");
- 泛型与方法:在返回值前
自己定义时候:
public <w> void show(w str){
//对str操作;
}
使用时候:
tool.show("abc");//使用时候直接传对象就可以了,不用额外的操作.
或者借助类的泛型来定义,但是使用时候只能是类的泛型类型.
注意:
静态方法是不能访问类上定义的泛型,因为泛型依赖于对象,只能采用这种方法将泛型定义在方法上.
- 泛型与上下限
- 泛型与通配符;?(未知类型)
? extends person:只能传入Person以及他的子类.下面的使用直接就得使用?extends person.
存的时候使用.
? super person :只能传输Person以及他的父类.
取元素时候使用.
注意:泛型的使用注意集合内的方法也可以被约定类型了,但别越界.
注意:泛型的使用注意集合内的方法也可以被约定类型了,但别越界.
五.用上集合,几多方便?
1.集合使用中需要注意的注意点:
- 使用集合时一般引入java.util包.容器API全在该包中.
- 对于自定义的类需重写equals方法时候,必须重写hashCode()方法,且两对象相等它的hash值也相等.
- 总结:打印重写toString()方法.Set集合重写equals()方法,hashset还需重写hashCode();方法
- 对于Map的键值必须同时重写equals和hashCode方法,并保持一致.
2.如何选择使用的集合:
衡量标准:读的效率和改的效率
- Array:数组=>读快改慢,有角标.
- Linked:链表=>改快读慢,add get remove + first last.
- Hash:哈希表+两者之间,唯一性,元素需要覆盖hashCode和equals().
- tree: 二叉树,排序,两个接口Comparator和comparable.
3.集合的使用方法:
Collection c = new ArrayList();//这样写的好处是:引用变量c可以这次对应着ArrayList类型对象,下次可以对应HashSet对象.即放入不同类型的对象,而且后面的代码不需要修改.
4.遍历集合的两种方法:
- 使用迭代器遍历集合:
- 使用增强型for循环:
for(object o : c)
{....}
该方法的优点:
用于遍历Array或者Collection的时候相当简便
该方法的缺点:
遍历数组时候,不能方便的访问下标值。
遍历集合时候,不能方便的删除集合中的内容。
总结:除了简单的遍历并读取其中的内容外,不建议使用增强for。
五.集合的内部实现:
待续......