【Java_Senior】四、集合

集合

集合与数组都是对多个Java对象进行操作的容器
现在的存储都是只涉及内存层面的,不涉及硬盘也就是说没有持久化,不能保存数据。

数组的特点与缺点:

  1. 数组一旦初始化、其长度就不可更改(缺点)
  2. 数组的类型在初始化时就确定了,不能存储非其类型的数据(中性特点)
  3. 数组定义的操作(属性、方法)相当少,尤其对于增加、删除效率很低(缺点)
  4. 没有提供具体的存放了多少数据的接口(length是长度,不是存储数据的个数)(缺点)
  5. 数组中数据有序、可重复,对于需要无序或要求不能重复的需求没有对应的实现接口(缺点)

Collection

Collection 单列对象:存储一个一个的数据对象
List:有序的,可重复的数据。类似于数组但可以增加长度(动态数组)
Set:无序的,不可重复的数据

ArrayList():一个Collection接口的实现类(线性表)。
LinkList():链表
Vector():

.add():向集合中添加一个元素。
.size():集合的大小。
.clear():清空集合中的元素。
.isEmpty():判断集合是否为空,为空则返回true、不为空返回false。

    @Test
    public void test(){
        Collection coll = new ArrayList();
        coll.add("AA");
        coll.add(new Date());
        coll.add(567);
        coll.add("Yao");
        coll.add("MING");
        System.out.println(coll.size());

        Collection coll1 = new ArrayList();
        coll1.add("Li");
        coll1.add("Ning");
        coll1.addAll(coll);
        System.out.println(coll1.size());
        System.out.println(coll1.toString());
        coll.clear();
        System.out.println(coll.isEmpty());
        /*
        5
        7
        [Li, Ning, AA, Wed Aug 31 00:01:19 CST 2022, 567, Yao, MING]
        true
         */
    }

.contains(Object o);判断o在不在该集合中,内层是遍历集合并调用equals()方法判断,若对象中重写过equals()方法(例如String重写过equals方法变成判断内容是否相等),则调用equals()方法,若没有重写过,则调用Object中的equals()方法,就是"=="就变成了比较地址

equals()方法的重写可以直接通过编辑器生成。

    public void test(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);    //bool类型的包装类、Boolean
        coll.add(new Date());
        coll.add(new String("Yao Ming"));
        Person p = new Person("孔子", 564);
        coll.add(p);

        System.out.println(coll.contains(123));
        System.out.println(coll.contains(new String("Yao Ming")));
        System.out.println(coll.contains((new Person("孔子", 564))));

        /*
        true
        true
        false
        */
    }

.containsAll(Collection col);
判断col中的元素是否都在该集合中

.remove(Object o)方法从集合中移除某个元素,会先调用equals()方法判断该元素是否在集合中,所以若有自定义类,则重写equals()方法的环节很重要
.removeAll(Collecton col)方法从集合中移除另一个集合中的所有元素,即另一个集合中有的元素都会在原集合中被移除,这时候也会调用equals()方法。

colT.retainAll(Collection col);计算colT与col的交集并存入colT中

equals()判断对象元素是否相等,注意ArraysList还需要元素的存储顺序也相等

.hashcode()返回对象的哈希值。

.toArray()集合–>数组
Object[] o = col.toArray();

调用Arrays中的静态方法.asList()可以使数组转换为集合
List<String> list = Arrays.asList(new String[]{"AA", "BB"});,若存基本数据类型,则必须存储对应的包装类

使用Iterator接口实现对集合的遍历

Iterator(迭代器)

    public void test(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);    //bool类型的包装类、Boolean
        coll.add(new Date());
        coll.add(new String("Yao Ming"));
        Person p = new Person("孔子", 564);
        coll.add(p);

        //创建一个接口
        Iterator iterator = coll.iterator();
//        System.out.println(iterator.next());    //若超出范围则抛异常

        //常用遍历方法
        while(iterator.hasNext()){              //hasNest()方法判断该元素后是否还有元素,若还有则返回true,没有元素了就返回false
            System.out.println(iterator.next());
        }
    }

调用.next()方法会使指针下移、hasNext()方法单纯判断一下是否后面还有元素。

必须显示声明Iterator iterator,不能匿名,要不然指针不会下移,每次循环都是新的Iterator迭代器

iterator.remove()迭代器也可以调用remove()方法,用来删除集合中的元素,注意要先.next()获取到元素才可以进行删除。

        Iterator iterator = coll.iterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            if(o.equals("Yao Ming")){
                iterator.remove();
            }
        }

foreach循环遍历集合元素

增强for循环

        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);    //bool类型的包装类、Boolean
        coll.add(new Date());
        coll.add(new String("Yao Ming"));
        Person p = new Person("孔子", 564);
        coll.add(p);


        //内部仍然调用了迭代器
        for(Object o : coll){
            System.out.println(o);
        }

List接口

都存储有序的、可重复的数据。

  1. ArrayList
    顺序表,线程不安全,故高效
  2. LinkedList
    双向链表,利于插入删除
  3. Vector(不常用)
    古老的线性表,线性安全,低效

ArrayList:
初始给10个地址,不够的话进行扩容,默认扩容为原来的1.5倍,并将原先的赋值过来(复制一份加过来),若还不够则直接将需要的大小复制过来,若超过对应元素的数据类型最大值,则抛出异常。
list.add[123]; //element[0] = new Integer(123);

为了避免多次扩容,建议使用带参构造器new ArrayList(int initialCapacity)指定初始化集合的大小。

在JDK7中,ArrayList list = new ArrayList()会创建长度为10的Object[] element;
而在JDK8中,不会在ArrayList list = new ArrayList()时创建数组,而是会在初次调用add方法时才创建,延迟了数组对象的创建时间,减少内存的占用时间。

List常用方法

void add(int index, Object ele);向索引为index位置上插入ele。
boolean addAll(int index, Collection col);向索引为index的位置上插入连续多个元素,这些元素在col中。
Object get(int index);返回index中的元素
int indexOf(Object obj);返回对象obj在集合中首次出现的位置(索引),若不存在则返回-1。
int lastIndexOf(Object obj);返回对象obj在集合中最后一次出现的位置(索引),若不存在则返回-1。
Object remove(int index);按索引删除,也有重载方法按内容删除,返回被删除的内容。
.set(int index, Object obj);将索引为index位置的元素替换为obj。
.subList(int fromIndex, int toIndex); 返回索引位置从fromIndex到toIndex位置上的所有对象的子集合。

Set接口

无序的、不可重复的

  1. HashSet:Set接口的主要实现类,线程不安全,可以存储null值
  2. LinkedHashSet:HashSet的子类,假装有序,可以按照添加元素的顺序进行遍历
  3. TreeSet:底层为红黑树的存储,要求放入TreeSet中的对象必须为相同对象,可以按照添加对象的指定属性进行排序

Set中没有定义新的方法,其方法都是Collection中继承而来(因为其不具有索引)

HashSet

HashSet底层其实也是数组存储,但其中元素不是按数组索引顺序存储的,按照(Hash算法)(散列表)进行存储。
保证添加的元素在添加时不能返回true(调用equals()方法),即相同元素只能添加一次
若要添加元素a,则先调用hashCode()方法计算元素的hash值,再通过hash值决定(散列函数)元素在数组中的存放位置,若hash值相同,则调用equals方法判断是否相等(不用一直调equals()方法,效率高),若再相等,则添加失败,否则添加成功,以链表形式加到那个数组索引位置的后面。(原先的元素在数组中,指向a)

其初始容量为16,底层为数组+链表。

向Set中添加的类必须重写equals方法和hashCode方法,相等的对象要有相同的hash值。

hashSet底层就是实现的hashMap

LinkedHashSet

HashSet的子类,添加数据的同时维护了每个数据的双向指针,但底层还是以HashSet的形式存储在数组中,给每个数据增加了双向链表类似的指针

遍历操作会比HashSet更高

TreeSet

TreeSet是为了排序而提供的表。故:
TreeSet中添加的对象必须是相同类的对象,不能是不同类的对象,否则不能进行比较。
其底层为红黑树。

自然排序:
TreeSet的输出会自动在底层进行排序,其会调用类中的CompareTo()方法,若没有重写CompareTo()方法则会抛出异常,注:在相等时,也需要另外的判断。

定制排序:
调用TreeSet(Comparator com)的带参构造器,需要重写Compare()方法

Map

Map 双列对象:存储一对一对的数据(key - value)

key是无序、不可重复的,使用Set存储,自定义类必须重写equals()和hashCode()方法。

注:hashCode()方法会生成一串数字、有相同内容的数据会有相同的hashCode值,可以便捷的进行插入操作,不同hashCode的元素必然不同,减少equals()的比较。

value是有序的、可重复的,使用Collection存储。要重写equals()方法。
Entry:一个键-值对构成了一个Entry,Entry也是无序的

HashMap(线程不安全、效率高)

Hashtable作为Map的古老实现类,其不能存储null,null会被认为是空指针。
数组+链表+红黑树

HashMap map = new HashMap();在创建对象之后,底层会存储一个长度为16的Entry[]数组。

  1. 每次put(key、value)会首先计算key的hashcode值、再通过该hashCode值计算(散列函数)出这个元素的存储位置。
  2. 若hashCode值对应的位置没有元素、则直接存储。
  3. 若hashCode值对应的位置存在元素、则先比较hashCode的值、若hashCode值不相等(两元素内容一定不同)则存储、若相等,则调用equals()方法比较、若equals()不相等、则存储成功、否则则会将表中原有的key对应的value修改成这个value(修改功能)。

扩容:扩容为原先的2倍并将原先的数据复制过来

JDK8中的修改:

  1. new HashMap()时没有创建长度为16的数组。
  2. 在首次调用put()方法是才创建数组
  3. 数组不再是Entry[], 而是Node[]
  4. 底层增加了红黑树、在数组长度 > 64且某一个索引位置上的元素数量 > 8时会将那个索引位置上的元素以红黑树的方式进行存储。

扩容机制不是在无法存储更多元素时才进行扩容,有一个负载因子,由负载因子和当前长度计算出临界值,超过临界值、且生成新的链表时(新存储的位置原先有一个元素,在那个索引生成了一个新的链表、这样会使查找效率降低)就会进行扩容

hash值的计算中有调用hashCode().

默认加载因子:0.75.

List只会在存储满后进行扩容,Map会在扩容临界值达到时扩容。

LinkedHashMap

假装有序的HashMap,结点为Entry[],Entry继承与Node,并新增了成员变量Before和After用于记录元素的添加顺序。

Map中的方法

  1. 新增(.put(Object key, Object Value))、修改(同key元素put一下)、删除(.remove(Object key))、
  2. map.size()返回Map中键值对的数量。.clear()将map中元素全部清除,但不是将map = null;不会在调用类似方法时有空指针异常。
  3. .containsKey(Object ksy)、.containsValue(Object Value)方法,判断Map中是否有该Key,是否有该Value

对增删改的测试

        HashMap map = new HashMap();
        //添加
        map.put("AA", 123);
        map.put("BB", 123);
        map.put("CC", 45);
        map.put(45, 123);
        //修改
        map.put("AA", 878);

        System.out.println(map);

        HashMap map1 = new HashMap();
        map1.put("59", 123);
        map1.put("555", 123);
        map.putAll(map1);

        System.out.println(map);

        map.remove("CC");
        System.out.println(map);

遍历涉及到的方法,Map属于键值对,不能直接使用迭代器。

  1. Key值的遍历
    使用KeySet()方法获取Set的对象,调用Set的迭代器(iterator)进行遍历
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
  1. Values值的遍历
    调用.values()方法获取一个Collection对象,其中存储Map中的所有value值,其顺序与.KeySet()方法得到的元素顺序相一致。
        Collection values = map.values();
        for(Object o : values){
            System.out.println(o);
        }
  1. Entry的遍历
    使用.entrySet()方法返回一个Set对象,其中以Entry形式存储map中所有的键值对,在经过迭代器和向下转型之后可以调用.getKey()与.getValue()方法获取具体的键值对。
        Set set = map.entrySet();   //存储的时一个个Entry
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            Map.Entry e =  (Map.Entry)iterator.next();      //iterator.next()返回的是一个Entry。
            System.out.println(e.getKey() + "--->" + e.getValue());
        }

Properties

Properties是Hashtable的子类,但一般使用Properties进行读取配置文件。

// jdbc.properties文件:
// 键值对形式,可以被Properties读取,不能有空格

name=QingHe
password=qh1234567

通过流与Properties对象实现对配置文件的读取:
.load();
.getProperties(String key);

        Properties pro = new Properties();
        FileInputStream fis = new FileInputStream("jdbc.properties");
        pro.load(fis);
        System.out.println(pro.getProperty("name"));

注:根据Properties读取的文件Key必须是String。

Collections工具类

Collections是用来操作List、Set和Map的工具类,其中提供了便利的方法。

排序操作:(均为static方法)

  1. reverse(List):反转 List 中元素的顺序
  2. shuffle(List):对 List 集合元素进行随机排序
  3. sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
  4. sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序(定制排序)
  5. swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

查找、替换

  1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素

  2. Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素

  3. Object min(Collection)

  4. Object min(Collection,Comparator)

  5. int frequency(Collection,Object):返回指定集合中指定元素的出现次数

  6. void copy(List dest,List src):将src中的内容复制到dest中(要求dest长度必须大于等于src长度)

    //标准写法,直接创建list会导致list长度过小
         List list1 = Arrays.asList(new Object[list.size()]);
         Collections.copy(list, list1);
         System.out.println(list1);
    
  7. boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换
    List 对象的所有旧值

线程安全:
使用对应的.synchronizedXxx()方法,返回一个线程安全的对应对象。

List list2 = Collections.synchronizedList(list);    //此时list2即为线程安全的ArrayList(线性表)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值