JAVA集合可以更方便的存储数据,相对于数组来说有很大的优势,集合的容量可以动态的添加,而数组定义后大小不可变,集合分为Collection和Map两种单双列集合。
JAVA集合框架
总述:集合包括三大接口Iterator、Collection和Map;均属于java.util包下
集合与数组的区别:
数组在定义后,其长度是固定的,但如果需要增大数组,需要自己编写动态数组的实现;可以存储基本类型数据,也可以存储引用类型数据。
集合的长度是可动态变化的,只能存储引用类型数据。
Collection:方法 15+
- 在JDK1.2之后出现;该接口不提供任何方法的具体实现,对象实例表示可以存储一组对象,这一组对象称为Collection的元素;一些Collection是允许元素重复的,也有不允许元素重复;一些Collection元素有序,也有无序的。
对于Collection又可以分为两个子接口List和Set:
Collection接口定义的方法按照功能分类:
添加功能:
boolean add(Object o)————添加任意类型数据,添加成功返回true
boolean addAll(Collection c)————将一个集合中所有元素添加至集合,调用集合添加参数集合中的所有元素删除功能:
void clear()————移除集合中全部元素,没有返回值
boolean remove(Object o)————移除集合中指定元素,集合元素被移除返回true
boolean removeAll(Collection c)————移除元素,调用集合移除参数集合中包含的元素,调用集合元素发生更改,返回true,参数集合不发生变化判断功能:
boolean contains(Object o)————判断指定元素是否存在,调用集合中存在参数元素,返回true
boolean containsAll(Collection c)————判断集合中是否包含指定集合元素,调用集合包含参数集合中全部元素返回true
boolean isEmpty()————判断该集合是否为空,集合为空返回true获取功能:
Iterator Iterator()————集合的迭代器,用于集合的遍历,返回集合用于遍历的iterator对象【a】
Object[] toArray()————将集合元素转换为数组形式,返回Object类型数组
T[] toArray(T[] t)————将集合元素返回指定类型的数组形式,返回集合所有元素的数组,集合元素可以直接存储在参数数组中(前提是参数数组必须大小与集合转化为数组大小相同,可以小于将转化为的数组,但是只有在返回的数组大小与参数数组大小一致时才存储在参数数组中),也作为返回值返回长度功能:
int size()————得到集合的长度,返回调用集合长度
交集功能:
boolean retainAll(Collection c)————仅保留两个集合中重复的元素,并且将重复元素存储在调用集合中,调用集合元素发生更改返回true,参数集合不发生变化
【a】Iterator对象有三个方法:boolean hasNext(),E next(),void remove();
hasNext();如果迭代后面仍有元素,返回true
next();返回迭代的下一个元素,并同时指向下一个元素
remove();从集合中移除迭代器返的最后一个元素,每调用一次next仅可以用一次该方法Iterator接口是在具体实现类中通过内部类实现,以此来针对不同的数据组织形式,编写hasNext(),next()和remove()方法。
迭代器是依赖于集合存在的,如果在使用迭代器的时候,使用集合修改元素,,这时迭代器并不能发现集合元素的变化,所以就会报出错误【ConcurrentModificationException,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。】但是有时就是需要在遍历时添加元素,这是我们就需要解决这种异常错误;有两种方法;A:在使用迭代器遍历时,使用迭代器提供的方法修改元素,但是在Iterator中并没有提供添加元素的方法,这就需要用到ListIterator接口提供的方法(只有在List集合中存在该接口)。B:使用集合遍历元素,利用集合提供的方法修改元素(普通for)。
只有在List类型的集合才能使用ListIterator接口;在后面有Listiterator的示例代码。不允许既使用迭代器又使用集合。对Collection接口定义的方法代码演示:
static void collection(){ //创建集合对象,接口不能实例化,需要使用其子实现类实例化 Collection<Student> coll = new ArrayList<>(); Collection<Student> c = new ArrayList<>(); //创建要添加的元素 Student s1 = new Student("张三",12); Student s2 = new Student("李四",15); Student s3 = new Student("王五",19); //向集合中添加元素 coll.add(s1); coll.add(s2); coll.add(s3); c.add(s1); c.add(s2); //向集合中添加一个集合 coll.addAll(c); //移除集合中指定的单个实例 coll.remove(s1); //移除集合中与参数集合中所有相同的元素 coll.removeAll(c); //移除集合中所有的元素 c.clear(); c.add(s3); System.out.println("判断元素s1是否存在集合coll中:" + coll.contains(s1)); System.out.println("判断参数集合中元素是否为调用集合元素的子集:" + coll.containsAll(c)); System.out.println("判断集合是否为空:" + coll.isEmpty()); //将集合对象转为一个数组 Object[] o = coll.toArray(); Student s = (Student)o[0]; System.out.println(s.getName()+ "---" + s.getAge()); //获取集合的大小 System.out.println("该集合共有元素:" + coll.size()); //保留两个集合的交集元素,保留元素存放在调用集合中 coll.retainAll(c); //使用Iterator方法遍历集合 Iterator<Student> i = c.iterator(); while(i.hasNext()){ Student ss = new Student(); ss = i.next(); System.out.println(ss.getName() + "---" + ss.getAge()); } } /*输出结果(需要一个Student类): 判断元素s1是否存在集合coll中:false 判断参数集合中元素是否为调用集合元素的子集:true 判断集合是否为空:false 王五---19 该集合共有元素:1 王五---19 */
首先学习了Collection,练习了其接口方法,掌握集合的基本使用;一些集合允许重复,一些不允许重复;一些元素有序,一些无序;那么这就与集合接口的具体实现有关系了,该接口存在两个子接口:List和Set两类。他们都包含了父类方法,同时也添加了适合自己数据结构的一些方法。
List:新增方法 10+
- 允许元素重复,有序的集合,用户可以对元素的插入位置精确的控制,也可以通过整数索引访问元素;
- 具体常用实现类:ArrayList、LinkedList和Vector
新增方法:
- void add(int index,E e)————向集合指定位置添加元素
- void addAll(int index,Collection
Set:无新增方法
- 这种集合不允许元素重复,集合元素也是无序的
- 该集合的实现类有:TreeSet和HashSet两种类型
- 无新增方法
- 代码演示:在子类中实现
#### HashSet:方法:8+ 底层使用哈希表,要hashCode和equals两个方法保证集合元素的唯一性,使用的是HashMap的put方法添加元素;对于自定义的一些类对象,就需要我们重写hashCode和equals方法(IDE工具可以自动生成) 代码示例
static void hashSet(){ HashSet<Student> hs = new HashSet<>(); hs.add(new Student("张三",12)); hs.add(new Student("李四",50)); hs.add(new Student("王五",20)); hs.add(new Student("张三",19)); hs.add(new Student("张三",12)); for(Student s : hs){ System.out.println(s.getName() + "---" + s.getAge()); } } //Student对象中需要重写hashCode和equals方法,因为添加元素并保证元素的唯一性需要通过这两个方法的返回值决定 /*输出结果:通过输出结果可以看到,集合元素的顺序和我们输入的顺序不一致 李四---50 张三---12 王五---20 张三---19 */
LinkedHashSet:无新方法 这是一种有序并且保证集合元素唯一的类,父类是HashSet
- 示例代码:略(使用方法和HashSet一样)
TreeSet:方法:26+ 该类型集合底层实现是使用红黑树(自平衡二叉树),其中的元素是无序的(元素是按照代码中的排序方式排序的:自然排序和比较器排序Comparable,具体实现取决于构造方法Comparator)集合的具体实现是使用的TreeMap的方法
代码示例:
/* * 集合的唯一性通过排序方法中的比较方法返回值决定的,返回为0,表示元素重复 * 排序方式有两种 * 自然排序:让元素所属的类实现Comparable接口 * 比较器排序:让集合的构造方法接受一个Comparator子类对象 * 两种排序方法在重写方法中编写排序方式 */ static void treeSet(){ //创建集合对象,使用自然排序,在String类中实现了Comparable<E>接口 TreeSet<String> ts = new TreeSet<>(); //添加集合元素 ts.add("第一个"); ts.add("第二个个"); ts.add("啊啊"); ts.add("第一个"); //Set集合不允许匀速重复 for(String s : ts){ System.out.println(s); } System.out.println("--------------"); /* * 对存储自定义对象 * 这是就需要注意了,如果使用存储自定义对象就必须在自定义对象类中实现Comparable接口 * 实现接口中的compareTo方法,在该方法中定义自己需要的排序方式 * 在自定义对象中设置的按照年龄排序,然后年龄相同在比较姓名,如果两者相同则认为同一对象 */ //使用无参构造方法 TreeSet<Student> ts2 = new TreeSet<>(); ts2.add(new Student("张三",12)); ts2.add(new Student("李四",50)); ts2.add(new Student("王五",20)); ts2.add(new Student("张三",19)); ts2.add(new Student("张三",12)); ts2.add(new Student("张三",12)); for(Student s : ts2){ System.out.println(s.getName() + "---" + s.getAge()); } System.out.println("--------------"); //使用比较器比较元素;使用有参构造方法 TreeSet<Student> ts3 = new TreeSet<>(new MyComparator()); ts3.add(new Student("张三",12)); ts3.add(new Student("李四",50)); ts3.add(new Student("王五",20)); ts3.add(new Student("张三",19)); ts3.add(new Student("张三",12)); ts3.add(new Student("张三",12)); for(Student s : ts2){ System.out.println(s.getName() + "---" + s.getAge()); } System.out.println("----------------"); //参数中直接创建接口的实现内部类;实现Comparator接口的方法 TreeSet<String> ts1 = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { int i1 = o1.length() - o2.length(); int i2 = i1==0?o1.compareTo(o2):i1; return i2; } }); ts1.add("第一个"); ts1.add("第二个个"); ts1.add("第三个"); ts1.add("啊啊"); for(String s : ts1){ System.out.println(s); } } /*输出结果: 啊啊 第一个 第二个个 -------------- 张三---12 张三---19 王五---20 李四---50 -------------- 张三---12 张三---19 王五---20 李四---50 ---------------- 啊啊 第一个 第三个 第二个个 */
Collection集合的简单总结:
- Collection
- List:有序,可重复
- ArrayList:增删慢,查找快;底层使用数组,线程不安全,效率高
- Vector:增删满,查找快;底层使用数组,线程安全,效率低
- LinkedList:增删快,查找慢;底层使用链表
- Set:无序,不可重复
- HashSet:集合元素有序,底层使用哈希表,依靠hashCode和equals方法,保证元素唯一
- LinkedHashSet:底层是链表和哈希表(链表保证有序,哈希表保证唯一)
- TreeSet:底层使用自平衡二叉树,有两种排序方案:自然排序(Comparable)、比较器排序(Comparator),实现该接口,保证唯一依赖的是排序方法的返回值,0表示元素重复
- HashSet:集合元素有序,底层使用哈希表,依靠hashCode和equals方法,保证元素唯一
- List:有序,可重复
Map:方法 14+
- 该集合是一种将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。Map的数据结构键有关,是双列结构
- 该接口的使用是通过HashMap和TreeMap两个实现类
Map方法按照功能分类:
添加功能:
V put(K key,V value)————添加/修改一对键值对元素,返回集合之前键对应的值
void putAll(Map
Map集合的简单总结:
- Map:这是双列集合,采用键值对的方式,数据结构与键有关,与值无关
- HashMap:采用哈希表保证元素的唯一性,但是元素不保证有序,需要实现hashCode和equals方法
- LinkedHashMap:采用链表和哈希表,链表保证有序,哈希表保证唯一
- TreeMap:采用红黑树的数据结构保证元素的唯一性,使用该种集合,元素所属的类需要实现Comparable接口,或者该集合的构造方法参数是一个比较器排序的对象Comparator
集合工具
单列集合(Collection)和双列集合(Map);那么还有一个集合的工具类:Collections该类提供的方法很多,都是静态方法,只列举几个常用的方法
void sort(List list)————默认情况是自然排序,集合元素所属的类必须实现自然排序接口才可以使用排序方法
int binarySearch()————二分查找
max(Collecton<?> c)————最大值
void reverse(List<?> list)————反转
void shuffle(List<?>list)————随机置换
更多方法参考JAVA API