JAVAEE第七篇 集合Collection和泛型

学习内容

  • 集合和数组的区别
  • Collection的常用功能
  • 使用迭代器取集合元素
  • 增强型for实现原理和使用
  • 使用泛型定义定义集合对象
  • 泛型的上下限以及写法
  • 泛型通配符的使用
  • 类、方法、参入参数中泛型的使用
  • 数据结构
  • List和Set集合方法

第一节 Collection集合

1.1 集合的概念

集合:集合是JAVA提供的一种容器,用来存储多个数据.
集合和数组的区别:
(1)数组长度是固定不变的,集合是长度可变的
(2)数组中存储的是同一种数据类型,集合中可以存储多种不同的对象.以后的开发中都用集合来存储数据

1.2 集合框架

  • 概述:有多种集合,我们常用地主要有Collection(单列)和Map(双列)集合.
  • Collection集合拓扑图
    在这里插入图片描述
  • Collection介绍
    通过上图可以看出Collection是一个抽象类,定义了一些常用的公用方法,由List和Set接口继承,再由具体的集合类去实现.这样可以利用多态实现常用的方法如添加 查询 删除等方法.

1.3 Collection集合常用方法

  • 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(): 把集合中的元素,存储到数组中。
    代码举例:
   //以ArrayList为例,利用多态性,调用Collection方法
    public static void main(String[] args) {
        Collection<String> collection = new ArrayList<String>();
        collection.add("ad");
        collection.add("cd");
        collection.remove("ad");
        boolean isContains = collection.contains("cd");
        collection.clear();
        int size = collection.size();
        boolean isEmpty = collection.isEmpty();
        Object[] objects = collection.toArray();
    }

第二节 迭代器

2.1 背景

在程序开发中,我们经常需要遍历集合元素,而有的集合是无序的并且没有索引的,这样我们利用一般的for循环是无法遍历的,并且如果各集合都写自己的遍历集合方法,那开发者使用起来也很费劲,由此JAVA定义了规范的遍历集合接口称为迭代器.

2.2 迭代器常用方法:

  • public Boollean hasNext():如果有元素返回True
  • public E next();返回下一个集合元素.

2.3 代码实现

    public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("ab");
        collection.add("cd");
        //得到迭代器对象
        Iterator<String> iterator = collection.iterator();
        //通过迭代器遍历
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

2.4 for循环的增强型

  • 概述:JDK1.5以后用来专门遍历数组和集合的.实现原理其实是调用的上述的迭代器,使用起来比上述简单多了,但是不能进行增删改.因为迭代器实现原理没有索引.
  • 格式:for(集合类型 变量名:集合对象)
  • 代码实现
    public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("ab");
        collection.add("cd");
         //增强型for
        for (String it:collection){
            System.out.println(it);
        }
    

第三节 泛型

3.1 泛型概述

为了解决在未知类型的情况下传入参数的类型问题,例如集合元素可以是任何数据类型,我们可以把数据类型当做参数传进去,这样我们实例化集合的时候,传什么类型进去集合就是什么类型.如果不传类型进行,java则把集合类型当成Object,这样每次必须经过强转.

3.2 泛型的使用

3.2.1 泛型在类中的使用

  • 格式:
    class 类名<泛型的变量> { 
    	...
    }
    
  • 代码举例:
   public static void main(String[] args) {
   		//实例化的时候确定传入类型String
        User<String> user = new User<>();
        String name = "张三";
        user.name = name;
    }   
    //属性name引用T泛型
    public static class User<T>{
       public T name;
    }

3.2.2 泛型在方法中的使用

  • 格式

    修饰符 <泛型的变量> 返回值 方法名(参数){
    }
    
  • 代码举例

    public static void main(String[] args) {
        User user = new User();
        String name = "张三";
        user.show(name);
    }
    
    public static class User{
        //T名可以随意起,多个点话用逗号隔开
        public <T> void show(T name){
            System.out.println("类名:" + name.getClass());
            System.out.println("值:"+name);
        }
    }
    

3.2.3 泛型在接口中的使用

  • 格式
    interface 接口名<泛型名>{
    	....
    }
    
  • 代码实现
    接口代码
public interface FanInteface<V> {
    public <V> void show(V name);
}

  • 接口实现代码1
public class FanImpl<V> implements FanInteface<V> {
    @Override
    public <V> void show(V name) {
        ....
    }
}
  • 接口实现代码2
public class FanImpl implements FanInteface<String> {
    @Override
    public <String> void show(String name) {

    }
}

3.2.4 泛型的通配符

  • 概述:当我们调用泛型类或者泛型接口的时候,我们无法确定传入的类型是什么,可以使用泛型通配符?表示
  • 泛型的上限
    格式: 类型名称 <? extends 类 > 对象名称
    意义: 只能接收该类型及其子类
  • 泛型的下限
    格式: 类型名称 <? super 类 > 对象名称
    意义: 只能接收该类型及其父类型
  • 代码实现
    public static void main(String[] args) {
        ArrayList<Integer> num1 = new ArrayList<>();
        ArrayList<String> num2 = new ArrayList<>();
        num1.add(1);
        num2.add("张三");
        getElement(num1);//运行正常
        getElement(num2);//运行正常
        getElement1(num1);//不符合泛型限定范围 报错 
        getElement2(num1);//运行正常
        getElement2(num2);//报错:不符合泛型限定范围
    }
    //泛型没有限定范围,所有类型都接受.
        public static void getElement(Collection<?> collection){
        System.out.println(collection);
    }
    //必须是Number类型或者Number类型的父类
    public static  void getElement1(Collection<? super Number> collection){
        System.out.println(collection);
    }
    //必须是Number类型或者Number类型的子类
    public static void getElement2(Collection<? extends Number> collection){
        System.out.println(collection);
    }

第四节 数据结构

4.1 结构概述

集合在内存中存储的结构常用的有栈、队列、数组、链表、红黑树.
栈:先进后出
队列:先进先出
数组:长度不可变,地址是连续的,查询快,修改每次都要新增一整块地址,因此修改慢
链表:由一系列点组成,每个点记录着数据和下个地址,地址不是连续的,查找的时候要一个一个找,修改的时候只需要修改数据即可,因此查询慢修改快.
红黑树:二叉树(叶子节点最多有俩个),平横数(左右子树相等),不平衡数(左右子数不相等),红黑树是介于平衡和不平衡数之间的.

第五节 List集合

5.1 List特点

  • 元素有序
  • 带有索引
  • 允许有重复值

5.2 List的常用方法

   public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("ab");//添加
        list.add(1,"cd");
        list.add(2,"ef");
        int cd = list.indexOf("ef");
        System.out.println("索引号:"+cd);
        boolean empty = list.isEmpty();
        System.out.println("集合是否为空:"+empty);
        list.remove(0);//根据索引移除
        String st = list.get(1);//获取索引为1的值
        for (String s : list) {
            System.out.println("遍历集合:" +s);
        }

5.3 List的子类(ArrayList 和LinkedList)

5.3.1 ArrayList 子类

  • 特点:继承List集合的所有方法,原理由数组组成,查询快,增删慢,有索引,可以有重复值,连续.

5.3.2 LinkedList

  • 特点:继承List的所有方法,原理是双向链表形式,查询慢,增删快.双向链表每个子节点除了记录数据值和下一个地址,还记录了上一个地址值.
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("ab");
        linkedList.add(1, "cd");
        linkedList.add(2, "ef");
        linkedList.get(2);//根据索引获取值
        linkedList.addLast("hg");//向尾部添加字符
        linkedList.addFirst("oo");//向首部添加
        linkedList.removeFirst();
        linkedList.removeLast();
        String pop = linkedList.pop();//堆栈弹出一个元素,相当于removeFirst()
        linkedList.push("xx");//将元素推入堆栈,相当于向首部添加元素
        System.out.println(linkedList.getLast());//打印出尾部

        System.out.println("遍历结合------");
        for (String s : linkedList) {
            System.out.println(s);
        }
    }

第六节 Set集合

  • 特点:Set结合元素无序,并且以某种规则保证无重复值

6.1 HashSet集合

  • 概述:根据哈希值来确定存储的位置,保证元素的唯一性.依赖于hashCode和equals方法,可以重写这俩方法
  • 哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的
  • 自定义引用类型HashSet集合的时候,需要我们重写hashcode和equals方法,equals返回的值如果是true,那这两个对象的hash值就相等.
  • 代码举例
public class Student {
    private  String name;
    private  int age;

    public Student(){};
    public Student(String name, int age){
        this.setName(name);
        this.setAge(age);
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o == null || o.getClass() != this.getClass()) {
            return false;
        }
        Student student = (Student) o;
        return (student.getAge() == age && Objects.equals(student.getName(), name));
    }

    //根据姓名和年龄获取哈希值
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

代码实现

    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<>();
        Student stu1 = new Student("张三",10);
        Student stu2 = new Student("李四",20);
        Student stu3 = new Student("张三",10);
        students.add(stu1);
        students.add(stu2);
        students.add(stu3);
        for (Student student : students) {
        	//打印出来的顺序是不一定的
            System.out.println(student.toString());
        }
    }

6.2 LinkedHashSet

  • 概述:相比HashSet而言LinkedHashSet是有顺序的.按照插入的顺序而定

  • 代码演示

     LinkedHashSet<String> str = new LinkedHashSet<>();
     str.add("aaaa");
     str.add("ccc");
     str.add("bbb");
     for (String s : str) {
     	//打印的结果必须 aaa  ccc bbb
         System.out.println(s);
     }
    

    6.3 可变参数

  • 格式 返回值 方法名(参数类型… 参数名){ }

  • int… 和int[] 的区别
    int[]作为参数类型传的时候传入必须是数组类型
    int…作为参数类型的时候可以是多个此类型的数据.

public class demo2 {
    public static void main(String[] args) {
        int sum = sum(10, 10, 20, 30);
        System.out.println("求和的结果"+sum);


    }
  public  static int sum(int... i){
      for (int num : i) {
          return num++;
      }
      return 0;
    }
}
发布了40 篇原创文章 · 获赞 4 · 访问量 6333

猜你喜欢

转载自blog.csdn.net/oFlying1/article/details/104494415