集合1——集合和泛型

集合和泛型


集合Collection

集合由来

​ 开发应用程序时,如果想储存多个同类型的数据,可以使用数组来实现,但是使用数组存在如下一些明显缺陷:

  1. 数组长度固定不变,不能很好地适应元素数量动态变化的情况。

  2. 可通过数组名.length获取数组的长度,却无法直接获取数组中实际储存的元素个数。

  3. 数组采用在内存中分配连续空间的存储方式存储,根据元素信息查找时效率比较低,需要多次比较。

因此,Java提供了比数组更灵活、更实用的集合框架,可大大提高软件的开发效率,并且不同的集合适用于不同的应用场景。

Java集合框架提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中。

集合继承体系

在这里插入图片描述
Collection接口

​ Collection接口是集合中的顶层接口,那么它中定义的所有功能子类都可以使用。查阅API中描述的Collection接口。Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。

创建集合的格式:

Collection 变量名 = new ArrayList();//父类引用指向子类对象

collection接口通用方法

/* 集合中只能存储引用数据类型,不可能存储基本类型,存储的基本类型其实也是自动装箱的
 * Collection接口的通用方法:
 *     boolean add(Object e):将传过来的数据添加集合容器中
 *                           
 *     void clear():清空集合中所有,便于重复利用这个集合                
       boolean isEmpty():判断集合是否为空
       int size():获取集合中存储的元素的个数

       boolean contains(Object o):判断集合中是否包含指定元素,如果包含返回true,如果不包含返回false
       boolean remove(Object o):从集合中删除指定元素,如果删除成功,返回true,如果删除失败返回false
   
   集合相对与数组的优点:我们在使用集合的时候,不用手动指定集合的长度,而数组必须指定长度
 */
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
    public static void main(String[] args) {
        Collection c= new ArrayList();//父接口指向子类对象
        c.add("abc");//Object o="abc",多态的使用方式
        c.add("def");
        System.out.println(c);//[abc, def] 中括号中的数据代表集合中的元素
    }
}
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
    //boolean add(Object o)
    //尝试用add方法存储基本类型
    public static void main(String[] args) {
        Collection c= new ArrayList();//父接口指向子类对象
        c.add(2);//先把2自动装箱-->new Integer(2),然后再把这个Integer对象给了Object o
        //Object o=new Integer(2);//多态
        c.add(2.3);//装箱成new Double(2.3)
        System.out.println(c);//[2,2.3]
    }
}
//clear()方法
public static void main(String[] args) {
    Collection c= new ArrayList();//父接口指向子类对象
    c.add("abc");
    c.add("def");
    System.out.println(c);//[abc, def]
    
    c.clear();
    System.out.println(c);//[]
}
//isEmpty()判断集合是否为空
public static void main(String[] args) {
    Collection c= new ArrayList();
    c.add("abc");
    boolean b=c.isEmpty();
    System.out.println(b);//false
}
//size()获取集合中存储的元素的个数
public static void main(String[] args) {
    Collection c= new ArrayList();
    c.add("abc");
    c.add("def");
    c.add("ghk");
    System.out.println(c);//[abc, def, ghk]
    int i=c.size();//c中有3个元素
    System.out.println(i);//3
}
//contains方法与remove方法()
public static void main(String[] args) {
    Collection c= new ArrayList();
    c.add("令狐冲");
    c.add("岳灵珊");
    boolean b1=c.contains("岳灵珊");
    boolean b2=c.contains("岳不群");
    System.out.println(b1+" "+b2);//true,false


    boolean b3=c.remove("岳灵珊");
    System.out.println(b3);//true
    System.out.println(c);//[令狐冲]

    boolean b4=c.remove("任盈盈");
    System.out.println(b4);//false
    System.out.println(c);//[令狐冲]
}

集合遍历

普通for循环遍历

普通for循环遍历集合的思想和遍历数组的思想相似,但是我们的Collection中并没有提供根据索引获取元素的方法,我们需要去使用子类ArrayList中的get(int index)方法来获取元素

public static void main(String[] args) {
    Collection c = new ArrayList();//ArrayList()集合底层会对元素编号从0开始
    c.add("李雷");//对应0索引
    c.add("韩梅梅");//对应1索引
    c.add("李梅");//对应2索引
    for (int i = 0; i < c.size(); i++) {
        ArrayList al = (ArrayList) c;//强制向下转型,为了使用子类特有方法
        Object obj = al.get(i);//第一次循环:Object obj=al.get(0);//Object obj="李雷"
        //第二次循环:Object obj=al.get(1);//Object obj="韩梅梅"
        //....
        System.out.println(obj);
    }
}

迭代器遍历

interface Collection{
   Iterator<E> iterator();
}

Interface Iterator<E>{
  boolean hasNext();
  E next();
}
	/*1.获取迭代器 
	 *  	c.iterator();
	 *2.利用迭代器的hasNext()方法,判断集合中是否有待取的元素
	 *  如果有,返回true 
	 *3.利用迭代器的next()方法取出当前的元素
	 *4.直到hasNext()返回false,停止遍历*/

在Collection接口描述了一个抽象方法iterator方法,所有Collection子类都实现了这个方法,并且有自己的迭代形式。
在这里插入图片描述
java中提供了很多个集合,它们在存储元素时,采用的存储方式不同。我们要取出这些集合中的元素,可通过一种通用的获取方式来完成。

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

集合中把这种取元素的方式描述在Iterator接口中。Iterator接口的常用方法如下:
在这里插入图片描述

  • hasNext()方法:用来判断集合中是否有下一个元素可以迭代(遍历)。如果返回true,说明可以迭代。

  • next()方法:返回当前遍历到的元素。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*Collection中的获取迭代器方法:
 *     Iterator iterator() 
 *          返回一个迭代器对象,我们利用这个迭代器对象对集合进行遍历  
 *接口Iterator中的方法
 *  boolean hasNext() 
    判断当前遍历的集合中是否还有元素,有返回true,没有返回false    
   Object next() 
              取出当前遍历到的元素           
  void remove() 
    删除当前遍历到的元素
 */
public class Demo {
    public static void main(String[] args) {
        //1.获取集合中的一个迭代器对象
        Collection c = new ArrayList();
        c.add("李雷");
        c.add("韩梅梅");
        c.add("李梅");
        Iterator it = c.iterator();//c.iterator()一定返回Iterator的实现类对象
        //多态思想
        //Calendar c=Calendar.getInstance();//返回是Calendar的子类对象
        //2.利用Iterator中的方法
        boolean b = it.hasNext();//判断当前是否有要遍历的元素,有返回true,没有返回false
        System.out.println(b);
        Object obj = it.next();//取出当前遍历的元素
        System.out.println(obj);//"李雷"

        boolean b2 = it.hasNext();
        System.out.println(b2);
        Object obj2 = it.next();
        System.out.println(obj2);//"韩梅梅"

        boolean b3 = it.hasNext();
        System.out.println(b3);
        Object obj3 = it.next();
        System.out.println(obj3);//"李梅"

        boolean b4 = it.hasNext();
        System.out.println(b4);//false,因为此时已经没有元素可以取
        // Object obj4=it.next();
        // System.out.println(obj4);//java.util.NoSuchElementException
    }
}
public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("李雷");
        c.add("韩梅梅");
        c.add("李梅");
        Iterator it = c.iterator();//c.iterator()一定返回Iterator的实现类对象
        //多态思想
        //Calendar c=Calendar.getInstance();//返回是Calendar的子类对象

        while (it.hasNext()) {//判断是否有元素
            Object obj = it.next();//取出元素
            System.out.println(obj);
        }
    }
并发修改异常
/*
 * 需求:
 *   定义一个集合,往集合中添加三个字符串,遍历集合
 *   如果在遍历过程中发现有"abc",我们就向集合中再添加一个字符串"mm"
 * Exception in thread "main" java.util.ConcurrentModificationException
 * 并发修改异常:
 *   产生原因:在使用迭代器遍历的时候,使用了集合的方法添加/删除 集合中元素
 *   解决方案:使用普通for循环方式遍历集合,再往集合中添加
 */
 //使用迭代器方式遍历
public static void main(String[] args) {
    //1.定义一个集合
    Collection c=new ArrayList();
    //2.往集合中添加三个字符串
    c.add("aa");
    c.add("bc");
    c.add("abc");
    System.out.println(c);
    //3.遍历集合判断集合中是否有abc,如果有我就往集合中添加一个字符串mm
    Iterator it = c.iterator();
    while(it.hasNext()){
        Object obj=it.next();
        if(obj.equals("abc")){
            c.add("mm");
        }
    }

    System.out.println(c);
}

在这里插入图片描述

//使用for循环遍历
public static void main(String[] args) {
    //1.定义一个集合
    Collection c=new ArrayList();
    //2.往集合中添加三个字符串
    c.add("aa");
    c.add("bc");
    c.add("abc");
    System.out.println(c);//[aa, bc, abc]

    //利用for循环遍历
    for(int i=0;i<c.size();i++){
        ArrayList al=(ArrayList)c;//对c进行向下转型
        Object obj=al.get(i);//取出当前元素
        if(obj.equals("abc")){
            c.add("mm");
        }
    }
    System.out.println(c);//[aa, bc, abc, mm]   
} 

增强for循环遍历

JDK1.5新特性:增强for,遍历数组或集合经常使用增强for

/*
 * JDK1.5新特性:
 *   增强for循环
 *   格式:
 *     for(容器中元素类型 变量 : 数组对象或者集合对象){
 *         //通过for上声明的变量取值
 *     }
 *   1.用普通for遍历数组有索引,而用增强for遍历数组没有索引
 *   2.使用增强for遍历集合,需要集合实现或者继承Iterable接口
 *     增强for遍历集合,其实底层使用依然是迭代器
 *   3.增强for可以用快捷键生成  写一个for,alt+/
 */
public static void main(String[] args) {
    Collection c=new ArrayList();
    c.add("abc");//将"abc"以Object类型添加到集合,取出的时候也是Object,类似:Object obj="abc"
    c.add("def");
    for(Object obj : c){
        System.out.println(obj);//第一次循环obj="abc"
        //第二次循环obj="def"
    }
}

泛型

概述

泛型:广泛的引用数据类型

泛型是jdk1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,使代码可以应用于多种类型。简单来说,java语言引入泛型的好处是安全简单,且所有强制类型转换都是自动和隐式进行的,提高了代码的重用率。

把对象的类型作为参数,指定到其它类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛型。泛型的本质就是参数化类型。

语法格式:

类1或者接口<类型实参> 对象 = new 类2<类型实参>();

类上的泛型

泛型的引入

class GenericDemo01 {
	public void method01(Integer i) {
		System.out.println(i);
	}

	public void method02(String s) {
		System.out.println(s);
	}
}

public class Demo01 {
	public static void main(String[] args) {
        GenericDemo01 gd=new GenericDemo01();
        gd.method01(3);
        gd.method02("abc");
	}
}

我们的method01和metho02的方法逻辑完全一样,只不过参数类型不同,而我们却写了2次

因此我们考虑能不能通过一个方法来使用不同的类型,使用泛型

类上泛型的使用

/*类上的泛型:
 *  格式:
 *    class 类名<E,Q,..>{//E,Q泛型变量
 *       //再类中使用这些泛型变量
 *    }
 *  使用:
 *    创建对象的时候需要带上<>,然后在里面传入引用类型
 *    创建对象的时候,泛型变量值确定
 *    再类中用到这个泛型变量的地方都会被替换成传入的类型

 */
class GenericDemo<E>{//E是泛型变量
    //E=String
    public void method(E e){//String e
        System.out.println(e);
    }
}
public class Demo {
    public static void main(String[] args) {
        //由于类上有泛型,因此在创建对象的时候需要带上<>
        GenericDemo<String> gd=new GenericDemo<String>();
        //里面写要传过去的引用类型
        gd.method("abc");

        //由于类上有泛型,因此在创建对象的时候需要带上<>
        GenericDemo<Integer> gd2=new GenericDemo<Integer>();
        gd2.method(3);

    }
}

集合类上使用泛型

ArrayList类上定义的有泛型,并且add方法就使用了ArrayList上的泛型E,因此我们按照泛型的用法使用

/*ArrayList定义:
 * class ArrayList<E>{
 *   boolean add(E e){//使用的E就是ArrayList上的E 
 *   }
 * }
 */
import java.util.ArrayList;
public class Demo {
    public static void main(String[] args) {
        ArrayList<String> al=new ArrayList<String>();
        al.add("abc");//由于创建ArrayList时候我们给泛型变量E传入String类型
        //add方法上的E替换成String
        al.add("def");
        al.add("ghk");
        System.out.println(al);//[abc, def, ghk]

    }
}

方法上的泛型

方法上定义泛型

/*
 * 方法上的泛型:
 *   格式:
 *     class 类名{
 *       修饰符 <T,E,...>返回值类型 方法名(T t,E e,...){
 *       }
 *     }
 *   方法上的泛型,由传入的参数类型决定
 */
class GenericDemo {
    public <T> void method(T t) {// T将来接收引用类型 t变量名
        System.out.println(t);
    }
}

public class Demo {
    public static void main(String[] args) {
        GenericDemo gd=new GenericDemo();
        gd.method("abc");//当传入"abc"的时候,此时T被替换成String
        gd.method(2);//当传入2的时候,此时T被替换成基本类型包装类Integer
    }
}

集合中使用泛型的方法

只要给泛型方法传入什么类型,泛型变量就会被替换为什么类型

/*
 *Collection中的方法使用到泛型:
 *    <T> T[] toArray(T[] a):将集合转换成数组,同时把集合中的元素添加到数组中
 */
import java.util.ArrayList;
import java.util.Collection;
public class Demo {
    public static void main(String[] args) {
        Collection<String> c=new ArrayList<String>();
        c.add("abc");
        c.add("def");

        String[] strArr=new String[c.size()];
        String[] arr=c.toArray(strArr);//当传入一个字符串数组的时候
        //方法变为:<String> String[] toArray(String[] a)
        //返回的数组中装满了集合的元素

        for (String str : arr) {//打印数组的元素
            System.out.println(str);//abc       def
            
        }
    }
}

接口上的泛型

接口上定义泛型

/* 
 * 接口上的泛型定义格式:
 *   interface 接口名<E,Q,T,...>{
 *     //可以在接口中使用泛型变量
 *   }
 */
public interface Father<T>{
   public void method(T t);//使用的是接口上的泛型T
}
  • 接口上的泛型的第一种被确定方式:
/*
 *确定接口上的泛型的第一种方式 
 *  当子类实现接口的时候传入类型,那么会把这个类型代替接口上声明的泛型变量
 *  在接口中用到泛型变量的地方也会替换成该类型
 *  Father<String>->String替换了接口上的T
 *  method方法上的T也被替换成String
 */
public class Son implements Father<String> {
	@Override
	public void method(String t) {
		System.out.println(t);
	}
}
class Demo {
	public static void main(String[] args) {
        Son s=new Son();
        s.method("abc");
	}
}
  • 接口上的泛型第二种被确定方式:
/*
 *确定接口上的泛型的第二种方式  
 *当创建子类对象的时候来确定泛型的值
 * Son2<Integer> s=new Son2<Integer>();
 * 类上声明T会被替换成Integer
 * method方法上的T也会被替换成Integer
 */
public class Son2<T> implements Father<T> {
	public void method(T t) {
		System.out.println(t);
	}
}
class Demo {
	public static void main(String[] args) {
       Son2<Integer> s=new Son2<Integer>();
       s.method(3);
	}
}

迭代器以及增强for使用泛型

我们后期都会采用泛型的写法,无论是接口上的泛型还是类上的泛型

只要被确定了类型,那么所有用到泛型的地方都会被确定为这个类型

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/*
 *1.定义集合的时候使用泛型 
 *2.使用迭代器遍历的时候使用泛型
   interface Collection<E>{
         Iterator<E> iterator()//Iterator<E>中的E用的是Collection上的E
    }
   interface Iterator<E>{
       boolean hasNext() 
         E next()//next()方法上用的E就是Iterator接口上的E
   }
 3.使用增强for遍历也使用泛型
 */
public class Demo {
	public static void main(String[] args) {
		//method01();
		method02();
	}
	public static void method02(){
		//使用泛型定义集合
        Collection<String> c=new ArrayList<String>();
        c.add("乔峰");//只能添加String类型,因为add方法的形参被限定为String
        c.add("慕容复");
        c.add("王语嫣");
        for(String str : c){//增强for底层在遍历集合的时候其实用的还是迭代器
        	System.out.println(str.length());
        } 
	} 
     //使用泛型的迭代器
	public static void method01() {
		//使用泛型定义集合
         Collection<String> c=new ArrayList<String>();
         c.add("乔峰");//只能添加String类型,因为add方法的形参被限定为String
         c.add("慕容复");
         c.add("王语嫣");
         //获取迭代器对象
         Iterator<String> it=c.iterator();
         //使用Iterator中的方法进行遍历
         while(it.hasNext()){
        	 String str=it.next();
        	 System.out.println(str.length());//使用泛型后,避免强转,可以直接使用存入的元素的方法
         }
	}
}
发布了19 篇原创文章 · 获赞 0 · 访问量 1925

猜你喜欢

转载自blog.csdn.net/m0_46183003/article/details/104101900