Java编程笔记 第七章:集合

本文详细介绍了Java编程中的集合概念,包括Collection集合的特性、泛型的使用和好处,以及数据结构栈、队列、数组和链表的基础知识。重点讲解了集合框架,如List接口及其子类ArrayList和LinkedList,以及Set接口中的HashSet和哈希表原理。此外,还涵盖了Iterator接口和增强for循环在遍历集合中的应用。

7.1 Collection集合

7.1.1 集合概述

- 集合:集合是java中提供的一种容器,可以用来存储多个数据。

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

7.1.2 集合框架

Java的集合框架 从整体上可以分为两种:

  1. Collection接口:该接口下的所有子孙均存储的是单一对象
  2. Map接口 :该接口下的所有子孙均存储的是key-value(键值对)形式的数据

另外还有三个分支,均是为上述服务的。
Iterator(迭代器):主要用于遍历Colleciton接口的及其子类而设计。
Comparator(比较器): 在集合中存储对象时候,用于对象之间的比较
Collecitons 是工具类:注意该类名带个s,一般就表示工具类。里面提供了N多静态方法,来对Colleciton集合进行操作。

7.1.3 Collect集合常用功能
  • public boolean remove(E e) 把给定的对象在当前集合中删除
  • public boolean contains(E e) 判断当前集合中是否包含指定对象
  • public boolean isEmpty() 判断当前集合是否为空
  • public int size() 返回集合中元素个数
  • public Object[] toArray() 把集合中的元素存储到数组中
  • public void clear() 清空集合中的元素
/**

 * @author wangquan 1126909120@qq.com
 * @create 2019/3/10 9:58
 * @since JDK8u191
 */
public class CollectionTest {
    public static void main(String[] args) {
        Collection<String> s = new ArrayList<>();
        System.out.println(s);
        //public boolean add(E e)给指定的对象添加到元素中
        boolean b1 = s.add("张三");
        boolean b2 = s.add("李四");
        boolean b3 = s.add("王五");
        boolean b4 = s.add("赵六");
        boolean b5 = s.add("田七");
        System.out.println(s);

        //public boolean remove(E e)把给定的对象在当前集合中删除
        boolean b6 = s.remove("田七");
        System.out.println(s);

        //public boolean contains(E e)判断当前集合中是否包含指定对象
        boolean b7 = s.contains("田六");
        System.out.println(b7);

        //public boolean isEmpty()判断当前集合是否为空
        boolean b8 = s.isEmpty();
        System.out.println(b8);

        //public int size()返回集合中元素个数
        int b9 = s.size();
        System.out.println(b9);

        //public Object[] toArray()把集合中的元素存储到数组中
        Object[] b10 = s.toArray();
        for (int i = 0; i < b10.length; i++) {
            System.out.println(b10[i]);
        }

        //public void clear()清空集合中的元素
        s.clear();
        System.out.println(s);
    }
}
7.1.4 Iterator接口

如果需要遍历集合中的所有元素。需要使用到接口java.util.Iterator。Iterator接口也是Java集合中的一员,但它与Collection、Map接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,所以Iterator对象也被称为迭代器。

Iterator接口的常用方法如下:

  • public E next():返回迭代的下一个元素。
  • public boolean hasNext():如果仍有元素可以迭代,则返回 true。
/**
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/10 10:20
 * @since JDK8u191
 */
public class IteratorTest {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();
        coll.add("迪丽热巴");
        coll.add("古力娜扎");
        coll.add("马儿扎哈");
        coll.add("赵丽颖");
        coll.add("刘亦菲");
        
//使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
        Iterator<String> it = coll.iterator();
        
//        boolean b = it.hasNext();
//        String s = it.next();
//        System.out.println(s);

//使用while循环遍历更方便
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
}
7.1.5 增强for循环
  • 增强for循环(也称for each循环)是JDK1.5以后出来的高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

格式:

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

代码实现:

**
 * 增强for循环
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/10 10:53
 * @since JDK8u191
 */
public class ForeachTest {
    public static void main(String[] args) {
        demo01();
        demo02();
    }


    private static void demo01() {
        int[] array = {1, 2, 3, 4, 5};
        for (int a : array) {
            System.out.println(a);
        }
    }

    private static void demo02() {
        ArrayList<String> arr = new ArrayList<>();
        arr.add("aaa");
        arr.add("bbb");
        arr.add("ccc");
        for (String i :
                arr) {
            System.out.println(i);
        }
    }
}

7.2 泛型

7.2.1 泛型的概念

泛型:是一种未知的数据类型,当我们不知道用什么数据类型的时候,可以使用泛型。泛型也可以看成是一个变量,可以接收所有的数据类型

E e : Element元素
T t : Type类型

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

public class Generic<E> {
    private E name;

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }
}
7.2.2 使用泛型的好处
  1. 运行时期的ClassCastException,转移到了编译时期变成了编译失败。
  2. 避免了类型强转的麻烦。
    例如:
public class GenericDemo2 {
	public static void main(String[] args) {
        Collection<String> list = new ArrayList<String>();
        list.add("abc");
        list.add("itcast");
        // list.add(5);//当集合明确类型后,存放类型不一致就会编译报错
        // 集合已经明确具体存放的元素类型,那么在使用迭代器的时候,迭代器也同样会知道具体遍历元素类型
        //使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String str = it.next();
            //当使用Iterator<String>控制元素类型后,就不需要强转了。获取到的元素直接就是String类型
            System.out.println(str.length());
        }
	}
}
7.2.3 定义和使用含有泛型的类

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

 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 19:07
 * @since JDK8u191
 */
public class MyGenericClass<MVP> {
	//没有MVP类型,在这里代表 未知的一种数据类型 未来传递什么就是什么类型
	private MVP mvp;
     
    public void setMVP(MVP mvp) {
        this.mvp = mvp;
    }
     
    public MVP getMVP() {
        return mvp;
    }
}

class GenericClassDemo {
  	public static void main(String[] args) {		 
         // 创建一个泛型为String的类
         MyGenericClass<String> my = new MyGenericClass<String>();    	
         // 调用setMVP
         my.setMVP("大胡子登登");
         // 调用getMVP
         String mvp = my.getMVP();
         System.out.println(mvp);
         //创建一个泛型为Integer的类
         MyGenericClass<Integer> my2 = new MyGenericClass<Integer>(); 
         my2.setMVP(123);   	  
         Integer mvp2 = my2.getMVP();
    }
}
7.2.4 定义和使用含有泛型的方法

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

 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 19:07
 * @since JDK8u191
 */
public class MyGenericMethod {	  
    public <MVP> void show(MVP mvp) {
    	System.out.println(mvp.getClass());
    }
    
    public <MVP> MVP show2(MVP mvp) {	
    	return mvp;
    }
}
//调用方法时,确定泛型的类型
class GenericMethodDemo {
    public static void main(String[] args) {
        // 创建对象
        MyGenericMethod mm = new MyGenericMethod();
        // 演示看方法提示
        mm.show("aaa");
        mm.show(123);
        mm.show(12.45);
    }
}
7.2.5 定义和使用含有泛型的接口

定义格式:
修饰符 interface接口名<代表泛型的变量> {
}

 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 19:07
 * @since JDK8u191
 */
public interface MyGenericInterface<E>{
	public abstract void add(E e);
	
	public abstract E getE();  
}
//使用格式
class MyImp1 implements MyGenericInterface<String> {
	@Override
    public void add(String e) {
        // 省略...
    }

	@Override
	public String getE() {
		return null;
	}
}
7.2.6 泛型通配符

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

  • 通配符基本使用

泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。

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

/**
 * 泛型通配符
 *
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 19:07
 * @since JDK8u191
 */
public class GenericTest {
    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<Integer>();
        getElement(list1);
        Collection<String> list2 = new ArrayList<String>();
        getElement(list2);
    }

    //?代表可以接收任意类型
    public static void getElement(Collection<?> coll) {
    }
}
通配符的高级使用—受限泛型

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

  • 格式: 类型名称 <? extends 类 > 对象名称
  • 意义: 只能接收该类型及其子类

泛型的下限:

  • 格式: 类型名称 <? super 类 > 对象名称
  • 意义: 只能接收该类型及其父类型
    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>();

        getElement(list1);
        getElement(list2);//报错
        getElement(list3);
        getElement(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) {
    }

7.3 数据结构

7.3.1 数据结构 栈

栈:stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。
简单的说:采用该结构的集合,对元素的存取有如下的特点:

  • 栈的存储顺序是先进后出,栈的入口和出口都在集合的同一侧
  • 先进后出:存进去的元素,要在后它后面的元素依次取出后,才能取出该元素
    压栈就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
    弹栈就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置
7.3.2 数据结构 队列
  • 队列的存储顺序是先进先出
  • 队列的入口和出口在集合的两侧,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素
7.3.3 数据结构 数组

数组特点:

  • 查询快:通过索引,可以快速访问指定位置的元素
  • 增删慢
  1. 指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置
  2. 指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中
7.3.4 数据结构 链表

链表特点:

  • 查询慢:链表中的地址不是连续的,每次查询元素,都必须从头开始查询
  • 增删块:链表结构,增加/删除一个元素,对链表的整体结构没有影响,所以增删块
    链表中的每一个元素也称之为一个节点,一个节点包含了一个数据源(存储数组),两个指针域(存储地址)
    单向链表:链表中只有一条链子,不能保证元素的顺序(存储元素和取出元素的顺序可能不一致)
    双向链表:链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合
7.3.5 数据结构 红黑树

7.4 List集合

7.4.1 List集合

List接口特点:

  1. 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
  2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
  3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
    List接口中带索引的方法(特有)
  • public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
  • public E get(int index) :返回集合中指定位置的元素。
  • public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
  • public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素
package cn.itcast.day12;

import java.util.ArrayList;
import java.util.List;

/**
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 20:07
 * @since JDK8u191
 */
public class ListTest {
    public static void main(String[] args) {
        //创建一个List集合对象,多态
        List<String> list = new ArrayList<>();
        //使用add方法往集合中添加元素
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("a");
        //打印集合
        System.out.println(list);//[a, b, c, d, a]

        //public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
        //在c和d中添加一个wangquan
        list.add(3, "wangquan");
        System.out.println(list);
        
        // String remove(int index) 删除指定位置元素 返回被删除元素
        // 删除索引位置为2的元素
        System.out.println("删除索引位置为2的元素");
        System.out.println(list.remove(2));
        System.out.println(list);
        // String set(int index,String s)
        
        // 在指定位置 进行 元素替代(改)
        // 修改指定位置元素
        list.set(0, "王权");
        System.out.println(list);
        
        // String get(int index) 获取指定位置元素
        // 跟size() 方法一起用 来 遍历的
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
         //还可以使用增强for
        for (String string : list) {
            System.out.println(string);
        }
    }
}
7.4.2 List的子类
ArrayList集合

java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为
查询数据、遍历数据,所以 ArrayList 是最常用的集合

LinkedList 集合

java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合
LinkedList是一个双向链表
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方
法我们作为了解即可:

  • public void addFirst(E e) :将指定元素插入此列表的开头。
  • public void addLast(E e) :将指定元素添加到此列表的结尾。
  • public E getFirst() :返回此列表的第一个元素。
  • public E getLast() :返回此列表的最后一个元素。
  • public E removeFirst() :移除并返回此列表的第一个元素。
  • public E removeLast() :移除并返回此列表的最后一个元素。
  • public E pop() :从此列表所表示的堆栈处弹出一个元素。
  • public void push(E e) :将元素推入此列表所表示的堆栈。
  • public boolean isEmpty() :如果列表不包含元素,则返回true。
import java.util.LinkedList;

/**
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 20:26
 * @since JDK8u191
 */
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<String> link = new LinkedList<String>();
        //添加元素
        link.addFirst("abc1");
        link.addFirst("abc2");
        link.addFirst("abc3");
        System.out.println(link);
        // 获取元素
        System.out.println(link.getFirst());
        System.out.println(link.getLast());
        // 删除元素
        System.out.println(link.removeFirst());
        System.out.println(link.removeLast());
        //判断集合是否为空
        while (!link.isEmpty()) {
            //弹出集合中的栈顶元素
            System.out.println(link.pop());
        }
        System.out.println(link);
    }
}

7.5 Set集合

java.util.Set接口 extends Collection接口
Set接口的特点:

  1. 不允许存储重复的元素
  2. 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
7.5.1 Hash集合

HashSet集合 implements Set接口
HashSet特点:

  1. 不允许存储重复的元素
  2. 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
  3. 是一个无序集合,存储元素和取出元素的顺序可能不一致
  4. 底层是一个哈希表结构(查询速度非常快)
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 20:58
 * @since JDK8u191
 */
public class HashSetTest {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        //使用add方法往集合中添加元素
        set.add(1);
        set.add(3);
        set.add(2);
        set.add(4);
        set.add(2);
        //使用迭代器遍历Set集合
        Iterator<Integer> it = set.iterator();
        while (it.hasNext()){
            Integer n = it.next();
            System.out.println(n);//1 2 3 4
        }
    }
}
7.5.2 哈希表
  • 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来的额地址,不是数据实际存储的物理地址)
  • 在Object类有一个方法 可以获得对象的哈希值:
    int hashCode() 返回对象的哈希值
    使用hashCode()方法获取哈希值:
/**
 * @author wangquan 1126909120@qq.com
 * @create 2019/3/12 21:15
 * @since JDK8u191
 */
public class HashCodeTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        //获取对象p的哈希值
        int h1 = p1.hashCode();
        Person p2= new Person();
        int h2 = p2.hashCode();
        //打印输出
        System.out.println(h1);//460141958
        System.out.println(h2);//1163157884

        System.out.println(p1);//cn.itcast.day12.Person@1b6d3586
        System.out.println(p2);//cn.itcast.day12.Person@4554617c
        System.out.println(p1==p2);//false

        //String类的哈希值
        //String类重写Object类的hashCode方法
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.hashCode());//96354
        System.out.println(s2.hashCode());//96354

        //重地和通话的hashCode值是一样的
        System.out.println("重地".hashCode());
        System.out.println("通话".hashCode());
    }
}

class Person{

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值