Java集合框架及背后的数据结构

Java集合框架简介

什么是集合?
集合是用来存放数据对象引用的容器,是对数组在功能上的扩展。

如果需要存放基本数据类型的数据,则需要使用包装类,基本类型可以自动转换为包装类型

java.util包下的集合框架主要有几个接口和实现类组成。
Java集合框架及背后的数据结构_第1张图片
Java集合框架及背后的数据结构_第2张图片

Iterator接口
Iterator接口,这是一个用于遍历集合中元素的接口,主要包含hashNext(),next(),remove()三种方法。它的一个子接口LinkedIterator在它的基础上又添加了三种方法,分别是add(),previous(),hasPrevious()。也就是说如果是先Iterator接口,那么在遍历集合中元素的时候,只能往后遍历,被遍历后的元素不会再遍历到,通常无序继续实现的都是这个接口,比如HashSet,HashMap;而那些元素有序的集合,实现的一般都是LinkedIterator接口,实现这个接口可以双向遍历,既可以通过next()访问下一个元素,又可以通过previous()访问前一个元素,比如ArrayList。

Collection是一个接口

Collection常用方法

方法 说明
boolean add(E e) 将元素e放入集合中
void clear() 删除集合中的所有元素
boolean isEmpty() 判断集合是否没有任何元素,俗称空集合
boolean remove(object e) 如果元素e出现在集合中,删除其中一个
int size() 返回集合中的元素个数
object[ ] toArray() 返回一个装有所有集合中元素的数组
public static void main(String[] args) {
        // 集合里面放存放数据类型的包装类,一定不能是简单类型 后面的<>里面的类型可以省略
        // 使用Collection 发生了向上转型
        Collection<Integer> collation = new ArrayList<>();
        // 此时相当于有了一个顺序表
        collation.add(1);
        collation.add(2);
        // 能打印出来 可能是ArrayList 或者它的父类重写了toString方法
        System.out.println(collation);

        // java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
        // 问题:数组不能整体进行强制类型转换
        Object[] array = collation.toArray();
        System.out.println(Arrays.toString(array));

    }
/**
[1, 2]
[1, 2]
*/

泛型

  • 泛型就是编写模板代码来适应任意类型;(泛型就是将类型参数化,给类或者方法传类型)

  • 泛型的好处是使用时不必对类型进行强制转换,它通过编译器对类型进行检查;

  • 注意泛型的继承关系:可以把ArrayList向上转型为List(T不能变!),但不能把ArrayList向上转型为ArrayList(T不能变成父类)。

      * 问题:如何实现一个通用顺序表?
      *  1. : 代表当前类是一个泛型类。
      *  2. new T[10]:(×)  不能new泛型类型的数组 T[] t = new T[];
      *
      * 泛型的意义:
      *  1.在存储元素的时候,可以自动进行类型检查
      *  2.在获取元素的时候,可以进行自动类型的转换
      *  3.泛型类型的参数,不可以是简单参数
      *  4.泛型类型的参数,是不参与类型的组成的
      *
      * 面试问题:
      *      泛型是怎么编译的?
      *          1.泛型只在编译的时候起作用,在运行的时候,是没有泛型的概念的!
      *          2.泛型的编译使用的是擦除机制 -> 把类型擦除成 Object -> 不严谨,可以设置擦除边界
    

基本数据类型与包装类的对应关系

基本数据类型 包装类
byte Byte
short Short
int Interger
long Long
float Float
double Double
char Character
boolean Boolean

包装类有三个作用 一个实现基本类型之间的转换 ,二是便于函数传值 ,三就是在一些地方要用到Object的时候方便将基本数据类型装换。

  • long和double都占了64位(64bit)的存储空间
  • 默认的浮点数据类型是double,如果要指明使用float,则需要在后面加f
  • 基本数据类型是没有静态方法的,但是基本数据类型的包装类却有

包装类的使用:装箱和拆箱

装箱/装包 就是把简单数据类型转变成包装类型
装箱又分为自动装箱和手动装箱

// 装箱
        int i = 10;
        Integer j = i;  //自动装箱
        Integer j2 = Integer.valueOf(i);
        System.out.println(j);
        System.out.println(j2);

        // 拆箱
        Integer a = 20;
        int b = a; // 自动拆箱
        int b2 = a.intValue();      // ×××Value()
        System.out.println(b);
		
		Integer x1 = -129;
        Integer x2 = -129;
        // true 的范围为 -128 ~ 127
        System.out.println(x1==x2);

列表(List):有序存放,允许重复,可以存放不同类型的对象。
List继承了Collection接口:元素有序(有序或无序是指是否按照其添加的顺序来存储对象),可重复,并引入位置下标

方法 说明
boolean add(E e) 尾插e
void add(int index,E element) 将e插入到index位置
boolean addAll(Collection c) 尾插c中的元素
E remove(int index) 删除index位置元素
boolean remove(Object o) 删除遇到的第一个o
E get(int index) 获取下标index位置元素
E set(int index,E element) 将下标index位置元素设置为element
void clear() 清空
boolean contains(Object o) 判断o是否在线性表中
int indexOf(Object o) 返回第一个o所在下标
int lastIndexOf(Object o) 返回最后一个o的下标
List subList(int fromIndex,int toIndex) 截取部分list
public static void main(String[] args) {
        List<Integer> list = new ArrayList();
        list.add(10);
    }

底层源码
在这里插入图片描述
在这里插入图片描述
数组的初始长度为0。
在这里插入图片描述

  • ArrayList里add函数的源码

Java集合框架及背后的数据结构_第3张图片
此时 elementDat[size++]=e 代码运行的结果相当于:

elementData[size] = 10;
size++;

在这里插入图片描述

Java集合框架及背后的数据结构_第4张图片
Java集合框架及背后的数据结构_第5张图片
扩容函数:grow() 1.5倍扩容
Java集合框架及背后的数据结构_第6张图片

  • ArrayList中 void add(int index,E element) 底层源码

调用arraycopy库函数一段一段拷贝。Java集合框架及背后的数据结构_第7张图片

public static void main(String[] args) {
        List<Integer> list = new ArrayList();
        list.add(10);
        list.add(1,10);
        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.add(4);
        list.addAll(list2);

        System.out.println(list);   // [10, 10, 1, 2, 3, 4]

        //迭代器  就是用来遍历集合中的元素的
        // 只有实现了iterable接口的类才能用iterable来打印  Map就不行
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

        for (Integer e:list) {
            System.out.println(e);
        }
    }
public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list);   // [1, 2, 3]

        int index = list.remove(2);  // 3
        System.out.println(index);
        System.out.println(list);   // [1, 2]

        //get返回的是对象
        boolean flg = list.remove(list.get(1));
        System.out.println(list);       // [1]

        list.set(0,100);
        // list.set(1,200);             下标没有数据的地方不能修改元素
        System.out.println(list);       // [100]

        //list.clear();
        //System.out.println(list);       // []

        boolean flg2 = list.contains(100);
        System.out.println(flg2);       // true
    }
public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(4);
        list.add(4);
        System.out.println(list.indexOf(2));    // 1
        System.out.println(list.lastIndexOf(4));    // 6

        List<Integer> elist = list.subList(1,3);
        elist.set(1,11);
        // subList截取出来的还是原来的数组
        System.out.println(elist);  // [2, 11]
        System.out.println(list);   // [1, 2, 11, 4]
    }

LinkedList

构造方法

方法 说明
ArrayList() 无参数构造
ArrayList(int initialCapacity) 指定顺序表初始容量
ArrayList(Collection c) 利用其他Collection构建ArrayList
ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>(30);
        ArrayList<Integer> list3  = new ArrayList<>(list2);
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.lang.*;
/*有若干学生(学生对象放在一个List中),每个学生有一个姓名(String),班级(String)和考试成绩属性(double)
某次考试结束后,每个学生都获得了一个考试成绩。遍历list集合,并把学会对象的属性打印出来。
* */

/**
 * 有一个List当中存放的是整形的数据,要求使用Collections.sort对List进行排序
 * */
class Student implements Comparable<Student>{

    private String name;
    private String className;
    private int sorce;

    public Student(String name, String className, int sorce) {
        this.name = name;
        this.className = className;
        this.sorce = sorce;
    }

    public String getName() {
        return name;
    }

    public String getClassName() {
        return className;
    }

    public double getSorce() {
        return sorce;
    }

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

    public void setClassName(String className) {
        this.className = className;
    }

    public void setSorce(int sorce) {
        this.sorce = sorce;
    }

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

    @Override
    public int compareTo(Student o) {
        return this.sorce-o.sorce;
    }
}

public class TestDemo9 {
    public static void main(String[] args) {
        // 自定义类型也能放到list中
        List<Student> list = new ArrayList<>();
        list.add(new Student("张三","一班",95));
        list.add(new Student("李四","二班",75));
        list.add(new Student("王五","三班",100));
        Collections.sort(list);
        System.out.println(list);
        //[Student{name='李四', className='二班', sorce=75},
        // Student{name='张三', className='一班', sorce=95},
        // Student{name='王五', className='三班', sorce=100}]

    }
}
public static void main(String[] args) {
        /**
         * 删除第一个字符串当中出现的第二个字符串中的字符
         * 例如:String str1 = "welcome to bit";
         * String str2 = "come";
         * 输出 wl t bit
         * */
        String str1 = "welcome to bit";
        String str2 = "come";
        ArrayList<Character> list = new ArrayList<>();

        for (int i = 0; i < str1.length(); i++) {
            // charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。
            char ch = str1.charAt(i);
            if(!str2.contains(ch+"")){
                list.add(ch);
            }
        }
        System.out.println(list);
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i));
        }
    }
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

class Card{
    public int rank;    // 牌面值
    public String suit; // 花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    public String toString() {
        return "Card{" +
                "rank=" + rank +
                ", suit='" + suit + '\'' +
                '}';
    }
}
public class TestDemo11 {
    // 穷举所有的花色
    public static final String[] SUITS = {"♠","♥","♣","♦"};
    // 买一副牌
    private static List<Card> buyDeck(){
        List<Card> deck = new ArrayList<>(52);
        // 经过两次循环 产生52个牌对象
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 13; j++) {
                // 花色进行赋值
                String suit = SUITS[i];
                // j就相当于牌面值
                int rank = j;
                Card card = new Card(rank,suit);
                deck.add(card);
            }
        }
        return deck;
    }
    private static void swap(List<Card> deck,int i,int index){
        // 此时是链表 不是数组了
        Card t = deck.get(i);
        deck.set(i,deck.get(index));
        deck.set(index,t);
    }
    private static void shuffle(List<Card> deck){
        Random random = new Random(20190905);
        for (int i = deck.size()-1; i > 0; i--) {
            // nextInt(int n) 方法用于获取一个伪随机,在0(包括)和指定值(不包括),从此随机数生成器的序列中取出均匀分布的int值。
            int r = random.nextInt(i);
            swap(deck,i,r);
        }
    }

    public static void main(String[] args) {
        List<Card> deck = buyDeck();
        System.out.println("刚买回来的牌:");
        System.out.println(deck);
        shuffle(deck);
        System.out.println("洗过的牌");
        System.out.println(deck);

        List<List<Card>> hands = new ArrayList<>();
        hands.add(new ArrayList<>());
        hands.add(new ArrayList<>());
        hands.add(new ArrayList<>());

        //三个人 每个人轮流抓5张牌
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                //返回值
                //如果传入元素,删除成功,则返回 true。
                //如果传入索引值,则返回删除的元素。
                Card card = deck.remove(0);
                hands.get(j).add(card);
            }
        }

        System.out.println("剩余的牌:");
        System.out.println(deck);
        System.out.println("A手中的牌:");
        System.out.println(hands.get(0));
        System.out.println("B手中的牌:");
        System.out.println(hands.get(1));
        System.out.println("C手中的牌:");
        System.out.println(hands.get(2));

    }
}

使用remove方法也可以

LinkedList(链表) LinkedList的内存结构是用双向链表存储

构造方法 说明
LinkedList() 无参构造

集合(Set):无序存放,不允许重复,可存放不同类型的对象。

SortedSet:排好序列的Set

映射(Map):俗称键值对
Map接口是键-值对象

常用方法

方法 说明
V get(object k) 根据指定的k查找对应的v
V getOrDefault(object k,v defaultvalue) 根据指定的k查找对应的v,没有找到用默认值代替
V put(k key,v value) 将指定的k-v放入Map
boolean containskey(object key) 判断是否包含key
boolean containValue(object value) 判断是否包含value
Set> entrySet() 将所有键值对返回
boolean isEmpty() 判断是否为空
int size() 返回键值对的数量
public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1981,"张三");
        map.put(2001,"李四");
        map.put(1990,"王二");
        System.out.println(map);
        // {2001=李四, 1990=王二, 1981=张三}
        // 哈希表在存放元素的时候,是根据某种函数来存储的

        String value = map.getOrDefault(1984,"逗比");
        System.out.println(value);
        //逗比

        // map.entrySet() 的作用是把 k和v封装成一个整体,放到set当中(相当于一个布袋)
        // 每一个东西的类型是 Map.Entry
        Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
        for (Map.Entry<Integer,String> en : entrySet) {
            System.out.println(en.getKey()+"-->"+en.getValue());
            /**
             * 2001-->李四
             * 1990-->王二
             * 1981-->张三
             * */
        }
    }

SortedMap:排好序列的Map

你可能感兴趣的:(数据结构,数据结构)