集合和泛型
在JDK1.2之前,Java中提供的集合容器数量比较少。到了jdk1.2开始提供大量的集合容器。由于我们在程序中会遇到不同的需求,在存储对象的时候,需要采用不同的方式来存放。集合容器最终它对存放在其中的对象存储的方式不同,这时sun公司就对这些集合容器存放数据的方式以及操作这些集合容器的方法进行了共性的抽取。于是就形成了一个集合体系。把这个体系称为集合框架。而在这个体系的最顶层定义着当前所有集合容器操作的最共性(最基本)的操作行为。
Collection位于java.util包下。集合属于Java中的工具类,都位于util包下。
学习集合要求掌握集合容器的 增加 删除 修改 查询(CRUD) 判断 遍历 这6种操作。
Collection接口是集合体系的顶层接口,它是用来定义集合的最基本的操作行为的。
Collection集合中可以存放多个对象,其中存放的对象称为元素。在Collection下的子类中有些集合中可以存放重复元素,有些不能存放。有些子类可以存放有序数据,有些无序。Collection没有直接实现类,但它有直接的子接口List和Set。
增加:boolean add( Object element ) 把当前的element元素添加到当前的集合中,如果添加没有成功返回false。
删除 :clear() 清空集合中所有元素,会让集合中的size变成0
remove(Object obj) 删除集合中指定的元素
判断:contains(Object obj ) 判断当前obj元素是否在集合中存在
迭代:
集合公共遍历方式:
要遍历集合,首先要做事情先判断集合中有没有元素,有元素就把当前这个元素取出来,然后再判断有没有,如果还有继续取出。直到把所有元素全部取出。
Iterator接口定义了三个方法:迭代器
hasNext() 问集合中有没有下一个元素; 调用这个方法会返回一个boolean类型的值,如果有则返回true, 没有返回false
next() 取出当前这个元素;, 取值
remove() 删除当前的元素;
List接口继承了Collectoin接口,List接口就拿到Collection接口中的所有方法,同时List接口根据自己的特点,还定义了额外,主要是围绕List的下标而设计的特有功能。
List它描述的所有有序集合的公共行为。并且List接口描述的集合它拥有下标(索引index),我们就可以根据这个下标来操作集合中的元素。List接口描述的集合中允许存放重复元素。
List集合存储元素的特点:有序,可重复
List接口的实现类:ArrayList、LinkedList
ArrayList实现了长度可变的数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高 - 查询比较快
LinkedList采用链表存储方式,插入、删除元素时效率比较高
ArrayList是List接口的实现类,它采用的可变数组来存放元素。可变数组:会在ArrayList内部维护一个数组,用来存放调用add方法时传递进来的元素,当数组中存放不下时,这时会在内部自动创建一个新的数组,先把原始数组中的内容存储到新数组中,然后在新增加的内容存放到数组的后面。
ArrayList集合的特点:底层使用可变数组,存储的元素:有序,可重复。
不足:查询快,增删慢。
常用方法:
增加:
boolean add( Object element ) 把当前的element元素添加集合的尾部,成功返回true, 失败返回false;
void add(int index, E element) 在集合中指定位置上添加元素
注意:使用add方法添加元素的时候,一定要保证指定的位置前面有元素。否则会发生下标越界异常。
删除:
remove(Object obj) 删除集合中指定的元素
Object remove(int index) 删除集合中指定位置上的元素,并返回被删除的元素 。删除时指定的下标的位置一定要保证有元素。
clear() 清空集合中所有元素,会让集合中的size变成0。
注意:使用List调用remove如果指定的是值,这时这个值一定是下标(默认),因此如果要删除集合中存放的包装类型的数据, 这时需要把这个int值包装成对应的Integer类型,Integer.valueOf(int)。
修改:
Object set(int index, E element) 修改集合中指定位置上的数据。 原来的元素就被删除掉了。返回被替换的那个元素。
查询:
get(int index) 返回此列表中指定位置上的元素
其他一些方法:
size() 求一个集合的长度
isEmpty(), 判断这个集合是不是空的,如果为空集合返回true,否则为false
boolean contains(Object o) ,判断列表中是否存在指定元素
遍历:
For
Foreach
Iterator
LinkedList也是List接口的实现类
它的底层采用的链接列表(链表),由于链表有头和有尾的数据结构,因此LinkedList集合中定义了自己的特有方法,这些方法都围绕链表的头和尾设计的。新增、删除元素时,效率比较高。
方法名 |
说明 |
void addFirst(Object o) |
在列表的首部添加元素 |
void addLast(Object o) |
在列表的末尾添加元素 |
Object getFirst() |
返回列表中的第一个元素 |
Object getLast() |
返回列表中的最后一个元素 |
Object removeFirst() |
删除并返回列表中的第一个元素 |
Object removeLast() |
删除并返回列表中的最后一个元素 |
二者都是List接口的实现类,存储的元素都是有序可重复的。
ArrayList底层维护的是可变数组来存放元素,查询快,增删慢。
LinkedList底层采用的是链表结构,增删快,查询慢。
Collection接口的另外一个子接口——Set接口
Set接口描述的是一种比较简单的一种集合,集合中的对象并不按特定的方式排序,并且不能保存重复的对象。
HashSet是Set接口的常用实现类。而Set接口继承了Collection接口,同时没有添加新的方法,所以在使用上与List接口的实现类使用方式一致。都是有增加元素的add方法和获取元素个数的size方法。所以只需要进行类的替换就可以了。在这里就不做重复讲解了。
Set集合存储数据的特点:无序,不可重复。
调用set集合添加方法的时候,最终底层在调用object类中的hashCode() - 计算一个对象的hash值的,最终就是一串数字
1:解释HashSet集合如何存放元素:
当我们给HashSet中存放元素的时候,这时并不是直接把这个元素就存放到HashSet内部维护的数组中。
而是先根据当前要存放的那个元素,再结合一种算法(这个方法就是Object类中的hashCode方法),算出当前这个元素应该在数组中存储的位置。
在存放数据的时候,如果计算出来的位置上已经有元素,这时还会去调用当前正要存放的这个元素的equals方法,
把已经在计算出位置上的那个元素一起进行比较,如果equals方法返回的true,就丢弃当前正要存放的元素,不再存储。
如果equals方法返会的false,当前这个对象还要存储。
2:HashSet集合是如何保证元素不重复 (唯一性的)
当给hashset中存放元素的时候会先调用对象的hashCode方法,计算哈希值,根据哈希值来决定当前对象在集合中的存储位置。
在存储的时候,如果遇到了哈希值相同的元素,这时集合的底层还会去调用当前对象的equals方法,判断当前正要存放的对象和
位置上已经存在的对象是否是同一个对象,equals方法返回的true,就认为相同对象,不保存,如果equals方法返回的false,当前对象已经会被保存。
面试题:Set 集合可以使用传统for循环来执行遍历嘛?
要注意的是Set接口不存在get方法,也就是没有List接口中通过索引取值的方法。
List接口是使用for循环通过get方法取出每个对象的方式遍历输出整个集合,Set接口没有get方法要怎么输出呢?
使用foreach和迭代器可以对set集合实现遍历
Collection接口下的所有集合容器,它们中只能保存对象,但无法维护对象和对象之间的对应关系。
因此把Collection接口下的所有集合容器统称为单列集合。
Map集合:
Java中提供Map集合主要用来保存具有一定对应关系的数据。在给Map集合中存放对象的时候,一次要求存放一组(一对)对象。
这个一组(一对)对象之间有一定的对应关系。因此把Map集合称为双列集合。
Map集合中的常用方法:
增加:
put(K key, V value) :把当前的key和value存放到集合中。
注意如果当前的key在集合中已经存在,那么就会用当前的value覆盖
key对应的以前的value值,并且返回被覆盖的那个value值
删除:
clear();清空
remove(Object key) 根据指定的key删除key和value
修改:
可以利用新增方法中key唯一实现对元素的修改
获取:
get(Object key) 根据指定key获取Map集合中key对应的value值,如果key不存在,返回null
size() 获取key-value对应关系的个数
判断:
containsKey(Object key) 判断Map是否包含指定的key,有就返回true
containsValue(Object value) 判断Map是否包含指定的value,有就返回true
isEmpty() 判断Map集合是否为null,它的size 是零
keySet(),获取map中所有的key组成一个set集合。
entrySet() ,获取map中所有的键值对组成一个set集合。
在学习集合的时候,我们知道把数据存放到集合中之后,数据就会被提升成Object类型,在取出的时候,取出来的数据依然Object类型,如果要使用对象的特有功能时,特有数据时,就需要向下转型,只要是向下转型,就有可能发生异常。
在取出集合中元素的时候,由于集合中元素的类型不统一,导致在取出向下转型的时候,可能会发生ClassCastException,这个异常是在运行的时候才发生的。发生这个异常的原因是在给集合中存放对象的时候,由于存储了不同的类型数据,在运行程序过程中,取出时才发生了问题。如果我们能够控制在存放的时候,保证类型统一,那么在取出的时候,就不会发生问题了。
可以借助数组的思想,把集合在定义的时候,就让类型统一起来,如果在源码中给集合中存放数据的时候,如果类型不一致,就不让当前这个程序编译通过,那么就可以避免运行时期的问题了。
泛型技术,是编译时期技术,在编译源码的时候,会判断泛型指定的类型统一问题,当编译完成之后,生成的class文件中是没有泛型内容。
泛型的应用:<具体的数据类型>
<>尖括号中书写的类型是引用数据类型。不能是基本数据类型。
泛型技术,是编译时期技术,在编译源码的时候,会判断泛型指定的类型统一问题,当编译完成之后,生成的class文件中是没有泛型内容。
如:
List
Map
工具类collections用于操作集合类,如List,Set,常用方法有:
sort():排序
binarySearch():查找,如果搜索到了,返回位置(从0开始),找不到,返回一个负数
max()\min():查找最大\最小值
说一下collection 和collections的区别??
2:实现字符串的去重 - 使用2种方式,没有限制
String s = “abcabcab”
需求:返回一个没有重复数据的字符串
作业:
使用Map+泛型技术实现,
Int 类型的包装类
3:统计一个字符串中,每一个字符出现的次数,abcaba ,