Java 集合

集合类中默认可以存储任意数据类型 

集合提供泛型机制,在定义时,最好为集合类提供一个明确的类型

Collection接口定义了单列集合中共有的功能

        List:可以存储重复元素;List继承了Collection接口,有三个实现的类

                ArrayList:数组列表,数据采用数组方式存储;底层是一个数组实现,提供一系列对

                数组操作的方法;在第一次添加元素时创建底层数组,容量默认是10;在创建

                ArrayList对象时,就会创建底层数组,容量是指定容量;ArrayList实现了长度可变的

                数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高;查询快,

                中间增加、删除慢。

//add方法
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //检查底层数组是否可以存储下元素
        elementData[size++] = e;
        return true;
    }

    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0) //表示数组放不下了
            grow(minCapacity); //对数组进行扩容
        }

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); //新容量是原来长度的1.5倍
        if (newCapacity - minCapacity < 0) 
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity); //数组复制,创建一个新数组
    }
ArrayList arrayList = new ArrayList<>();
        arrayList.add(10); //向末尾添加元素,数组添加满了,自动扩容为原来的1.5倍
        arrayList.add(0,10); //向指定的索引处添加元素
        arrayList.add(20);
        arrayList.add(20);
        arrayList.add(20);
        arrayList.add(20);
        arrayList.add(20);
        arrayList.clear(); //清空元素
        arrayList.contains(10); //是否包含指定元素
        arrayList.get(3);
        /*E elementData(int index) {
            return (E) elementData[index];
        }*/
        arrayList.indexOf(20); //返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1
        arrayList.isEmpty(); //如果此列表不包含元素,则返回true
        arrayList.remove(10); //根据索引删除
        arrayList.remove((Object)10); //根据内容删除
        arrayList.set(0,20); //用指定的元素替换此列表中指定位置的元素
        arrayList.size(); //实际存储元素的个数
        Object[] objs = arrayList.toArray(); //以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组
        System.out.println(Arrays.toString(objs));
        System.out.println(arrayList);

                LinkedList:链表,底层实现是双向链表;

                一个一个的Node对象(data next(指针) prev(指针));插入、删除元素时效率比较

                高;LinkedList中,提供了一些队和栈的操作方法;查询慢,中间增加、删除快。

LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("a");
        linkedList.add("b");
        linkedList.add("c");
        linkedList.add("d");
        linkedList.add(1,"e");
        linkedList.addFirst("g");
        System.out.println(linkedList.get(2));
        /*public E get(int index) {
            checkElementIndex(index);
            return node(index).item;
        }
        //在查找一个元素时,首先判断索引是否小于size/2,是的话从头节点开始向后查找,否则从为节点开始查找
        //相比于ArrayList,查询效率低
        LinkedList.Node<E> node(int index) {
            if (index < (size >> 1)) {
                LinkedList.Node<E> x = first;
                for (int i = 0; i < index; i++)
                    x = x.next;
                return x;
            } else {
                LinkedList.Node<E> x = last;
                for (int i = size - 1; i > index; i--)
                    x = x.prev;
                return x;
            }
        }*/
        linkedList.addLast("e");
        System.out.println(linkedList.pollFirst()); //取出表头的元素并删除
        System.out.println(linkedList.remove());
        linkedList.addLast("e");
        System.out.println(linkedList.removeLast());

                Vector:数组列表,底层实现也是数组,添加同步锁,是线程安全的

        List集合遍历

                for循环遍历

                增强for循环的遍历

                迭代器遍历(Iterator)

ListIterator<String> listIterator = list.listIterator();
        while (listIterator.hasNext()) {
            String str = listIterator.next();
            System.out.println(str);
            //listIterator.remove();
        }

        Set:不可以存储重复元素,Set中的元素是没有索引的

                HashSet:底层使用哈希表,类中的元素不能重复,即彼此调用equals方法比较,都返回false,底层数据结构是哈希表+链表,哈希表依赖于哈希值存储。

                TreeSet:底层使用树结构,可以给Set集合中的元素进行指定方式的排序,存储的对象必须实现Comparable接口,TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)

        HashSet/HashMap中如何保证值(键)不重复:当添加一个元素时,首先会调用值的hashCode方法,计算出一个hash值(整数),hash值不安全,有可能内容不一样,hash值一样,equals方法判断效率低;底层实现:首先会用内容计算出一个哈希值,用哈希值比较,一旦哈希值相等,就会使用equals方法对内容进行比较。

Map接口是将键(key)映射到值(value)的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值;

Map接口是一种双列集合,存储的每个元素都由键和值两部分组成,一个键映射到一个值,键是不可以重复的,值可以重复;

HashMap集合是Map接口的一个实现类,它用于存储键值映射关系,但必须保证不出现重复的键,HashMap的键的类型一般锁定的是Sring类型;

//通过value获取key
    public void getKey(Map map, String value) {
        //通过entrySet()方法把map中的每个键值对变成对应成Set集合中的一个对象
        Set set = map.entrySet();
        Iterator<Map.Entry<String, String>> iterator = set.iterator();
        while (iterator.hasNext()) {
            //Map.Entry是一种类型,指向map中的一个键值对组成的对象
            Map.Entry<String, String> entry = iterator.next();
            if (entry.getValue().equals(value)) {
                System.out.print(entry.getKey() + ",");
            }
        }
    }

根据键值key计算hash值得到插入数组的索引 i

判断table[i]为空 ,直接new Node对象包含k,v,将Node对象存储到计算的位置即可

判断table[i]不为空,判断key是否存在,key如果存在,直接覆盖value

当计算的位置上已经有元素,判断链表长度,如果没有转为红黑树,直接将元素添加到链表中,如果已转为红黑树,那就添加到红黑树中

 HashTable

Hashtable hashtable = new Hashtable();
        hashtable.put("a", "a");
        hashtable.put("c", "b");
        hashtable.put("c", "c");
        hashtable.put("d", "c");
        hashtable.put("e", "e");
        hashtable.put("f", "f");
        System.out.println(hashtable);
        System.out.println(hashtable.keySet());
        System.out.println(hashtable.entrySet());//entrySet()只是单纯存储一组键值对
        System.out.println(hashtable.values());

不能存储空值 

HashTable适合多线程

HashMap适合单线程

Collections工具类

      List<String> list = new ArrayList<String>();

        Collections.addAll(list, "A", "B", "C", "D", "E", "E");
        System.out.println(list);

        Collections.reverse(list);//倒序
        System.out.println(list);

        Collections.reverse(list);
        System.out.println(list);

        Collections.shuffle(list);//随机排序
        System.out.println(list);

        Collections.sort(list);//
        System.out.println(list);

        Collections.swap(list, 1, 3);//交换位置
        System.out.println(list);

        Collections.replaceAll(list, "E", "X");//替换
        System.out.println(list);

        System.out.println(Collections.max(list));
        System.out.println(Collections.min(list));

        Collections.fill(list,"a");
        System.out.println(list);

泛型

泛型有三种使用方式,分别为:泛型类、泛型接口和泛型方法。

保证了类型的安全性:在没有泛型之前,从集合中读取到的每一个对象都必须进行类型转换,如果不小心插入了错误的类型对象,在运行时的转换处理就会出错。

public static void useGeneric() {
 
ArrayList<String> names = new ArrayList<>();
 
names.add("add是一个方法");
 
names.add(123); //编译不通过
 
}

 当重写为使用泛型时,代码不需要强制转换:

List<String> list = new ArrayList<String>();
 
list.add("hello");
 
String s = list.get(0); // no cast

 子类也是泛型类,子类和父类的泛型类型要一致

        class A<T> extends Demo<T>

子类不是泛型类,父类要明确泛型的数据类型

        class A extends Demo<String>

public class GenericClass<T> {
 
    private T value;
 
    public GenericClass(T value) {
 
        this.value = value;
    }
 
    public T getValue() {
 
        return value;
 
    }
 
    public void setValue(T value) {
 
        this.value = value;
 
    }
 
}

类型通配符上限

        类/接口<? extends 实参类型>

        要求该泛型的类型,只能是实参类型,或实参类型的子类类型

类型通配符下限

        类/接口<? super 实参类型>

        要求该泛型的类型,只能是实参类型,或实参类型的父类类型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值