Collection集合框架
文章目录
前言
包含(List接口:Vector集合、ArrayList集合、LinkedList集合)
特点
1、有序的集合,存取顺序一样
2、可以存储重复元素
3、有索引可以使用普通的for遍历
Set接口:TreeSet集合、HashSet集合(无序集合没有重复元素)、LinkedHashSet集合)
特点:
1、不允许重复元素
2、没有索引,不能使用普通的for循环来遍历
两个接口共性抽取形成父接口Collection(定义的是单列集合共性的方法,所有单列集合都可以使用的共性方法)
集合框架的学习:
1、学习顶层:顶层接口/抽象类中的共性方法所有 子类都可以使用
2、学习底层:底层不是接口就是抽象类,需要了解底层的子类创建对象使用
一、Collection接口常用方法
提供所有单列集合都可以使用的共性方法
public boolean add(E e)把给定的对象添加到集合
public void clear();清空集合中所有的元素
public boolean remove(E e);将给定的对象从集合当中删除,如果没有指定的元素会删除失败,返回false
public boolean contains(E e);判断当前集合中是否包含给定的对象
public boolean isEmpty(E e);判断集合是否为空
public int size();返回集合当中的元素个数
public Object[] toArray();把集合当中的元素,存储到数组当中
例如HashSet类 (无序且无重复元素)
public class Demo1Collection {
public static void main(String[] args) {
Collection<String> coll=new HashSet<>();
//向无序无重复元素的HashSet集合当中添加元素
coll.add("Arvin");
coll.add("Kevin");
coll.add("Kiki");
System.out.println("集合当中的元素:"+coll);
coll.remove("Kiki");
System.out.println("通过remove删除指定元素Kiki后:"+coll);
boolean a=coll.isEmpty();
System.out.println("isEmpty判断集合是否为空"+a);
System.out.println("通过size方法获取集合的元素个数:"+coll.size());
System.out.println("通过contains方法判断集合当中是否有Kiki元素:"+coll.contains("Kiki"));
coll.clear();
System.out.println("通过clear方法清空集合元素后查询是狗为空:"+coll.isEmpty());
Object[] array=coll.toArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
运行结果:
集合当中的元素:[Kevin, Arvin, Kiki]
通过remove删除指定元素Kiki后:[Kevin, Arvin]
isEmpty判断集合是否为空false
通过size方法获取集合的元素个数:2
通过contains方法判断集合当中是否有Kiki元素:false
通过clear方法清空集合元素后查询是狗为空:true
二、Iterator接口
迭代:即对Collection集合当中通用的取出元素的方式
两个常用的方法:
public boolean hasNext();如果任然有元素可以迭代,则返回true
判断集合有没有下一个元素,有就返回true,没有返回false
E next();返回迭代的下一个元素
Iterator是一个接口,无法直接使用,需要实现类的对象,获取的方法比较特殊
Collection接口当中有一个方法,叫做iterator(),这个方法可以返回实现类的对象
迭代器的使用步骤:(重点)
1、使用集合Collection调用方法iterator()获取迭代器的实现类对象
Collection coll=new HashSet<Integer>();
Iterator iterator = coll.iterator();
2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
3、使用Iterator接口 的方法next取出集合中的下一个元素
注意:Iterator接口也是有泛型的,迭代的泛型跟着集合走,泛型跟集合保持一致
public class Demo2Iterator {
public void method(Iterator<String> e){
while(true){
if(e.hasNext()){
System.out.println(e.next());
}
else{break;}
}
}
public static void main(String[] args) {
//多态
Collection<String> coll=new ArrayList<>();
coll.add("Arvin");
coll.add("Kevin");
coll.add("Kiki");
//用个Collection的方法iterator()获取Iterator迭代器接口的对象
Iterator<String> it=coll.iterator();
new Demo2Iterator().method(it);
}
}
结果:
Arvin
Kevin
Kiki
迭代器的原理:
Collectoin<E> coll=new HashSet<E>();
Iterator<E> it=coll.iterator();
coll.itetator();将集合的索引从0指向-1
it.hasNext();判断集合有没有下一个元素,有就返回true,没有返回false
it.next();做了两件事:
1、打印集合的下一个元素
2、把指针向后移动一位
增强for循环:(底层使用的也是迭代器,只是使用for循环的格式简化了迭代器的书写)
是jdk1.5之后出现的新特性。
Collection extends Iterable;所有的单列表集合都可以使用增强for循环。
public interface Iterable;实现这个接口允许对象成为foreach语句的目标。
所有增强for循环可以遍历数组和集合。
格式:
for(集合/数组数据类型 变量名:集合/数组名){
sout(变量名)}
public class Demo3Foreach {
public static void main(String[] args) {
//创建以个数组
String[] array={"Arvin","Kevin","Kiki"};
//使用增强for循环来遍历这个数组
for (String i:array
) {
System.out.println("增强for循环遍历数组:"+i);
}
//创建一个集合
HashSet<String> set=new HashSet<>();
set.add("Arvin");
set.add("Kevin");
set.add("Kiki");
//foreach遍历;;注意第一个是数组或者集合的数据类型
for (String i:set
) {
System.out.println("foreach来遍历集合:"+i);
}
}
}
DataResult:
增强for循环遍历数组:Arvin
增强for循环遍历数组:Kevin
增强for循环遍历数组:Kiki
foreach来遍历集合:Kevin
foreach来遍历集合:Arvin
foreach来遍历集合:Kiki
泛型的概念
是一种未知的数据类型,当我们不知到使用什么数据类型的时候,可以使用泛型 泛型也可以看作与i个变量用来接受数据类型。
E e:Element 元素
T t:Type 类型
列如:ArrayList集合再定义的时候,不知道集合当中都会存储什么类型的数据,所以使用泛型
所以E:看作未知数据类型
再创建对象的时候,就会确定泛型的数据类型
列如 ArrayList list=new ArrayList<>();
会把数据类型作为参数传递,把数据类型的值给泛型E
使用泛型的好处:
1、不使用泛型:好处 集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据
弊端:不安全,会发生异常
默认的Object类型如果打印的结果想要转型成string字符串,那么
需要使用向下转型,先将类型转换成String类型,但是如果字符串里面有Integer等类型的数据,那么就会产生类型转换错误。
2、使用泛型:
2.1、避免了类型转换的麻烦,存储的什么类型,取出的就是什么类型
2.1、把运行期的异常(代码运行之后才会产生的异常),提升到了编译器(写代码的时期)
弊端:
泛型是什么类型,就只能存储什么类型的数据
public class Demo4KownElement {
public static void main(String[] args) {
//不使用泛型创建一个集合,默认是Object类型,可以存储任意数据
HashSet set=new HashSet<>();
set.add("aaa");
set.add(3);
set.add(6);
//获取迭代器对像来输出遍历输出
Iterator it=set.iterator();
/*while(it.hasNext()){
//现在想用int来接受这些参数
//int num=(Integer)it.next();//ClassCastException程序运行报错ClassCastException
//发生类类型转换异常,应为集合当中有字符串
//System.out.println(num);
}*/
//使用泛型来创建一个集合
ArrayList<Character> list=new ArrayList<>();
list.add('a');
list.add('b');
//Object a=list.get(0);
//除了Object只能当前泛型的数据类型才能接收数据
char a=list.get(0);
}
}
定义和使用含有泛型的类
就可以在类创建对象的时候进行定义数据类型
public class Demo5Calss_E<E> {
private E name;
private E sex;
public Demo5Calss_E() {
}
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
public E getSex() {
return sex;
}
public void setSex(E sex) {
this.sex = sex;
}
public static void main(String[] args) {
//定义一个泛型的类,在创建对象的时候定义类型,类中所有的东西都是E 泛型
Demo5Calss_E<String> e=new Demo5Calss_E<>();
e.setName("Arvin");
e.setSex("男");
String a = e.getName();
String b = e.getSex();
System.out.println("姓名"+a+" "+"年龄"+b);
}
}
DataResult:
姓名Arvin 年龄男
定义含有泛型的方法
泛型定义在方法修饰符和返回值之间
格式:修饰符 《泛型》 返回值类型方法名 (参数列表(泛型)){}
含有泛型的方法,在调用方法的时候就确定泛型的数据类型,传递什么类型的参数、泛型就是什么类型
定义含有泛型的方法:泛型定义在方法修饰符和返回值之间
格式:修饰符 《泛型》 返回值类型方法名 (参数列表(泛型)){}
含有泛型的方法,在调用方法的时候就确定泛型的数据类型,传递什么类型的参数、
泛型就是什么类型
public class Demo6Method_E {
//创建一个含有泛型的成员方法
public <E> void method(E e){
E name=e;
System.out.println(name);
}
//创建一个含有泛型的静态方法
public static <E> void method2(E e){
System.out.println(e);
}
public static void main(String[] args) {
//创建当前类的对象
Demo6Method_E demo6=new Demo6Method_E();
//通过对象调用含有泛型的方法,传递的参数是什么数据类型,泛型就是什么类型
demo6.method("Arvin");
demo6.method(66);
//调用静态方法有两种方式1、通过对象调用(不推荐)2、之间使用类名来调用
demo6.method2("Arvin");
Demo6Method_E.method2("Kevin");
}
}
DataResult:
Arvin
66
Arvin
Kevin
定义接口当中的泛型
1、定义接口的实现类,实现接口,指定接口的泛型
public class Impl implements Interface<指定泛型>{}
public class Demo7Implements implements Demo7Interface_E<String> {
//数据类型定义在接口后边
//重写覆盖方法
@Override
public void method1(String e){
System.out.println(e);
}
public static void main(String[] args) {
Demo7Implements impl=new Demo7Implements();
impl.method1("Arvin");
//impl.method1(44);
}
}
DataResult:
Arvin
接口使用什么泛型,实现类就使用什么泛型,相当于实现类是一个含有泛型的类,在创建对象的时候确定泛型的数据类型
public class Implements<E> implements Interface<E> {}
public class Demo7Implements_2<E> implements Demo7Interface_E<E>{
//接口的泛型和实现类的泛型一样
@Override
public void method1(E o) {
System.out.println(o);
}
public static void main(String[] args) {
//通过创建实现类的对象给泛型数据类型
Demo7Implements_2<String> impl=new Demo7Implements_2<>();
impl.method1("Arvin");
}
}
DataResult:
Arvin
泛型的通配符<?>
? :代表任意的数据
使用方式:
不能创建对象,只能作为方法的参数使用
作用:列如可以定义一个方法,可以遍历所有类型的ArrayList集合
对于写ArrayList 是不可以的应为泛型没有继承概念
public void printArrays(ArrayList<?> lsit){
}
public class Demo8ElemntType {
public static void method(ArrayList<?> list){
//通过Collection的对象来调用iterator()方法,获取迭代器的对象
Iterator<?> it=list.iterator();
//用迭代器来遍历集合
while (it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args) {
//创建了连个不同数据类型的集合
ArrayList<String> list=new ArrayList<>();
list.add("Arvin");
ArrayList<Integer> list2=new ArrayList<>();
list2.add(66);
//现在定义一个方法可以接受任意数据类型,来遍历集合
//就需要使用泛型通配符?
method(list);
method(list2);
}
}
DataResult:
Arvin
66
泛型的上下限
泛型的上限: <? extends 数据类型> 代表使用的泛型只能是数据类型的子类/本身
泛型的下限:<? super 数据类型> 代表使用的泛型必须是数据类型是父类或者本身
对于泛型通配符权限的一个限定