2021-05-06

集合框架

https://www.bilibili.com/video/BV1zD4y1Q7Fw?p=43

一.什么是集合

  • 概念:存储对象的容器,定义了对象的常用操作方法,类似数组的功能。

  • 和数组的区别:

    (1)数组长度固定,集合长度不固定

    (2)数组可以存储基本类型和引用类型,集合只能存储引用类型(存储基本类型可使用装箱操作)

  • 位置:java.util.*

 

二.Collection体系集合

 

Collection接口

特点:代表一组任意类型的对象,有部分有序,有部分无序,无下标,有部分可重复,有部分不可重复

有序(添加和遍历顺序一致),有下标(可以通过下标访问),元素可重复

方法:

boolean add(Object obj) //添加一个对象

boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中

void clear() //清空此集合中所有元素

boolean contains(Object o) //检查此集合是否包含o对象

boolean equals(Object o) //比较两个对象是否相等

boolean isEmpty() //判断集合是否为空

boolean remove(Object o) //在此集合中移除o对象

int size() //获取集合中元素个数

Object[] toArray() //将此集合转换成数组

boolean removeAll(Collection c) //删除与集合c重复的元素

boolean retainAll(Collection c) //保留与c的交集

Iterator itrrator() //返回在此Collection的元素上迭代的迭代器,是个接口

 

代码展示

public class Demo1 {
    public static void main(String[] args) {
//创建集合
        Collection collection = new ArrayList();
//(1)添加元素
        collection.add("迪迦");
        collection.add("戴拿");
        collection.add("盖亚");
        System.out.println("元素个数" + collection.size());
        System.out.println(collection);
//(2)删除元素
        collection.remove("迪迦");
        System.out.println(collection);
//      collection.clear();
//(3)遍历元素[重点]
        //方法一:增强for
        for (Object object : collection) {
            System.out.println(object);
        }
        //方法二:迭代器,专门用来遍历集合的一个接口,有三个方法
        //hasNext();有无下一个元素
        //next();获取下一个元素
        //remove();删除当前元素即iterator.next();的返回元素
        Iterator iterator = collection.iterator();
        while (iterator.hasNext()){
            Object object = iterator.next();
            System.out.println(object);
        }
//(4)判断
        System.out.println(collection.contains("阿古茹"));
    }
}

 

注意

  • collection.add() 仅是把地址加入collection对象

  • collection.remove() 删除对象仅是把地址从collection对象中删除,但三个对象仍存在

  • 遍历输出时,可将Object类型强转成Student类型,以便输出值

  • 迭代过程中,不能使用collection的删除方法

 

List接口(Collection的子接口)

  • ArrayList实现了接口List

List heros = new ArrayList(); //List父类,ArrayList子类

 

  • 特点:有序(添加和遍历顺序一致),有下标(可以通过下标访问),元素可重复

 

方法

void add(int index , Object o) //在index位置插入对象o

boolean addAll(int index , Collection o) //将一个集合中的元素添加到此集合中的index位置

Object get(int index) //返回集合中指定位置的元素

List subList(int fromIndex, int toIndex) //返回fromIndex和toIndex之间的集合元素

ListIterator listiterator() //返回迭代器,迭代器存储当前对象的一系列信息,功能强大,可前可后遍历,可返回下标

boolean remove(Object o) //首先判断位置删除,其次可指定Object 20 即删除值为20的元素

 

ArrayList(List实现类)

  • 特点:数组结构实现,查询快,增删慢,需开辟连续空间

    JDK1.2版本,运行效率快,线程不安全

 

源码分析

  • 默认容量大小 10

private static final int DEFAULT_CAPACITY = 10;

 

  • 存放元素的数组

transient Object[] elementData;

 

  • size实际元素个数

private int size;

 

  • 无参构造方法(如果没有向集合添加任何元素,容量为0,添加任意1个元素后容量变为10,由add方法调用,填满后自动扩容原来的1.5倍 因为>>2 右移两位 )

public ArrayList() 

 

常用方法

因为ArrayList实现了List接口,所以List接口的方法ArrayList都实现了

 

  • 01 add

加对象

```jArrayList heros = new ArrayList();//定义容器
Hero h1 = new Hero(special Hero);//调用重写的构造
heros.add(h1);//最后位置加对象
heros.add(3,h1);//指定位置3

 

  • 02 contains

判断是否存在该对象

ArrayList heros = new ArrayList();
heros.contains(new Hero("hero 1"));//返回true或flase,这里因为是新创建的hero 1 不是一个对象,所以flase
​
heros.contains(specialHero);//有speacialHero对象则返回true

 

  • 03 get

获取指定位置对象

ArrayList heros = new ArrayList();//定义容器
sout(heros.get(5));//返回对象名

 

  • 04 indexOF

获取对象所处位置

heros.indexOf(specialHero);//获取specialHero对象所处位置

 

  • 05 remove

删除

heros.remove(2);//根据下标删除
heros.remove(specialHero);//根据对象删除

 

  • 06 set

 heros.set(5, new Hero("hero 5"));//替换下标为5的对象

 

  • 07 size

获取ArrayList的大小

heros.size();//返回heros的对象个数

 

  • 08 toArray

把一个ArrayList对象转换为数组

如果要转换为一个Hero数组,那么需要传递一个Hero数组类型的对象给toArray(),这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组

 Hero hs[] = (Hero[])heros.toArray(new Hero[]{}); //()强转

 

  • 09 addAll

把另一个容器所有对象都加进来

ArrayList heros = new ArrayList(); 
ArrayList anotherHeros = new ArrayList();
heros.addAll(anotherHeros);

 

  • 10 clear

清空一个ArrayList

heros.clear();

 

遍历ArrayList

for循环遍历

for(int i=0; i<heros.size;i++){
    Hero h = heros.get(i);
    sout(h);
} 

 

迭代器遍历1

使用迭代器Iterator遍历集合中的元素 ,迭代器就像指针,最开始指在空位置

 

List<Hero> heros = new ArrayList<Hero>();
//加入对象
。。。
Iterator<Hero> it = heros.iterator();
//从最开始的位置判断"下一个"位置是否有数据
//如果有就通过next取出来,并且把指针向下移动
//直到"下一个"位置没有数据
while(it.hasNext()){
Hero h = it.next();
System.out.println(h);
}

 

迭代器遍历2

for (Iterator<Hero> iterator = heros.iterator(); iterator.hasNext();) {
            Hero hero = (Hero) iterator.next();
            System.out.println(hero);
        }

 

迭代器遍历3(列表迭代器)

ListIterator lit = arrayList.listIterator();
while(lit.hasNext()){
Stdent s = (Student)lit.next();
System.out.println(s);
}

 

 

增强for遍历

List<Hero> heros = new ArrayList<Hero>();
for (Hero h : heros) {
            System.out.println(h);
        }

 

Vector(List实现类)

数组结构实现,查询快,增删慢

JDK1.0版本,运行效率慢,线程安全

 

常用函数

add

remove

elements() //使用枚举器遍历

while(en.hasMoreElements()){
    Object o = en.nextElement();
    sout(o);
}

 

 

LinkedList(List实现类)

链表结构实现,增删快,查询慢,无需开辟连续空间

LinkedList linkedList = new LinkedList<>();

 

方法

LinkedList也实现了List接口,有add,remove,contains等等方法。

 

源码分析

  • transient int size = 0; 初始大小

 

  • transient Node<E> first; 头结点

 

  • transient Node<E> last; 尾结点

 

  • 构造方法

    public LinkedList() {
    }

 

  • add方法 指向linkLast()方法 有Node节点(E是实际数据,next后节点,prev 前节点)

 

 

双向链表Deque

LinkedList还实现了双向链表结构Deque接口。

  • 声明

LinkedList<Hero> ll =``new` `LinkedList<Hero>();
  • 后插

ll.addLast(newHero("hero1"));
  • 前插

ll.addFirst(new Hero("heroX"));

前取,后取,前查,后查

 

队列 - Queue

LinkedList 除了实现了List和Deque外,还实现了Queue接口(队列)。

offer 在最后添加元素 poll 取出第一个元素 peek 查看第一个元素

List ll =new LinkedList<Hero>();
Queue<Hero> q= new LinkedList<Hero>();
q.offer(new Hero("Hero1"));
Hero h = q.poll();
h=q.peek();

 

泛型

  • 泛型定义

    JDK1.5引入,本质是参数化类型,把类型作为参数传递

  • 泛型形式

    泛型类,泛型接口,泛型方法

  • 语法

    类名<T>

    <T,...>类型 T称为类型占用符,表示一种引用类型,如果写多个用逗号隔开

    K键

    E值

  • 好处

    1.提高代码重用性

    2.防止转换异常

    不指定泛型的容器,可以存放任何类型的元素 指定了泛型的容器,只能存放指定类型的元素以及其子类

    在取出数据的时候,不需要再进行转型了,因为里面肯定是放的Hero或者其子类

List<Hero> genericheros = new ArrayList<Hero>();
genericheros.add(new Hero("盖伦"));
genericheros.add(new APHero());
Hero h = genericheros.get(0);

 

  • 泛型简写

基本写法

List<Hero> genericheros = new ArrayList<Hero>();

简写

List<Hero> genericheros2 = new ArrayList<>();

 

  • 泛两种类

定义一个接口,两个类实现接口

List<LOL> lolList = new ArrayList<>();
lolList.add( new Hero("盖伦")); //能放Hero
lolList.add( new Item("血瓶")); //也能放Item

泛型类

  • 声明出的对象里的任何属性,变量,方法都只能用某种引用类型

package Generic;
​
public class MyGeneric<T> {
    //1.泛型使用1创建变量
    T t;
    //2.作为方法的参数
    public void show(T t){
        System.out.println(t);
    }
    //3.作为方法的返回值
    public T getT(){
        return t;
    }
    //注意泛型类里不可以实例化,因为无法保证对应的构造方法是否一定存在
}

调用类

package Generic;
​
public class TestGeneric {
    public static void main(String[] args) {
        //使用泛型类创建对象
        //注意:1泛型只能使用引用类型2.不同泛型类型对象之间不能相互赋值
        MyGeneric<String> myGeneric = new MyGeneric<>();
        myGeneric.t = "hello";
        myGeneric.show("大家好");
        String string = myGeneric.getT();
​
        //使用泛型创建Integer
        MyGeneric<Integer> myGeneric1 = new MyGeneric<>();
        myGeneric1.t = 100;
        myGeneric1.show(200);
        Integer integer = myGeneric1.getT();
    }
}

 

泛型接口

  • 创建接口

public interface MyInterface<T> {
    String name = "张三";
    //不能使用泛型创建静态常量,因为不能实例化对象T t = new T();
​
    //创建函数
    T server(T t);
​
}

 

  • 实现接口

1.提前告知泛型类型

public class MyInterfaceImpl implements MyInterface<String>{
    public String server(String t){
        System.out.println(t);
        return t;
    }
}

 

2.实现接口不告知泛型类,在调用的时候指明类型(实现类也变成一个泛型类)

public class MyInterfaceImp2<T> implements MyInterface<T> {
​
    public T server(T t){
        System.out.println(t);
        return t;
    }
​
}

main方法里

MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImp2<>();
impl2.server(1000);

 

泛型方法

  • 定义

public class MyGenericMethod {
    //泛型方法
    public <T> void show(T t){
        System.out.println(t);
        T t2;
    }
}
  • 调用

//泛型方法调用
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("中国加油");//方法的类型由传入的类型决定
myGenericMethod.show(100);

 

泛型好处

1.提高代码重复性:泛型方法

2.防止类型转换异常,提高代码安全性

 

泛型集合

  • 概念:参数化类型,类型安全的集合,强制集合类型的元素必须一致

 

  • 特点:编译时即可检查,而非运行时抛出异常

访问时,不必类型转换

不同泛型间不能相互赋值,泛型不存在多态

 

  • 使用

1.集合不调用泛型,自动Object,虽然所有类型都可以加入arrarylist但无法判断输入类型

public class Demo {
    public static void main(String[] args) {
        ArrayList <String> arrayList = new ArrayList<String>();
        arrayList.add("111");
        arrayList.add("222");
    }
}

 

Set集合

  • 特点:无序,无下标,元素不可重复(只要地址不同就可以添加)

 

方法

继承自Collection方法

 

HashSet

  • 特点

元素不能重复

基于HashCode计算元素存放位置

当存入元素的哈希码相同时,会调用equals进行确认,如结果是true,则拒绝后者存入(hashcode和equals方法如果值一样,无法存入)

 

  • 存储结构

数组+链表+红黑树

 

  • 使用

public class Demo1 {
    public static void main(String[] args) {
        HashSet<String> hashSet = new HashSet<>();
        //添加元素
        hashSet.add("刘德华");
        System.out.println(hashSet.toString());
    }
}

 

HashSet<String> names =new HashSet<String>();
names.add("gareen");
System.out.println(names);
//第二次插入同样的数据,是插不进去的,容器中只会保留一个
names.add("gareen");
System.out.println(names);
  • Set中的元素顺序,是不确定的

  • Set不提供get()来获取指定位置的元素 ,所以遍历需要用到迭代器,或者增强型for循环

 //遍历Set可以采用迭代器iterator
        for (Iterator<Integer> iterator = numbers.iterator(); iterator.hasNext();) {
            Integer i = (Integer) iterator.next();
            System.out.println(i);
        }
         
        //或者采用增强型for循环
        for (Integer i : numbers) {
            System.out.println(i);
        }

 

  • HashSet和HashMap的关系

HashSet里封装了一个HashMap<E,Object>,实际上就是用HashSet的构造方法初始化这个HashMap

向HashSet中增加元素,其实就是把该元素作为key,增加到Map中

value是PRESENT,静态,final的对象,所有的HashSet都使用这么同一个对象

 

TreeSet

  • 特点

基于排列顺序实现元素不重复

实现了SorttedSet接口,对集合元素自动排序

元素对象的类型必须实现Comparable接口,指定排序规则

通过compareTo方法确定是否为重复元素(若出现String类型,无法比较可重写该compareTo方法),方法返回0,认为是重复

 

 

  • 存储结构

红黑树

 

比较器

  • Comparator接口(定制比较器)

Comparator给定如何进行两个对象之间的大小比较(定义对象的比较属性)

重写compare接口方法

 

 

  • Comparable接口

compareTo方法

 

Map集合

 

  • 特点

1.用于存储键值对

2.键:无序,无下标,不允许重复

3.值:无序,无下标,允许重复

 

Map父接口

  • 特点

1.用于存储键值对

2.键:无序,无下标,不允许重复

3.值:无序,无下标,允许重复

 

  • 方法

put()//添加

 

  • 使用

Map<String,String> map = new HashMap<>();

 

  • 遍历

1.keySet方法

 

 

2.entrySet方法

 

 

 

HashMap(哈希表)

  • 特点

JDK1.2,线程不安全,运行效率快,运行效率快,允许用null作为key或value

 

HashMap储存数据的方式是—— 键值对

key 》value 一个key只能指向一个value(重复指向会覆盖),一个value可被多个key指向

HashMap<String,Hero> heroMap = new HashMap<String,Hero>();
heroMap.put("gareen", new Hero("gareen1"));
System.out.println(heroMap);//输出所有键值对
​

 

HashTable

  • 特点

JDK1.0,线程安全,运行效率慢,不允许null作为key或者value

 

 

 

TreeMap(红黑树)

  • 实现类SortedMap接口(Map子接口),可以对key排序,红黑树实现

 

Collections工具类

  • 概念:集合工具类,定义了除了存取以外的集合常用方法

  • 方法:

reverse() //翻转元素

shuffle() //重制元素顺序

sort()//升序元素

 

补充

 

 

栈 - Stack

push 压栈

pull 出栈

peek 查看最后一个

LinkedList<Hero> heros = new LinkedList<Hero>();
​
public void push(Hero h) {
        heros.addLast(h);
    }
​
public Hero pull() {
        return heros.removeLast();
    }
​
public Hero peek() {
        return heros.getLast();
    }

 

二叉树

 

排序

根据左边放小,右边放大的顺序,创建节点

递归二叉树排序,定义Node类产生对象,add方法给对象赋值或比较

每次都从根节点开始比较

package er_chashu;
​
public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
​
    // 值
    public Object value;
​
    // 插入 数据
    public void add(Object v) {
        // 如果当前节点没有值,就把数据放在当前节点上
        if (null == value)
            value = v;
​
            // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
        else {
            // 新增的值,比当前值小或者相同
​
            if ((Integer) v -((Integer)value) <= 0) {
                if (null == leftNode)
                    leftNode = new Node();
                leftNode.add(v);
            }
            // 新增的值,比当前值大
            else {
                if (null == rightNode)
                    rightNode = new Node();
                rightNode.add(v);
            }
​
        }
​
    }
​
    public static void main(String[] args) {
​
        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
​
        Node roots = new Node();
        for (int number : randoms) {
            roots.add(number);
        }
​
    }
}
​

 

遍历

整体来看很好理解,最外层小的放在左边(递归新的根节点),自己在中间,最外层大的放在右边(递归新的根节点)

    // 中序遍历所有的节点
    public List<Object> values() {
        List<Object> values = new ArrayList<>();
​
        // 左节点的遍历结果,左节点执行values方法,递归调用
        if (null != leftNode)
            values.addAll(leftNode.values());//最外层全部加入最左边
​
        // 当前节点加入values,无左节点把自己加进去
        values.add(value);
​
        // 右节点的遍历结果
        if (null != rightNode)
​
            values.addAll(rightNode.values());//最外层全部加入最右边
        //左右均无节点把自己返回
        return values;
    }

 

 

 

Collection类

Collection是 Set List Queue和 Deque的接口

  • 注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的

  • 注:Deque 继承 Queue,间接的继承了 Collection

 

Collections

Collections是一个类,容器的工具类,就如同Arrays是数组的工具类

提供一系列静态的public方法

类似Math类中的方法,直接调用即可

  • 反转 reverse

List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
            numbers.add(i);
        }
Collections.reverse(numbers);

 

  • 混淆 shuffle

Collections.shuffle(numbers);`

 

  • 排序sort

Collections.sort(numbers);

 

  • 交换swap

Collections.swap(numbers,0,5);

 

  • 滚动rotate

Collections.rotate(numbers,2);

 

  • 线程安全化

List<Integer> numbers = new ArrayList<>();
System.out.println("把非线程安全的List转换为线程安全的List");
List<Integer> synchronizedNumbers = (List<Integer>) Collections.synchronizedList(numbers);

 

关系与区别

 

ArrayList与HashSet的区别

  • 元素有无顺序

ArrayList: 有顺序 HashSet: 无顺序

 

  • 元素能否重复

List中的数据value可以重复 Set中的数据value不能够重复

 

ArrayList和LinkedList的区别

ArrayList是数组:插入数据慢,定位快

LinkedList是双向链表:插入数据快,定位慢

 

HashMap和HahTable的异同

  • 同:HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式

  • 异:

    区别1: HashMap可以存放 null Hashtable不能存放null 区别2: HashMap不是线程安全的类 Hashtable是线程安全的类

 

几种Set的比较

HashSet: 无序 LinkedHashSet: 按照插入顺序 TreeSet: 从小到大排序

HashSet<Integer> numberSet1 =new HashSet<Integer>();
LinkedHashSet<Integer> numberSet2 =new LinkedHashSet<Integer>();
TreeSet<Integer> numberSet3 =new TreeSet<Integer>();

 

hashcode原理

数组+链表:空间换时间

List查找低效率

HashMap查找高效

 

HashMap高效原因

  • 概念:所有的对象,都有一个对应的hashcode(散列值)

  • 保存数据:某一hashcode已有值,在这个hashcode创建链表,链式存储多个元素

  • 查找数据:首先根据hashcode下标,到数组中进行定位,再比较元素名称

 

HashSet判断是否重复

因为HashSet没有自身的实现,而是里面封装了一个HashMap,所以本质上就是判断HashMap的key是否重复。

如果hashcode不一样,就是在不同的坑里,一定是不重复的 如果hashcode一样,就是在同一个坑里,还需要进行equals比较 如果equals一样,则是重复数据 如果equals不一样,则是不同数据。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值