java之Collection集合框架、包含的通用方法,Iterator接口迭代器,增强for循环(for-each语法),泛型

目录

Collection集合

概述

集合框架介绍

Collection的通用方法

Iterator迭代器

Iterator接口概述

迭代器的使用步骤(重点)

增强for循环(for-each循环JDK1.5+)

泛型

概述:

泛型在不同场合的利弊

泛型的定义和使用(类、方法、接口)

泛型通配符


Collection集合

概述

集合:集合是Java中提供的一种容器,可以用来存储多个数据。前面讲过的ArrayList就是属于集合的一种。

集合和数组的区别:

1.数组的长度是固定的,集合的长度是可变的。

2.数组中存储的是同一类型的元素,可以存储基本数据类型值和对象。集合存储的不能是基本数据类型,都是对象。而且对象类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

// 数组
int[] list1 = new int[10]; // 存储基本类型数据
Student[] list2 = new Student[10]; // 存储对象
// 集合
ArrayList<Student> list3 = new ArrayList<>(); // 只能存储对象
ArrayList<Double> list4 = new ArrayList<>();  // 只能使用基本数据类型的泛型
ArrayList<Student><String><Integer> list3 = new ArrayList<>(); // 可以存储多个不同对象

集合框架介绍

集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection和双列集合java.util.Map.

下面主要介绍的是Collection集合。 

 

List集合和Set集合在另外一篇介绍

Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是java.util.List和java.util.Set。

学习集合的目标:

1.会使用集合存储数据。

2.会遍历集合,把数据取出来。

3.掌握每种集合的特性。

集合框架的学习方式:

1.学习顶层:学习顶层接口/抽象类中共性的方法,所有子类都能使用。

2.使用底层:顶层不是接口就是抽象类,无法创建对象使用,需要使用底层的子类创建对象使用。

List接口特点:

1.有序的集合(存取和取出元素顺序相同)。

2.允许存储重复的元素。

3.有索引,可以使用普通的for循环 遍历。

Set接口特点:

1.不允许存储重复元素。

2.没有索引,不能使用循环遍历。

3.1无序的集合(存储和取出元素的顺序有可能不一致)(HashSet和TreeSet)

3.2有序的集合(LinkedHashSet)

List的接口实现类有:java.util.ArrayList、java.util.LinkedList、java.util.Vector

Set的接口实现类有:java.util.HashSet、java.util.TreeSet、java.util.LinkedHashSet

Collection的通用方法

因为是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法 。

  • public boolean add(E e): 把给定的对象添加到当前集合中 。

  • public void clear() :清空集合中所有的元素。

  • public boolean remove(E e): 把给定的对象在当前集合中删除。

  • public boolean contains(E e): 判断当前集合中是否包含给定的对象。

  • public boolean isEmpty(): 判断当前集合是否为空。

  • public int size(): 返回集合中元素的个数。

  • public Object[] toArray(): 把集合中的元素,存储到数组中。

import java.util.ArrayList;
import java.util.Collection;

public class Demo1Collection {
    public static void main(String[] args) {
		// 创建集合对象 
    	// 使用多态形式
    	Collection<String> coll = new ArrayList<String>();
    	// 使用方法
    	// 添加功能  boolean  add(String s)
    	coll.add("小李广");
    	coll.add("扫地僧");
    	coll.add("石破天");
    	System.out.println(coll);

    	// boolean contains(E e) 判断o是否在集合中存在
    	System.out.println("判断  扫地僧 是否在集合中"+coll.contains("扫地僧"));

    	//boolean remove(E e) 删除在集合中的o元素
    	System.out.println("删除石破天:"+coll.remove("石破天"));
    	System.out.println("操作之后集合中元素:"+coll);
    	
    	// size() 集合中有几个元素
		System.out.println("集合中有"+coll.size()+"个元素");

		// Object[] toArray()转换成一个Object数组
    	Object[] objects = coll.toArray();
    	// 遍历数组
    	for (int i = 0; i < objects.length; i++) {
			System.out.println(objects[i]);
		}

		// void  clear() 清空集合
		coll.clear();
		System.out.println("集合中内容为:"+coll);
		// boolean  isEmpty()  判断是否为空
		System.out.println(coll.isEmpty());  	
	}
}

Iterator迭代器

Iterator接口概述

定义:在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.IteratorIterator接口也是Java集合中的一员,但它与CollectionMap接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

Iterator接口的常用2个方法:

  • public E next():返回迭代的下一个元素。

  • public boolean hasNext():如果仍有元素可以迭代,则返回 true。

Iterator迭代器是一个接口。我们无法直接使用需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊。Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象。

Iterator<E>  iterator() 返回在此collection的元素上进行迭代的迭代器。

迭代器的使用步骤(重点)

1.使用集合中的方法 iterator() 获取迭代器的实现类对象,使用Iterator接口接收(多态)

备注:Iterator<E>接口也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型

2.使用Iterator接口中的方法hasNext判断还有没有下一个元素。

3.使用Iterator接口中的方法next取出集合中的下一个元素。

import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
public class UsingIterator {
    public static void main(String[] args) {
        // 创建一个集合,多态
        Collection<String> coll = new ArrayList<>();
        // 往集合中添加元素
        coll.add("虞姬");
        coll.add("杨玉环");
        coll.add("貂蝉");
        coll.add("王昭君");
        // 迭代器使用步骤如下:
        // 步骤一
        // 多态  接口 对象名 = 实现类对象
        Iterator<String> it = coll.iterator();
        // 步骤二。使用Iterator接口中的方法hasNext判断有没有下一个元素
        boolean flag = it.hasNext();
        System.out.println(flag);
        // 步骤三。使用Iterator接口中的方法next取出集合中的下一个元素
        String a = it.next();
        System.out.println(a);
        // 使用循环来解和这两个方法(分别使用while循环和for循环)
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("++++++++++++++++++++++++++++++++++++++");
        for(Iterator<String> iterator = coll.iterator();iterator.hasNext();/*省略了步进表达式*/){
            String s = iterator.next();
            System.out.println(s);
        }
    }
}

迭代器的实现原理:

增强for循环(for-each循环JDK1.5+)

增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的

它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作

格式:

for(元素的数据类型  变量 :Collection集合or数组){
      //写操作代码
}

注意:

1.它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

2. 新for循环(增强for循环)必须有被遍历的目标。目标只能是Collection或者是数组。新for循环仅仅作为遍历操作出现。

遍历数组:

public class NBForDemo1 {
    public static void main(String[] args) {
		int[] arr = {3,5,6,87};
       	//使用增强for遍历数组
		for(int i : arr){//a代表数组中的每个元素
			System.out.println(i);
		}
	}
}

遍历集合:

public class NBFor {
    public static void main(String[] args) {        
    	Collection<String> coll = new ArrayList<String>();
    	coll.add("小河神");
    	coll.add("老河神");
    	coll.add("神婆");
    	//使用增强for遍历
    	for(String s :coll){//接收变量s代表 代表被遍历到的集合元素
    		System.out.println(s);
    	}
	}
}

泛型

概述:

泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。

泛型也可以看成是一个变量,用来接收数据类型。

E:未知类型, e:Element元素

T:未知类型,  t:Type类型

举例:ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型。

JDK1.7版本之前,创建集合对象/数组时必须把前后的泛型都写上

ArrayList<String> list01 = new ArrayList<String>();

JDK1.7版本之后,等号(=)后面的泛型可以省略,因为后面的泛型可以根据前面的泛型推导出来

ArrayList<String> list02 = new ArrayList<>();

泛型在不同场合的利弊

创建集合对象,不使用泛型的利弊:

优点:稽核部使用泛型,默认类型就是Object类型,可以存储任意类型的数据。

缺点:不安全,会引发异常。

import java.util.ArrayList;
import java.util.Iterator;
public class show0 {
    public static void main(String[] args) {
        // 创建集合,不使用泛型<E>
        ArrayList list = new ArrayList();
        list.add("迪丽热巴"); // 存储字符串类型元素
        list.add(1); // 存储int类型元素
        // 使用迭代器遍历list集合
        Iterator it = list.iterator();
        while(it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
            // 要想使用String类特有的方法length获取字符串长度,不能使用。因为obj是多态。所以需要向下转型
            String s = (String)obj;
            // 会抛出ClassCastException类型转换异常,不能把Integer类型转换成String类型。
            System.out.println(s.length());
        }
    }
}

创建集合,使用泛型的利弊:

优点:

1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型。

2.把运行期异常(代码运行之后会抛出的异常),提升到了编译期(写代码的时候会报错)。

缺点:泛型是什么类型,只能存储什么类型的数据。

泛型的定义和使用(类、方法、接口)

泛型,用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。

定义和使用含有泛型的类

泛型类的定义格式:

修饰符 class 类名 <代表泛型的变量> {

        // ...

}

注意:泛型定义在类名后面。在创建对象的时候确定泛型的数据类型,没有指定那么默认是Object类型。

// 定义含泛型的类
public class GenericClass<E>{
    private E name;
    public E getName() {
        return name;
    }
    public void setName(E name) {
        this.name = name;
    }
}
// 创建对象的时候指定泛型的数据类型
public class GenericClassTest {
    public static void main(String[] args) {
        // 不写泛型,默认为Object类型
        GenericClass gc1 = new GenericClass();
        gc1.setName("迪丽热巴");
        Object s1 = gc1.getName();
        System.out.println(s1);
        // 泛型使用String类型
        GenericClass<String> gc2 = new GenericClass<>();
        gc2.setName("古力娜扎");
        String s2 = gc2.getName();
        System.out.println(s2);
        // 泛型使用Integer类型
        GenericClass<Integer> gc3 = new GenericClass<>();
        gc3.setName(100);
        int s3 = gc3.getName();
        System.out.println(s3);
    }
}

定义和使用含有泛型的方法

泛型方法的定义格式:

修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ 

   // 方法体

}

注意:泛型定义在方法的修饰符和返回值类型之间。在调用方法的时候确定泛型的数据类型。传递什么类型的参数,泛型就是什么类型。

// 定义含有泛型的方法
public class GenericMethod {
    public <M> void method1(M a){
        System.out.println(a);
    }
    public static <S> void method2(S b){
        System.out.println(b);
    }
}
// 使用泛型方法
public class GenericMethodTest {
    public static void main(String[] args) {
        GenericMethod gm = new GenericMethod();
        gm.method1(1);
        gm.method1("迪丽热巴");
        gm.method1(1.9);
        gm.method1(false);
        gm.method2("静态方法不建议创建对象使用");
        GenericMethod.method2("静态方法建议使用类调用!");
        GenericMethod.method2(100);
    }
}

定义和使用含有泛型的接口

泛型接口的定义格式:

修饰符 interface  接口名<代表泛型的变量>

   // .....

}

注意:泛型定义在接口名后面。在创建对象的时候确定泛型的数据类型,没有指定那么默认是Object类型。

泛型接口有两种使用方式:

1.定义实现类时就确定泛型的类型。修饰符 class 实现类名称 implements 接口名称<指定泛型类型>{ ... }

2.定义是实现类时也不确定泛型的类型,直到创建对象时,确定泛型的类型。修饰符 class 实现类名称<代表泛型的变量> implements 接口名称<代表泛型的变量>{  ...  }

// 定义含有泛型的接口
public interface MyGenericInterface<E>{
	public abstract void add(E e);
	
	public abstract E getE();  
}
// 第一种使用方法
public class MyImp1 implements MyGenericInterface<String> {
	@Override
    public void add(String e) {
        // 省略...
    }

	@Override
	public String getE() {
		return null;
	}
}
// 第二种使用方法
public class MyImp2<E> implements MyGenericInterface<E> {
	@Override
	public void add(E e) {
       	 // 省略...
	}

	@Override
	public E getE() {
		return null;
	}
}
// 两种方法的实际使用
public class GenericInterface {
    public static void main(String[] args) {
        MyImp1 my1 = new MyImp1();  // 直接创建对象,和以前一样  
        my1.add("迪丽热巴");
        MyImp2<String>  my2 = new MyImp2<String>(); // 不能直接创建对象,而是需要为泛型指定类型。
        my2.add("古力娜扎");
    }
}

泛型通配符

当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。

通配符的基本使用:

不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符,代表任意的数据类型。

使用方式:不能创建对象使用,只能作为方法的参数使用。

import java.util.ArrayList;
import java.util.Iterator;
public class Generic{
    public static void main(String[] args){

        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);

        ArrayList<String> list2 = new ArrayList<>();
        list2.add("a");
        list2.add("b");      
        // 使用通配泛型定义的方法
        printArray(list1); //传入的可以是Integer类型
        printArray(list2); // 传入的也可以是String类型 
    }    
    /*
      定义一个方法,能便利所有类型的Arraylist集合。
      这时候我们不知道ArrayList集合使用什么数据类型,可以使用通配符?来接收数据。  
      注意:泛型没有继承的概念
    */
    public static void printArray(ArrayList<?> list){
        // 使用迭代器遍历集合
        Iterator<?> it = list.iterator();
        while(it.hasNext()){
            // it.next()方法取出的元素是Object,可以接收任意的数据类型
            Object o = it.next();
            System.out.println(o); 
        }
        System.out.println("====================================");
        // 使用增强型for循环,未知通配符不能作为数据类型,编译报错。
     /*   for(<?> i : list){
            System.out.println(i);
          }
     */ 
    }   
}

 注意:

1.泛型不存在继承关系 Collection<Object> list = new ArrayList<String>();这种是错误的。 Object类型不可以接收String类型(因为没有继承的概念)

2.增强型for循环不能使用通配符作为数据类型,编译报错!

通配符的高级使用:

之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限下限

泛型的上限

  • 格式类型名称 <? extends E > 对象名称

  • 意义只能接收E类型本身及其子类

泛型的下限

  • 格式类型名称 <? super E > 对象名称

  • 意义只能接收E类型本身及其父类

// 比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement1(list1);
    getElement1(list2);//报错
    getElement1(list3);
    getElement1(list4);//报错
  
    getElement2(list1);//报错
    getElement2(list2);//报错
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值