16.泛型,迭代器和list集合

第一节 概念
1.1 集合的概念

集合:就是一个存储数据的容器。
集合与数组一样,也是一个容器,与数组的区别:
1 数组长度固定,集合的长度不固定。
2 数组可以存储基本类型和引用类型,集合中存储的元素类型只能是引用类型。

1.2 集合的框架结构介绍

Collection集合的框架结构
在这里插入图片描述

Map集合的框架结构
在这里插入图片描述

1.3 集合与数组的对比

相同点:

都是数据的容器,在一个数组或集合中可以存储多个数据

不同点:

元素: 数组中可以存储基本类型和引用类型,集合只能存储引用类型
长度(元素个数):
数组是定长的,一旦初始化长度就不可以修改
集合长度可以修改,可以删除元素和添加元素

第二节 Collection接口

Collection 层次结构集合中的根接口。
List派系:可以重复、有序
Set派系:不能重复、无序

2.1 Collection中常用的方法
方法名描述
add(E e)确保此 collection 包含指定的元素(可选操作)。
addAll(Collection<? extends E> c)将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
clear()移除此 collection 中的所有元素(可选操作)。
contains(Object o)如果此 collection 包含指定的元素,则返回true。
containsAll(Collection<?> c)如果此 collection 包含指定 collection 中的所有元素,则返回 true。
equals(Object o)比较此 collection 与指定对象是否相等。
isEmpty()如果此 collection 不包含元素,则返回true。
iterator()返回在此 collection 的元素上进行迭代的迭代器。
remove(Object o)从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
removeAll(Collection<?> c)移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
retainAll(Collection<?> c)仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
size()返回此 collection 中的元素数。
toArray()返回包含此 collection 中所有元素的数组。
第三节 泛型
3.1 什么是泛型(只能表示引用类型

泛型就是可以表示一个广泛数据类型的类型参数(泛型只能表示引用类型),把数据类型作为参数来传递。
形式参数:声明方法时,在方法的参数列表中声明,而且在方法体中会使用到,是一个未知的数据。
实际参数:调用方法时,实际传递的参数。
类型参数:在一个类中声明一个未知的数据类型,在类中可以使用这个类型,但是具体类型取决于实例化时传入的实际类型。

3.2.1 泛型声明在类中:
  • 泛型类:泛型可以声明在类中,只是一个编译时概念,实际反编译得到的结果其实并没有泛型。
  • @author wgy
  • <>:表示泛型
  • T(Type): 标识符 ,就是一个数据类型的占位符 E(element) T V(value) K(key)
  • 泛型参数可以写多个,中间用逗号隔开
  • 泛型好处:
  • (1)提高代码的重用性
  • (2)防止类型转换异常,提高代码的安全性
    public class Generic<T> {//泛型声明在类中,在类的创建及初始化时要求确认具体类型
    	//1 使用泛型创建成员变量
    	T t;
    	//2 使用泛型作为方法的参数类型
    	public void show(T t) {
    		System.out.println(t);
    	}
    	//3使用泛型作为方法的返回值类型
    	public T getT() {
    		return t;
    	}
    	
    }


##### 3.2.1 泛型声明在接口:

```java
public interface MyInterface<E> {//泛型声明在接口,子类在实现泛型的时候必须先确认具体类型
    void show(E e);
    E get();
}
3.3 说明
1)标识符(占位符):只要是一个合法的标识符即可,一般情况下,只使用一个大写字母表示泛型

2)泛型的类型与声明的类或接口不需要有任何的关系

3)泛型可以在类中充当任何的成员

4)泛型是JDK1.5以后增加的,它可以帮助我们建立类型安全的集合。在使用了泛型的集合中,遍历时不必进行强制类型转换。JDK提供了支持泛型的编译器,将运行时的类型检查提前到了编译时执行,提高了代码可读性和安全性。   
泛型的本质就是“数据类型的参数化”。 我们可以把“泛型”理解为数据类型的一个占位符(形式参数),即告诉编译器,在调用泛型时必须传入实际类型
3.4 泛型使用时的注意事项

1)泛型不能在类中声明静态属性、常量
final修饰的属性必须在声明的同时初始化,所以泛型不能声明常量。
static修饰的属性是静态属性,先于对象,泛型类型取决于创建对象时传入的实际类型,所以泛型不能声明静态属性
综上所述:不能使用泛型声明静态属性、常量
2)泛型不能在类中初始化数组,但是可以声明数组
初始化数组时需要给元素进行分配空间,但是泛型类型不确定无法分配空间
3)在类中不能使用泛型声明参数个数相同的重载方法
当一个类中有两个泛型时,创建对象时,两个泛型使用相同类型替换,那么重载方法就是相同的方法(同名,参数列表也相同)
4)使用不同实际类型创建出的泛型类对象的引用不可以相互赋值。

3.5 受限泛型(理解即可)

上限类型和下限类型
1)<?>:表示任意类型
2)<? extends T>:表示T类或者T类的子类
3)<? super T>:表示T类或者T类的父类

public class Damon<T> implements MyInterface {
    T name;
    T age;

    @Override
    public T getName() {
        return name;
    }

    public Damon(T name, T age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void show() {
        System.out.println(age);
    }
}
public class lin extends Damon {

    public lin(Object name, Object age) {
        super(name, age);
    }
}
	public static void main(String[] args){     
    	Generic01<Lin> generic01 = new Generic01();
        print(generic01);

    }
//泛型类作为方法参数,泛型自己的参数需要是Damon以及Damon的子类,<? super Lin>
//Lin以及Lin的父类
    public static void print(Generic01<? extends Damon>  damon){
        System.out.println("hello");
    }
3.6 泛型应用在集合上

泛型在集合中应用,表示的是集合中元素的类型

第四节 Iterator迭代器
4.1 迭代器的工作原理

迭代器相当于一个游标,最初获取迭代器时,迭代器的位置在所有元素的前面,每迭代一个元素,返回当前元素,迭代器向后移动一个位置

在这里插入图片描述

4.2 迭代器的使用
方法名描述
hasNext()判断迭代器是否存在下一个元素可以迭代
next()迭代器迭代下一个元素
remove()从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
        //使用列表迭代器,迭代器的实例化并不是用迭代器的构造器,而是使用集合的方法。  
        ListIterator<String> it2 = list.listIterator();

不可以使用for循环同时进行删除和查找操作

每次使用都是现在的集合所对应的迭代器,如果集合更改,迭代器并不会改变

使用迭代器的时候每一次it.next()都会返回当前指向对象,指向下一个元素,所以如果需要使用的话先把他拿出来

     Linkman linkman = it.next();
     if(linkman.getName().equals(name)){
     	System.out.println(linkman);
     }

错误实例:

     if(it.next().getName().equals(name)){
     	System.out.println(it.next());
     }

第五节 List接口
方法名描述
add(int index, E element)在列表的指定位置插入指定元素(可选操作)。
addAll(int index, Collection<? extends E> c)将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。
containsAll(Collection<?> c)如果列表包含指定 collection 的所有元素,则返回true。
get(int index)返回列表中指定位置的元素。
indexOf(Object o)返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
lastIndexOf(Object o)返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
listIterator()返回此列表元素的列表迭代器(按适当顺序)。
remove(int index)移除列表中指定位置的元素(可选操作)。
set(int index, E element)用指定元素替换列表中指定位置的元素(可选操作)。
subList(int fromIndex, int toIndex)返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
5.1 List接口的存储特点
1 相对有序存储,可以存储相同元素(不排重),可以通过下标访问集合元素
2 List接口中可以使用独有的迭代器ListIterator,具有反向遍历的功能
5.2 List接口的实现类

5.2.1 ArrayList类

ArrayList类是List接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。
存储特点:
	相对有序存储,可以存储相同元素(不排重),可以通过下标访问集合元素,通过数组实现的集合
存储结构:数组

ps:ArrayList虽然没有实现toString但是Arraylist的父类已经重写了toString,
尽量使用迭代器完成循环,不可以使用集合.length作为循环的条件删除元素,因为每次删除会导致集合的长度变化

代码实现:

public class ArrayListDemo {
         	public static void main(String[] args) {
              	//创建一个ArrayList集合
            	ArrayList<String> list = new ArrayList<>();//构造方法中的泛型可以省略
              	list.add("zhangsan");//向集合中添加元素
              	list.add("lisi");
              	list.add("wangwu");
              	System.out.println(list.isEmpty());//判断list集合是否为空集合
              	System.out.println(list.size());//查看集合中元素的个数
              	System.out.println(list.get(1));//获取集合中下标为1的元素
              	System.out.println(list.set(1,"zhaoliu"));//修改集合中下标为1的元素
              	System.out.println(list.contains("wangwu"));//查看"wangwu"是否是集合中的元素
              	list.remove("wangwu");//删除集合中"wangwu"元素
              	list.remove(1);//删除集合中下标为1的元素
              	//for循环遍历集合
                for(int i=0; i<list.size(); i++){
                  System.out.println(list.get(i));
                }
              	//使用Iterator迭代器遍历
              	Iterator<String> it = list.iterator();//获取迭代器
                while(it.hasNext()){
                  System.out.println(it.next());
                }
              	//使用ListIterator迭代器遍历
              	ListIterator<String> lit = list.listIterator();
                while(lit.hasNext()){
                  System.out.println(lit.next());
                }
              	//反向遍历
                while(lit.hasPrevious()){
                  System.out.println(lit.previous());
                }
         }
}

当传入参数是自定义的对象时

  		//arralis判断的依据时equals
        ArrayList<Student> students=new ArrayList<>();
        //1添加
        Student s1=new Student("少泊", 20);
        students.add(s1);
        students.add(new Student("发海", 18));
        students.add(new Student("真真", 17));
        students.add(new Student("凯迪", 19));

        System.out.println(students.toString());

		//2删除(依据是什么? equals方法的返回值,如果true则删除,如果false则不删除)
        students.remove(new Student("少泊", 20));
        System.out.println("删除之后:"+students.toString());
        //3遍历
        for (Student student : students) {
            System.out.println(student.toString());
        }
        //4判断
        //4.1判断是否存在(equals方法)
        System.out.println(students.contains(new Student("少泊", 20)));

        //5获取位置
        System.out.println(students.indexOf(new Student("少泊", 20)));

    //remove 源码,所以如果想要实现对指定属性的元素进行操作,需要重写操作对象的equals方法
	public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

5.2.2 LinkedList类

LinkedList类是List接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括null)。
存储结构:
	双向链表
存储特点:
	相对有序存储,可以存储相同元素(不排重),可以通过下标访问集合元素,通过链表实现的集合

**
 * LinkedList的使用
 * 存储结构:链表
 * @author wgy
 *
 */
public class Demo5 {
	public static void main(String[] args) {
		//创建集合
		LinkedList<String> linkedList=new LinkedList<>();
		//1添加元素
		linkedList.add("苹果");
		linkedList.add("葡萄");
		linkedList.add("西瓜");
		linkedList.add("芒果");
		linkedList.add("桃子");
	
		System.out.println("元素个数:"+linkedList.size());
		System.out.println("打印:"+linkedList.toString());
		//2删除
//		linkedList.remove(0);
//		System.out.println("删除之后:"+linkedList.toString());
		//3遍历
		//3.1for
		//3.2foreach
		//3.3迭代器
		System.out.println("-----------迭代器-----------");
		Iterator<String> it = linkedList.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		//3.4 列表迭代器
		System.out.println("-----------列表迭代器-----------");
		ListIterator<String> lit = linkedList.listIterator();
		while(lit.hasNext()) {
			System.out.println(lit.next());
		}
		//3.5降序迭代器
		System.out.println("-----------降序迭代器-----------");
		Iterator<String> dit = linkedList.descendingIterator();
		while(dit.hasNext()) {
			System.out.println(dit.next());
		}
		
		//4判断
		System.out.println("isEmpty:"+linkedList.isEmpty());
		System.out.println("苹果:"+linkedList.contains("苹果"));
		//5查找位置
		System.out.println("桃子的位置:"+linkedList.indexOf("桃子"));
		
	}
}


ArrayList和LinkedList的总结

ArrayList存储结构是数组,LinkedList存储结构是双向链表。
ArrayList集合适用在对元素查询、遍历操作,不适合插入和删除。
LinkedList集合适用在对元素插入和删除操作,不适合遍历和查找。

5.2.3 Vector(了解)

Vector类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是Vector
的大小可以根据需要增大或缩小,以适应创建 Vector后进行添加或移除项的操作。

public static void main(String[] args) {
		//创建集合
		Vector<String> vector=new Vector<>();
		//1添加元素
		vector.add("xxx");
		vector.add("yyy");
		vector.add("zzz");
		System.out.println(vector.toString());
		//2删除
//		vector.remove(0);
//		System.out.println("删除之后:"+vector.toString());
		//3遍历
		//3.1for
		//3.2foreach
		//3.3迭代器
		//3.4枚举器
		Enumeration<String> elements = vector.elements();
		while(elements.hasMoreElements()) {
			System.out.println(elements.nextElement());
		}

5.2.4 Stack(了解)

Stack类表示后进先出(LIFO)的对象栈。是Vector的子类。

public static void main(String[] args) {
		//创建集合(先进后出,后进先出)
		Stack<String> stack=new Stack<>();
		//1入栈
		stack.push("abc");
		stack.push("hello");
		stack.push("你好");
		stack.push("他好");
		stack.push("大家好");
		//2出栈
		System.out.println("---------出栈---------");
		int size=stack.size();
		for(int i=0;i<size;i++) {
			String s=stack.pop();
			System.out.println(s);
		}
	}

5.2.5 使用Linkedlist实现队列

        //Queue队列接口
		//创建对象
        Queue<String> queue=new LinkedList<>();
        //1添加元素
        queue.offer("张三");
        queue.offer("李四");
        queue.offer("王五");
        queue.offer("赵六");
        queue.offer("少泊");

        //实现队列操作
        int size=queue.size();
        for(int i=0;i<size;i++){
            System.out.println(queue.poll());
        }

        System.out.println("执行完:"+queue.size());

5.2.6 ArrayList与LinkedList,Vector三种实现类存储的比较

a.功能基本相同
b.底层存储结构:ArrayList是数组,LinkedList是链表,Vector是数组
c.Vector是一个古老的集合,从JDK1.0开始就有了,Vector存在一些方法名比较长的方法,xxxElement,存在一个枚举器类专门枚举Vector中的元素,现已被迭代器取代。
d.Vector是线程安全的,效率低,ArrayList是线程不安全的,效率高,推荐使用ArrayList【Collections工具类中有相应的方法可以将ArrayList改为线程安全的】
e.ArrayList查找遍历比较快,LinkedList插入删除比较快

总结

1 集合概念,用来存储一组数据的容器。和数组类似
数组是长度固定的,集合长度可以变化。
数组能存储基本类型和引用类型,集合只能存储引用类型。
2 Collection接口,父接口, add() remove() clear() contains() iterator()
3 Collection有两个子接口 List和Set
4 泛型:本质使用数据类型作为参数传递
4.1 定义泛型类 泛型方法 泛型接口(类在书写时即要求确认泛型类型)
4.2 使用泛型类创建类对象,指定泛型的实际类型
4.3 泛型限制,<?> 表示任何类型
<? extends T> 表示泛型上限, T类型或T的子类
<? super T> 表示泛型下限,T类型或T的父类
5 Iterator迭代器
hasNext();
next();
remove(); //防止并发操作
6 List接口
List接口的特点:有序的,可以重复
7 ArrayList实现类
存储结构:数组
适合遍历查找
8 LinkedList实现
存储结构:双向链表
适合做添加,删除
9 Vector向量集合 Stack栈 (先进后出) push 入栈 pop 出栈 Queue 队列 offer 入队 pull 出队

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值