集合框架和泛型编程

Java集合框架

  • 一组存储对象的容器(动态)

常见的集合算法

  • 遍历集合
  • 添加集合元素
  • 删除集合元素
  • 查找集合元素
  • 集合元素排序

Java SE提供了:

  • Collection接口:存储另一个元素的集合
  • Map接口(图):存储键/值对
  • Collection:操作集合的工具类

注意

List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素索引来访问

Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)

集合框架包含内容

  • Set(规则集)
  • List(线性表)
  • Queue(队列)
  • Map(图)

Collection接口

方法 描述 boolean add(E e); / int size(); 向集合中添加元素e / 返回集合中的元素个数 boolean addAll(Collection c); 将集合c 中的所有元素添加到当前这个集合 boolean contains(Object o); 如果该集合中包含对象o,返回true boolean containsAll(Collection c); 如果该集合中包含集合c的所有元素,返回true boolean isEmpty(); / void clear(); 如果集合不包含任何元素,返回true / 删除集合中所有元素 Iterator iterator(); 返回集合中元素所用的迭代器 boolean remove(Object o); 从集合中删除元素o boolean removeAll(Collection c); 从集合中删除集合c拥有的所有元素 boolean retainAll(Collection c); 保留c和当前集合都有的元素(交集) Object[] toArray(); 返回该集合元素构成的Object数组

迭代器Iterator和ListIterator

  • 相同点:都是迭代器,当需要对集合中的元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用
  • 不同点:

    1. 使用范围不同,Iterator可以应用于所有集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型
    2. ListIterator有add方法,可以向list中增加对象。Iterator不可以
    3. Iterator和ListIterator都有hasNext()和next()方法,可以向后顺序遍历;ListIterator有hasPrevious()和previous()方法,可以逆向(顺序向前)遍历,Iterator不可以
    4. ListIterator可以定位当前索引位置,nextIndex()和previousIndex()可以实现,Iterator没有此功能
    5. 都可以实现删除操作,但ListIterator可以利用set()方法实现对象修改,Iterator不可以
  • hasNext():如果迭代器指向位置后面还有元素,则返回true,否则返回false

  • next():返回集合中Iterator指向位置后面的元素
  • remove():删除集合中Iterator指向位置后面的元素

  • add(E e):将指定元素插入列表,插入位置为迭代器当前位置之前

  • hasNext():以正向遍历列表时,如果列表迭代器后面还有元素,则返回true,否则返回false
  • hasPrevious():以逆向遍历列表时,如果列表迭代器前面还有元素,则返回true,否则返回false
  • next():返回列表中ListIterator指向位置后面的元素
  • nextIndex():返回列表中ListIterator当前位置后面的元素索引
  • previous():返回列表中ListIterator指向位置前面的元素
  • previousIndex():返回列表中ListIterator指向位置前面的元素索引
  • remove():删除列表中next()或previous()返回的最后一个元素
  • set(E e):从列表中将next()或previous()返回的最后一个元素返回的最后一个元素更改为指定元素e

List接口的实现类

  • 是一个大小可变的数组,在内存中分配连续空间
  • 遍历元素和随机访问元素的效率比较高
  • 在一列数据后面添加数据而不是在中间或前面,并且需要随机访问其中的元素时,使用ArrayList性能更好

  • 采用链表存储方式

  • 提供从线性两端提取,插入和删除元素的方法
  • 插入,删除元素效率比较高
  • 在一列数据前面或中间添加数据而且需要按照顺序访问其中的元素时,使用LinkedList性能更好
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

public abstract class ListDemo {
    public static void main(String[] args) {
        List arrayList = new ArrayList();
        arrayList.add(1);   arrayList.add(3);   arrayList.add(4);
        arrayList.add(1);   arrayList.add(2);
        arrayList.add(0,10);
        arrayList.add(3,30);
        System.out.println(arrayList);

        LinkedList linkedList = new LinkedList(arrayList);
        linkedList.add(1,"red");
        linkedList.removeFirst();
        linkedList.addFirst("green");
        ListIterator listIt = linkedList.listIterator();
        while(listIt.hasNext()) {
            System.out.print(listIt.next() + ";");
        }
        System.out.println();

        listIt = linkedList.listIterator(linkedList.size());
        System.out.println("倒序访问:");
        while(listIt.hasPrevious()) {
            System.out.print(listIt.previous() + ";");
        }

        LinkedList list = new LinkedList();
        System.out.println();
        list.add("哈哈");
        list.add("嘻嘻");
        list.add("呵呵");
        System.out.println(list);
    }
}

打印结果:

[10, 1, 3, 30, 4, 1, 2]
green;red;1;3;30;4;1;2;
倒序访问:
2;1;4;30;3;1;red;green;
[哈哈, 嘻嘻, 呵呵]

实现原理相同,功能相同,很多情况可以互用

  • Vector线性安全,ArrayList重速度轻安全,线性非安全
  • 长度需增长时,Vector默认增长一倍;ArrayList增长50%,有利于节约空间
  • 不需要同步最好使用ArrayList,因为速度快

Set接口和实现类

Set接口:用来操作存储一组唯一、无序的对象

  • HashSet:用来存储互不相同的任何元素
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * HashSet集合的使用
 * @author
 * @version
 * @data
 */
public class SetDemo {

    public static void main(String[] args) {
        Set set1 = new HashSet();
        set1.add("London");
        set1.add("Paris");
        set1.add("New York");
        set1.add("San Francisco");
        set1.add("Beijing");
        set1.add("New York");//set是无序集合,不可以有重复的元素

        System.out.println(set1);

        Iterator it = set1.iterator();//迭代器遍历
        while(it.hasNext()) {
            System.out.print(it.next() + "; ");
        }

        System.out.println();
        Set set2 = new HashSet();
        set2.add("Paris");
        set2.add("广东");
        set2.add("广西");
        set2.add("上海");
        set2.add("New York");
        set1.removeAll(set2);//在set1中移除set2的所有元素
        set1.retainAll(set2);//在set1中保留set2的所有元素
        System.out.println(set1);
    }

}
  • LinkedHashSet:使用链表扩展实现HashSet类,支持对元素的排序
  • 注意:若不需要维护元素插入的顺序,建议使用HashSet更加高效
  • TreeSet:可以确保所有元素都是有序的
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

/**
 * TreeSet集合使用
 * @author
 * @version
 * @data
 */
public class TreeSetDemo {

    public static void main(String[] args) {
        /**
         * 当更新一个规则集时,如果不需要保持元素的排序关系,就应该使用散列集
         * 因为在散列集中插入,删除元素所花的时间比较少
         * 当需要一个排好序的集合时,可以从这个散列集创建一个树形集
         */
        Set set1 = new HashSet();
        set1.add("London");
        set1.add("Paris");
        set1.add("San Francisco");
        set1.add("Beijing");
        set1.add("New York");

        TreeSet treeSet = new TreeSet(set1);//会自动按照字母顺序排序
        System.out.println("排序:" + treeSet);
        /**
         * 方法first和last:返回第一个和最后一个元素
         * headSet(toElement)和tailSet(fromElement):返回Set中小于element的元素;返回Set中大于等于element的元素
         */
        System.out.println("首元素:" + treeSet.first());
        System.out.println("尾元素:" + treeSet.last());
        System.out.println("New York之前的元素:" + treeSet.headSet("New York"));
        System.out.println("New York之后的元素:" + treeSet.tailSet("New York",false));

        /**
         * lower(e),floor(e),ceiling(e)和higher(e):分别返回小于、小于等于、大于等于、大于一个给定的元素,若没有这个元素,返回null
         */
        System.out.println(treeSet.lower("P"));//返回集合中小于P的最大元素
        System.out.println(treeSet.higher("P"));//返回集合中大于P的最小元素
        System.out.println(treeSet.floor("P"));//返回集合中小于等于P的最大元素
        System.out.println(treeSet.ceiling("P"));//返回集合中大于等于P的最小元素

        /**
         * pollFirst():删除并返回集合中的第一个元素
         * pollLast():删除并返回集合中最后一个元素
         */
        System.out.println("删除前:" + treeSet);
        System.out.println("删除第一个元素:" + treeSet.pollFirst());//删除并返回集合中第一个元素
        System.out.println("删除最后一个元素:" + treeSet.pollLast());//删除并返回集合中最后一个元素
        System.out.println("删除后:" + treeSet);

    }

}

Set和List的运行性能对比
– 规则集比线性表更加高效,若应用程序使用规则集足够,那么就用规则集
– 若程序不需要特别的顺序,就用散列集
– 若线性表中除了结尾之外的任意位置上进行插入或删除操作,链式线性表会比数组线性表更加有效

Comparable 接口

  • 需要排序的元素必须实现该接口
  • 集合中的元素本身能够实现比较

Comparator 接口

  • 自定义比较器实现该接口
  • 集合中的元素本身不能实现排序
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.Comparator;

public class CompareDemo {
    static final int N = 50000;
    public static void main(String[] args) {

        Set hashSet = new HashSet();

        hashSet.add(new Student(5,"曹冲"));
        hashSet.add(new Student(1,"曹操"));
        hashSet.add(new Student(3,"曹丕"));
        hashSet.add(new Student(2,"曹仁"));
        hashSet.add(new Student(4,"曹植"));

        System.out.println("排序前:" + hashSet);

        Set treeSet = new TreeSet(new StudentComparator());
        treeSet.addAll(hashSet);
        treeSet.add(new Student(6,"关羽"));
        System.out.println("排序后:" + treeSet);

    }

}

public class Student {
    private int id;
    private String name;

    public Student(int id, String name) {
        setId(id);
        setName(name);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return id + "-" + name;
    }
}

/**
 * 定义一个比较类,实现Comparator接口
 * @author
 * @version
 * @data
 */
public class StudentComparator implements Comparator{
    @Override
    public int compare(Student o1, Student o2) {
        if(o1.getId() == o2.getId()) {
            return 0;
        }
        if(o1.getId() < o2.getId()) {
            return -1;
        }
        return 1;
    }
}

java.util.Collection 工具类

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class CollectionDemo {

    public static void main(String[] args) {

        List list = Arrays.asList("are","you","ok");
        Collections.sort(list);//对指定列表进行排序
        System.out.println(list);

        Collections.sort(list, Collections.reverseOrder());//使用指定比较器进行排序,reverseOrder():返回逆序的比较器
        System.out.println(list);

        int index = Collections.binarySearch(list, "ok");//使用二分查找法搜索有序列表的键值
        System.out.println(index);

        Collections.shuffle(list);//随机打乱顺序
        Collections.shuffle(list,new Random(20));//使用随机对象打乱指定列表
        System.out.println(list);

        List list2 = Arrays.asList("my","name","is","cai");
        Collections.copy(list2, list);//复制list给list2
        System.out.println(list);
        System.out.println(list2);

        Collections.fill(list, "abc");//使用对象填充列表
        System.out.println("list:" + list);
        System.out.println("list2" + list2);

        System.out.println("没有相同的元素:" + Collections.disjoint(list, list2));//若没有公共元素返回true

        System.out.println("abc出现次数" + Collections.frequency(list, "abc"));//返回集合中指定元素出现的次数

    }

}

打印结果:

[are, ok, you]
[you, ok, are]
1
[ok, you, are]
[ok, you, are]
[ok, you, are, cai]
list:[abc, abc, abc]
list2[ok, you, are, cai]
没有相同的元素:true
abc出现次数3

支持队列操作的Queue

  • Queue通常用于操作存储一组队列方式的对象信息
  • 一般存储方式为先进先出(FIFO)方法 描述 boolean offer(element) 向队列中插入一个元素(类似于add方法) E poll() 获取并删除队列头元素,如果队列为空返回null E remove() 获取并删除队列头元素,若为空抛出异常 E peek() 获取但不删除队列头元素,如果队列为空返回null E element() 获取并删除队列头元素,若为空抛出异常

图(Map)

  • 以键 – 值存储元素的容器
  • 根据关键字(key)找到对应数据
  • 主要存储键值对,根据键得到值,不允许重复(重复就覆盖),但允许值重复
  • HashMap是最常用的Map,HashMap最多只允许一条记录的键为null;允许多条记录值为null
  • HashMap不支持线程同步,所以任一时刻可以有多个线程同时写HashMap,但可能导致数据不一致方法 描述 V put(key, value) 将一个键/值映射放入图中 V get(key) 根据键获取对应的value值 Set keySet() 返回包含键的规则集 Collection values 返回包含值的集合 boolean containsKey(key) 返回图中是否包含键值key Set
  • 使用建议
  • 如果更新图时不需要保持图中元素的顺序,就使用HashMap
  • 如果需要保持图中元素的插入顺序和访问顺序,就使用LinkedHashMap
  • 如果需要使图按照键值排序,就使用TreeMap

Properties

  • 键值对集合
  • 通常用于保存字符串类型键值对
  • 更多用于读取属性文件方法 描述 String getProperty(key) 通过指定的键(key)获取配置文件中对应的值(value) Object setProperty(key, value) 通过调用父类的put方法来设置键-值对 void load(instream) 从输入流读取属性列表 void store(outStream, comments) 将属性列表(键值对)写入到对应的配置文件中 void clear() 清除所有的键值对

泛型编程

泛型类就是具有一个或多个类型变量的类

  • 泛型
  • 指参数化类型的能力
  • 可以定义带泛型类型的类或方法,随后编译器会用具体的类型来替换它 注意
  • 指定类型后,添加其他类型的元素就会编译错误
  • 泛型类型必须是引用类型,不能是基本类型
  • 添加基本类型时,Java会自动打包
public class Main {

    public static void main(String[] args) {
        Holder holder = new Holder(new Trunk());
        AutoMobile auto = holder.getA();//无需转类型
        auto.run();
    }

}

/**
 * 泛型类
 */
public class Holder {
    private T a;
    public Holder(T a) {
        this.a = a;
    }

    public T getA() {
        return a;
    }
    public void setA(T a) {
        this.a = a;
    }
}

abstract class AutoMobile {
    public abstract void run();
}
public class Car extends AutoMobile{
    @Override
    public void run() {
        System.out.println("小车在跑");
    }
}
public class Trunk extends AutoMobile{
    @Override
    public void run() {
        System.out.println("卡车在跑");
    }
}

打印结果:卡车在跑
  • 如果需要对多种类型进行相同的操作,建议使用泛型
  • 如果需要处理的数据是值类型,可以使用泛型避免装箱和拆箱带来的性能损耗
  • 使用泛型可以在应用程序编译时发现类型错误,增强程序的健壮性
  • 可以减少重复代码,使代码结构更加清晰

Original: https://www.cnblogs.com/Zhouge6/p/12262789.html
Author: 笔架山Code
Title: 集合框架和泛型编程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/573658/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球