1、Collection集合
1.1、集合概述
集合:集合是Java中提供的一种容器技术,可以用来存储多个数据。
集合和数组都是容器技术,它们区别是:
●数组的长度是固定的,集合的长度是可变的
●数组中存储的是同一类型的元素,可以存储基本数据类型值,集合存储的都是对象,而且对象的类型可以不一致,在开发中一般当对象多的时候,使用集合进行存储。
1.2、集合框架
Java提供了满足各种需求的API,在使用这些API前,首先了解其继承与接口的操作架构,才能了解何时用哪个类,以及类之间如何彼此合作,从而达到灵活运用。
集合按照其存储结构可以分为两大类,分别是:单列集合java.util.Collection和双列集合java.util.Map,本章主要学习Collection集合。
Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它由两个重要的子接口,分别是:java.util.List和java.util.Set。其中,List的特点是:元素有序(会按照添加的顺序进行元素的输出),而且可以重复(重复指的是内容一致);Set的特点是:元素无序(输出时无序),而且元素不可以重复。
List接口的主要实现类:
- java.util.ArrayList
- java.util.LinkedList
- java.util.Vector
Set接口的主要实现类:
- java.util.HashSet
- java.util.LinkedHashSet
- java.util.TreeSet
集合本身是一个工具类,它存放在java.util包中。
1.3、Collection常用功能
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:
●public boolean add(E e):把给定的对象添加到当前集合中
● public boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到此集合
● public void clear():从此集合中删除所有元素(可选操作)。.
● public boolean contains(Object o) :如果此集合包含指定的元素,则返回 true 。
● public boolean isEmpty():判断当前集合是否为空
● public boolean remove(Object o):从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
● public int size():返回集合中元素的个数
● public Object[] toArray():把集合中的元素,存储到数组中
package com.bdit;
import java.util.ArrayList;
import java.util.Collection;
/*
Collection集合方法的应用
*/
public class Test1 {
public static void main(String[] args) {
Collection c1=new ArrayList();
//添加元素到集合中
c1.add("zhangsan");
c1.add(100);//
c1.add(96.69);
c1.add(false);
System.out.println("是否为空:"+c1.isEmpty());
System.out.println("是否包含:"+c1.contains(1000));
System.out.println("移除元素:"+c1.remove(100));
System.out.println("元素的个数:"+c1.size());
Collection c2=new ArrayList();
c2.addAll(c1);
System.out.println(c2);
}
}
2、Iterator迭代器
2.1、Iterator接口
在程序开发中,经常需要遍历集合的所有元素,针对这种情况,JDK专门提供了一个接口java.util.Iterator。Iterator接口也是java集合中的一员,但它与Collection、Map接口有所不同。Collectionu接口与Map接口主要用于存储元素。而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。
想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作。
●public Iterator iterator():获取集合对应的迭代器,用来遍历集合中的元素
迭代的概念:
●迭代,即Collection集合元素的通用获取方式,在去元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就继续取出来,一直把集合中所有的元素全部取出。这种取出方式专业术语称为迭代。
●Iterator常用方法:
- public E next():返回迭代的下一个元素
- public E next():返回迭代的下一个元素
package com.bdit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
Itertor迭代器
*/
public class Test2 {
public static void main(String[] args) {
Collection c1=new ArrayList();
c1.add("刘备");
c1.add("关羽");
c1.add("张飞");
c1.add("赵子龙");
c1.add("黄盖");
System.out.println(c1);
//获取集合的迭代器对象
Iterator it=c1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//此处会发生java.util.NoSuchElementException
//如果迭代完毕后,继续调用next方法,将会发生以上异常
System.out.println(it.next());
}
}
2.2、迭代器的实现原理
当遍历集合时,首先通过调用集合的iterator()方法获取迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素。如果存在,则调用next()方法将元素取出,否则说明已经到达了集合末尾,停止遍历元素。
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,为了更好的理解迭代器的工作原理,可以参考一下下列图片:
在调用iterator的next()方法之前,迭代器的索引位于第一个元素之前,不指向任何元素。当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next()方法时,迭代器的索引会指向第二个元素并将该元素返回,以此类推,直到hasNext()方法返回false,表示到达了集合的末尾,终止对元素的遍历。
2.3、增强for循环
增强for循环(也称for each循环)是JDK1.5以后新增的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历过程中,不能对集合中元素进行其它操作。
【使用增强的for循环,无法直接获取每个元素的下标值】
【增强的for循环,只适合用来对数组或集合中的元素进行遍历操作】
package com.bdit;
import java.util.ArrayList;
import java.util.Collection;
public class Test3 {
public static void main(String[] args) {
Collection c1=new ArrayList();
c1.add("刘备");
c1.add("关羽");
c1.add("张飞");
c1.add("赵子龙");
c1.add("黄盖");
//增强for循环
for(Object str:c1){
System.out.println(str.toString());
}
}
}
3、泛型
3.1、泛型概念
集合中可以存放任意对象的,只要把对象存储到集合后,那么这时对象都会被提升(向上转型)为Object类型。当我们在取出每一个对象,并且进行相应操作,这时必须采用类型转换(向下转型)。
观察下面代码:
package com.bdit;
import java.util.ArrayList;
import java.util.Collection;
/*
往集合中添加自定义类对象
*/
public class Test4 {
public static void main(String[] args) {
Collection c1=new ArrayList();
c1.add(new Student(1001,"张三",22));
c1.add(new Student(1002,"李四",23));
c1.add(new Student(1003,"王五",24));
c1.add(new Student(1004,"赵六",25));
//for(Object obj:c1){
//Test4 student=(Test4)obj;
//System.out.println(student);
//}
for(Object obj:c1){
Student student=(Student)obj;
System.out.println(student);
}
}
}
程序在运行时发生了问题java.lang.ClassCastException。为什么会发生类型转换异常呢?分析:
由于集合中什么类型的元素都可以存储,导致取出时强转引发运行时ClassCastException。怎么来解决这个问题呢?Collection虽然可以存储各种对象,但实际上通常Collection只存储一种类型即Object类型。因此在JDK5之后,新增了泛型(Generic)语法,让你在设计API时可以指定类或方法支持泛型,这样我们使用API的时候就变得更为简洁,并通过了编译时期的语法检查。
泛型:可以在类或方法中预支地使用未知的类型。
一般在创建对象时,将未知类型确定为具体类型,当没有指定泛型时,默认类型为Object类型。
3.2、使用泛型的好处
泛型有哪些好处:
- 将运行时期的ClassCastException,转移到编译时期,编译失败
- 避免了类型强转的麻烦
3.3、泛型的定义与使用
消除类型转换
集合类<泛型类型> 对象名=new 集合类<>();
package com.bdit;
import java.util.ArrayList;
import java.util.Collection;
/*
泛型
*/
public class Test5 {
public static void main(String[] args) {
Collection<Student> c1=new ArrayList<>();
c1.add(new Student(1001,"张三",22));
c1.add(new Student(1002,"李四",23));
c1.add(new Student(1003,"王五",24));
c1.add(new Student(1004,"赵六",25));
for (Student stu:c1){
System.out.println(stu);
}
}
}
定义和使用含有泛型的类
定义格式:
修饰符 class 类名<代表泛型的变量>{
}
自定义泛型类:
package com.bdit;
/*
自定义泛型类
*/
public class Test6 {
public static void main(String[] args) {
MyClass<String> myClass=new MyClass<>();
myClass.setName("张三");
System.out.println(myClass.getName());
}
}
class MyClass<MVP>{
private MVP name;
public void setName(MVP name){
this.name=name;
}
public MVP getName(){
return name;
}
}
在创建泛型类的对象时,必须给泛型类型确定为具体类型
例如:MyClass myClass=new MyClass<>();
在此类中MVP就相当于是泛型变量,那么创建对象时传递过来的具体类型,会把泛型类中所有使用到泛型变量的地方,替换为具体类型。
含有泛型的方法
定义格式:
修饰符 <代表泛型的变量> 返回值类型 方法名(参数列表){
}
package com.bdit;
/*
泛型方法
*/
public class Test7 {
public static void main(String[] args) {
Test7 test7=new Test7();
test7.show("张三");
System.out.println(test7.show2(100));
}
public <M> void show(M m){
System.out.println(m.getClass());
}
public <M> M show2(M m){
System.out.println(m.getClass());
return m;
}
}
【无论使用泛型类、泛型方法、泛型接口,传递的泛型类型只能是引用类型】
含有泛型的接口
定义格式:
修饰符 interface 接口名<代表泛型的变量>{
}
package com.bdit;
/*
泛型接口
*/
public class Test8 {
public static void main(String[] args) {
MyImpl1<String> myImpl1=new MyImpl1<>();
myImpl1.add("张三");
}
}
interface MyInter<E>{
public void add(E e);
public E get();
}
//定义实现类
class MyImpl1<E> implements MyInter<E>{
@Override
public void add(E e) {
}
@Override
public E get() {
return null;
}
}
【不能直接new泛型变量的对象,因为无法保证泛型变量就一定是类】