JAVA集合概述

集合

集合和数组的异同

同:都是用来存储数据的

异:数组长度不可变,且要求存储同一类型的数据,集合长度可变,可以存放不同类型的数据

集合的框架

 

java集合框架分为两个接口Collection(单列集合)和Map(双列集合)

二者的区别Collection和Map接口之间的主要区别在于:Collection中存储了一组对象,而Map存储关键字/值对。 在Map对象中,每一个关键字最多有一个关联的值。 Map:不能包括两个相同的键,一个键最多能绑定一个值。 null可以作为键,这样的键只有一个;可以有一个或多个键所对应的 值为null。 当get ()方法返回null值时,即可以表示Map中没有该键,也可以表示该键所对应的值为null。 因此,在Map中不能由get ()方法来判断Map中是否存在某个键,而应该用containsKey ()方法来判断。 HashTable:Dictionary的子类,确省是线程同步的。 不允许关键字或值为nul

Collection接口

Collection 接口是 List、Set 和 Queue 接口的父接口,通常情况下不被直接使用。Collection 接口定义了一些通用的方法,通过这些方法可以实现对集合的基本操作。定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。

// Collection的API常用方法
abstract boolean         add(E object)
abstract boolean         addAll(Collection<? extends E> collection)
abstract void            clear()
abstract boolean         contains(Object object)
abstract boolean         containsAll(Collection<?> collection)
abstract boolean         equals(Object object)
abstract int             hashCode()
abstract boolean         isEmpty()
abstract Iterator<E>     iterator()
abstract boolean         remove(Object object)
abstract boolean         removeAll(Collection<?> collection)
abstract boolean         retainAll(Collection<?> collection)
abstract int             size()
abstract <T> T[]         toArray(T[] array)
abstract Object[]        toArray()
/**
 * Collection方法声明对象的使用
 * 向Collection对象中添加数据用add()方法,可以调用各种类型的数据
 * contrain方法判断元素是否存在对象中,返回的是true或false
 */
@SuppressWarnings("all")
public class CollectionDemo01 {
    @Test
    // 集合的判断操作
    public void test1(){
        Collection col1 = new ArrayList<>();
        col1.add(123);
        col1.add(456);
        col1.add("A");
        col1.add("B");
        col1.add("fvhhb");
        col1.add(new String("jie"));
        col1.add(new Demo01("tianliang",22));
        // contains方法,判断元素是否存在集合中,返回的是true或false
        System.out.println(col1.contains(new String("jie")));
        System.out.println(col1.contains(new Demo01("tianliang",22)));
    }
    @Test
    // 集合的添加和移除
    public void test2(){
        Collection col1 = new ArrayList<>();
        col1.add(123);
        col1.add(456);
        col1.add("A");
        col1.add("B");
        col1.add("fvhhb");
        col1.add(new String("jie"));
        col1.add(new Demo01("tianliang",22));
        col1.remove(456);
        System.out.println(col1);
        col1.remove(new Demo01("tianliang",22));
        System.out.println(col1);
    }
    @Test
    // 集合的移除操作和求两个集合的交集
    public void test3(){
        Collection col1 = new ArrayList<>();
        col1.add(123);
        col1.add(456);
        col1.add("A");
        col1.add("B");
        col1.add("fvhhb");
        col1.add(new String("jie"));
        col1.add(new Demo01("tianliang",22));
        col1.remove(456);
        Collection col11 = Arrays.asList(123,456,896);
        col1.retainAll(col11);
        System.out.println(col1);
​
    }
    @Test
    // 集合与数组之间的转换
    public void test4(){
        Collection col1 = new ArrayList<>();
        col1.add(123);
        col1.add(456);
        col1.add("A");
        col1.add("B");
        col1.add("fvhhb");
        // 将集合转换为数组
        Object[] arr = col1.toArray();
        for (Object o:arr){
            System.out.println(o);
        }
        // 将数组转换为集合
        List<String> list = Arrays.asList(new String[]{"a", "b", "c"});
        List list1 = Arrays.asList(new Integer[]{123,456});
        System.out.println(list1);
    }
}
​

List子接口

List集合是一组有序可重复集合,元素都有索引,按照添加顺序排列,可以通过索引(LinkedList使用链表)快速查找,其中包含了三个常用的类,分别是ArrayList,Vector,LinkedList。

ArrayList实现类

  • 底层使用的是数组;

  • 根据数组索引查找元素,所以查询快;增删因为要移动元素位置,所以增删慢;

  • 元素按照插入的顺序排列,元素可以重复;

  • 非线程安全

ArrayList底层实现原理是数组,但jdk版本不一样其原理也有所不同

在jdk7中是先定义好一个长度为10的数组,而在jdk8中先不定义,在调用add()方法后再定义一个长度为10的数组

//jdk7:
ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementDate
list.add(123);//elementDate[] = new Integer(123);
...
list.add(11);//如果此次的添加导致底层elementDate数组容量不够,则扩容
//1.默认扩容为原来的1.5倍,同时将原来的数组元素复制到新的数组中。
//2.结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
​
​
//jdk8:
ArrayList list = new ArrayList();//底层Object[]数组elementDate初始化为{},并没有创建长度为10的数组
list.add(123);//第一次调用add()时,底层才创建了长度为10的数组,并将数据123添加到elementDate中
...
list.add(11);//如果此次的添加导致底层elementDate数组容量不够,则扩容
//1.默认扩容为原来的1.5倍,同时将原来的数组元素复制到新的数组中。
//2.结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)

ArrayList常用方法

/**
 * list常用方法
 * 总结:常用方法
 * 增:add(Object obj)
 * 删:remove(int index)或remove(Object obj)
 * 改:set(int index,Object ele)
 * 查:get(int index)
 * 插:add(int index,Object ele)
 * 长度:size()
 * 遍历:1.Iterator 2.增强for循环
 */
public class ListTest {
    @Test
    public void Test(){
        ArrayList arrayList = new ArrayList<>();
        arrayList.add(123);
        arrayList.add("r");
        arrayList.add("liqi");
        arrayList.add(85);
        arrayList.add(new Demo01("tianliang",22));
        // ArrayList插入操作 void add(index,Object ele),在索引位置插入元素
        System.out.println(arrayList);
        arrayList.add(2,"liang");
        System.out.println(arrayList);
        // boolean addall(int index,Collection eles),在索引位置开始插入集合
        List a = Arrays.asList("a", 123);
        arrayList.addAll(2,a);
        System.out.println(arrayList);
        // Object get(int index)通过索引获得元素
        System.out.println(arrayList.get(5));
        // int indexof(Object obj),返回某元素第一个出现的索引位置
        System.out.println(arrayList.indexOf(123));
        // int lastindexof(Object obj),返回某元素最后一次出现的索引位置
        System.out.println(arrayList.lastIndexOf(123));
        // Object remove(int index)移除指定索引位置的元素并返回该元素
        System.out.println(arrayList.remove(6));
        // Object set(int index,Object ele),修改某索引位置的元素并返回修改前的元素。
        System.out.println(arrayList.set(5,"wei"));
        // list sublist(int index,int index),列表切片,返回的是一个列表
        // 其中索引区间为左闭右开
        System.out.println(arrayList.subList(1,5));
    }
}
​

ArrayList结构图

LinkedList实现类

LinkList是一个继承于AbstractSequentialList的双向链表。它可以被当做堆栈、队列或双端队列进行操作。

LinkedList 实现 List 接口,能进行队列操作。

LinkedList 实现Deque接口,即能将LinkedList当作双端队列使用。

import org.junit.Test;
​
import java.util.LinkedList;
/*
LinkedList实现类相关操作
 */
​
public class LinkListTest {
    @Test
    public void test() {
        LinkedList obj1 = new LinkedList<>();
        // 向Linklist中添加元素
        obj1.add(152);
        obj1.add("zeng");
        obj1.add(42);
        obj1.add("A");
        // 将元素放入队列的尾部
        obj1.offer("c");// 输出[152,zeng,42,A,c]
        // 将元素放入顶部
        obj1.push("f");// 输出[f,152,zeng,42,A,c]
        // 访问但不删除队列头部元素
        System.out.println(obj1.peekFirst());
        // 弹出队列顶部元素
        obj1.pop();
        System.out.println(obj1);// 输出[152,zeng,42,A,c]
​
​
    }
}

HashSet

HashSet是Set子接口的一个实现类,它只允许放入同种类型的数据,且数据是无序的和不能重复的。HashSet的底层通过HashMap实现的,而HashMap在1.7之前使用的是数组+链表实现,在1.8+使用的数组+链表+红黑树实现。其实也可以这样理解,HashSet的底层实现和HashMap使用的是相同的方式,因为Map是无序的,因此HashSet也无法保证顺序。HashSet的方法也是借助HashMap的方法来实现的。

/*
hashset实现类,当定义一个类时,所要有方法有无参构造方法和有参构造方法,tostring和set、get方法
以及hashcode和equals方法,当判断添加的元素是否重复时,先判断hashcode方法值,再判断eauals方法,当两个方法hashcode返回值相等,且equals方法返回true时,才能判断两个值是重复的
*/
@SuppressWarnings("all")
public class LinkListTest {
    @Test
     public void test02(){
        Set set = new HashSet<>();
        set.add(new Person("tianliang",29));
        set.add(new Person("tianliang",29));
        System.out.println(set);
    }
}
​
// 定义一个Person类,有私有对象name和age
class Person{
    private String name;
    private int age;
    // 无参构造器
    public Person() {
    }
    // 有参构造器
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // get()和set()方法
    public String getName() {
        return name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
    // 重写父类的打印方法
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //重写equals方法
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Person)){
            return false;}
        Person person = (Person)o;
        if (this.name.equals(((Person) o).name)&&this.age==((Person) o).age){return true;}
        return false;
    }
    // 重写hashcode()方法
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

Map接口

  • 实现类:

    • HashMap,其子类:

      • LinkedHashMap

    • SortedMap,其子类:

      • TreeMap

    • Hashtable,其子类:

      • Properties

  • Map接口:双列数据,存储key-value对的数据 ----类似于高中的函数:y = f(x) HashMap底层结构:jdk8中:数组+链表+红黑树 HashMap:作为Map主要的实现类:线程不安全,效率高;存储null的key和value,扩容为原来的两倍 子类:LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历 原因:在原有的HashMap底层结构基础上,添加一对指针,指向前一个和后一个 对于频繁的遍历操作,此类执行效率高于HashMap TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。 此时考虑key的自然排序或定制排序。 底层结构:使用红黑树 Hashtable:作为古老的实现类:线程安全,效率低;不能存储null的key和value 子类:Properties:常用来处理配置文件。key和value都是String类型

HashMap的底层实现原理

  • jdk7中:

  • HashMap map = new HashMap(); 1.实例化后底层创建了长度是16的一维数组Entry[] table。 ..可能已经执行过多次put... 2.map.put(key1,value1): 首先调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算得到Entry数组中的存放位置。 如果此位置上数据为空,此时key1,value1添加成功 如果此位置上有数据,比较key1和已经存在的一个或多个数据的哈希值(以链表形式存在): 如果哈希值都不相同,key1-value1添加成功 如果key1哈希值和某一个数据(key2-value2)的哈希值相同,调用key1所在类的equals(key2)方法比较: 如果equals()返回false,key1-value1添加成功 如果equals()返回ture,使用value1替换value2.

  • jdk8中: 1.new HashMap():底层没有创建一个长度为16的数组 2.jdk8底层的数组不是Entry[],而是Node[] 3.首次调用put()方法时,底层创建长度为16的数组 4。底层结构:数组+链表+红黑树, 当数组某一个索引位置上的元素以链表形式存在的数据个数>8,且当前数组的长度>64, 此索引位置上所有数据改为红黑树存储。

@SuppressWarnings("all")
/*
练习题:创建一个hashmap<Interge,Demo01>,Demo01是自定义类,里面有属性name和age.试将hashmap中的元素按照
姓名从大到小进行排序,要求不可拆分键值对。
分析:由于hashmap不可进行排序,我们可以将其转换为list(其中的元素对象为hashmap键值对entry),然后再使用Collections
工具类中的sort方法对list进行排序,然后遍历list通过ListHashMap进行有序的添加数据
 */
public class HashMapTest01 {
    public static void main(String[] args) {
        // 创建hashmap对象,键类型为int,值类型为Demo01对象
        HashMap<Integer, Demo01> a1 = new HashMap<>();
        a1.put(1, new Demo01("赵六", 18));
        a1.put(2, new Demo01("李四", 23));
        a1.put(3, new Demo01("王五", 17));
        a1.put(4, new Demo01("张三", 20));
        // 调用sort方法对值中的name属性进行排序
        HashMap<Integer, Demo01> a2 = sort(a1);
        // 输出排序前后的数据变化
        System.out.println("排序前:"+a1);
        System.out.println("排序后:"+a2);
    }
​
    public static HashMap<Integer,Demo01> sort(HashMap<Integer,Demo01> hashmap){
        // 获取hashmap键值对
        Set<Map.Entry<Integer, Demo01>> entry = hashmap.entrySet();
        // 将键值对转换为list,以便进行排序
        ArrayList<Map.Entry<Integer, Demo01>> list1 = new ArrayList<>(entry);
        // 调用Collections下的sort方法,对list进行排序
        Collections.sort(list1, new Comparator<Map.Entry<Integer, Demo01>>() {
            @Override
            public int compare(Map.Entry<Integer, Demo01> o1, Map.Entry<Integer, Demo01> o2) {
                // 创建Collator对象com,对字符进行排序
                Collator com = Collator.getInstance(Locale.CHINA);
                return com.compare(o2.getValue().getName(),o1.getValue().getName());
            }
        });
​
        LinkedHashMap<Integer, Demo01> hashmap1 = new LinkedHashMap<>();
        for (Map.Entry<Integer,Demo01> entry1 : list1){
            hashmap1.put(entry1.getKey(),entry1.getValue());
        }
        return hashmap1;
    }
​
​
​
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值