简述Java集合

本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。

简述

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象操作,就进行了对对象存储,集合是存储对象最常用的一种方式。而数组和集合类同是容器,有什么不同呢?
数组虽然可以存储对象,但长度是固定的,集合长度可变,并且数组可以存储基本数据类型对象,而集合只能存储对象
我们可以看一下Java当中的集合对象
在这里插入图片描述

public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("java01");
        arrayList.add("java02");
        arrayList.add("java03");
        arrayList.add("java04");
        System.out.println(arrayList.size());
        System.out.println(arrayList);
    }

打印结果:
在这里插入图片描述
我们如何像操作数据一样操作集合呢?Java中为我们提供了迭代器,其实就是取出集合元素的方式。

public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("java01");
        arrayList.add("java02");
        arrayList.add("java03");
        arrayList.add("java04");

        // 写法一
        /*       
        Iterator iterable =  arrayList.iterator();
        while (iterable.hasNext()) {
            System.out.println(iterable.next());
        }
        */
        // 写法二,推荐使用这种方式,因为这种方式节省内存,定义在局部变量在执行完就释放了,而while没有。
        for (Iterator iterator1 = arrayList.iterator();iterator1.hasNext();){
            System.out.println(iterator1.next());
        }
    }

List

List:元素是有序的,元素可以重复,因为该集合体系有索引(凡是可以操作角标的方法都是该体系特有的方法)。
Set:元素是无序的,元素不可以重复。

public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("java01");
        arrayList.add("java02");
        arrayList.add("java03");
        arrayList.add("java04");

        for(Iterator iterator = arrayList.iterator();iterator.hasNext();) {
            Object object = iterator.next();
            if (object.equals("java02")) {
                arrayList.add("java05");
            }
        }
    }

在这里插入图片描述
此时我们发现上面的代码发生了异常,因为在迭代时,通过集合对象操作集合中的元素时,会发生ConcurrentModificationException(并发修改异常),因为你修改了集合元素,但迭代器却不知道。

public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("java01");
        arrayList.add("java02");
        arrayList.add("java03");
        arrayList.add("java04");

        for(Iterator iterator = arrayList.iterator();iterator.hasNext();) {
            Object object = iterator.next();
            if ("java02".equals(object)) {
                iterator.remove();
            }
            System.out.println(object);
        }
        System.out.println(arrayList);
    }

在这里插入图片描述
此时会发现,结果依旧打印出了java02,而在集合中却被移除了,iterator.remover();将java02的引用从集合中删除了,但object 还存在这个引用。
List集合特有的迭代器,ListIterator是Iterator的子接口。在迭代时,不可以通过集合对象操作集合中的元素,因为会发生ConcurrentModificationException(并发修改异常)。所以在迭代器时,只能用迭代器的方式操作元素,因为Iterator方法是有限的,如果想要其他操作,如添加、修改等,就需要使用其子接口,ListIterator该接口只能通过List集合的ListIterator方法获取。

public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("java01");
        arrayList.add("java02");
        arrayList.add("java03");
        arrayList.add("java04");

        for(ListIterator iterator = arrayList.listIterator(); iterator.hasNext();) {
            Object object = iterator.next();
            if ("java04".equals(object)) {
                iterator.add("java05");
            }
            System.out.println(object);
        }
        System.out.println(arrayList);
    }

在这里插入图片描述
ArrayList:底层的数据结构使用的数组结构。
特点:查询速度很快,增删速度稍慢。(JDK1.2)线程不同步。

Vector

Vector:底层的数据结构使用的数组结构。(JDK1.0)线程同步,被ArrayList替代,不论查询还是增删,都很慢。

枚举是Vector特有的取值方式,发现枚举和迭代器很像,其实枚举和迭代是一样的,因为枚举的名称以及方法的名称过长,所以被迭代器给取代了。

public static void main(String[] args) {
        Vector vector = new Vector();
        vector.add("java01");
        vector.add("java02");
        vector.add("java03");
        vector.add("java04");

        for(Enumeration element = vector.elements(); element.hasMoreElements();) {
            System.out.println(element.nextElement());
        }
    }

在这里插入图片描述

LinkedList

LinkedList:底层用的是链表。特点:增删特点很快,查询速度很慢。
LinkedList特有的方法:

  • addFirst();
  • addLast();
  • getFirst();
  • getLast(); 获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
  • removeFirst();
  • removeLast(); 获取元素,并删除元素。如果集合中没有元素,会出现NoSuchElementException
  • 在JDK1.5版本中,出现了替代方法。
  • offerFirst();
  • offerLast();
  • peekFirst();
  • peekLast();
  • pollFirst();
  • pollLast(); 如果没有元素,会返回null。

Set

Set:集合是无序的(存入和取出的顺序不一致),元素是不可以重复的。
Set:集合的功能和Collection的是一致的。
常见子类:
HashSet:底层数据结构的哈希表,线程是非同步的。
TreeSet:底层数据结构是二叉树,可以对Set集合中的元素进行排序。
HashSet是如何保证元素的唯一性的呢?
是通过两个方法,hashCode和equals来完成的,如果元素的hashCode值相同,才回判断equals是否为true。如果元素的hashCode值不同,则不会调用equals。
注意,对于判断元素是否存在(contains),以及删除(remove)等操作,依赖的方法都是元素的hashCode和equals方法。

public static void main(String[] args) {
        Set set = new HashSet();
        set.add(111);
        set.add(2222);
        set.add(33333);
        set.add(444444);

        for(Iterator iterator = set.iterator();iterator.hasNext();) {
            System.out.println(iterator.next());
        }
    }

在这里插入图片描述

public class SetDemo
{
    public static void main(String[] args)
    {
        HashSet h = new HashSet();

        h.add(new Person("zhangsan", 21));
        h.add(new Person("lisi", 21));
        h.add(new Person("zhangsan", 21));
        h.add(new Person("wangwu", 21));
        h.add(new Person("zhangsan", 21));

        for(Iterator it = h.iterator();it.hasNext();)
        {
            Person p = (Person)it.next();
            System.out.println(p.getAge() + "    " + p.getName());
        }
    }
}
class Person
{
    private String name;
    private int age;

    Person(){
    }

    Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public int getAge()
    {
        return age;
    }

    public int hashCode()
    {
        return name.hashCode() + age * 37;
    }

    public boolean equals(Object obj)
    {
        if(!(obj instanceof Person))
            return false;

        Person p = (Person)obj;
        return p.getName().equals(this.getName()) && p.getAge() == this.getAge();
    }
}

在这里插入图片描述
TreeSet:底层数据结构是二叉树,可以对Set集合中的元素进行排序。
保证元素唯一性的依据是compareTo方法。
TreeSet排序的第一方式:让元素自身具有比较性。元素需要实现Comparable接口,重写compareTo方法,这种方式也称为元素的自然排序,或者叫做默认排序。注意:排序时,当主要条件相同时,一定要判定次要条件。
在这里插入图片描述
TreeSet练习
往TreeSet集合中存储自定义对象学生,按照学生的年龄进行排序。

public class SetDemo
{
    public static void main(String[] args)
    {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Student("zhangsan", 19));
        treeSet.add(new Student("zhangsan", 50));
        treeSet.add(new Student("lisi", 22));
        treeSet.add(new Student("lisi", 40));
        for(Iterator iterator = treeSet.iterator();iterator.hasNext();) {
            System.out.println(iterator.next());
        }
    }
}

class Student implements Comparable {

    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        if (!(o instanceof Student)) {
            throw new RuntimeException("不是学生对象!");
        }
        Student student = (Student)o;
        if (this.age > (student.getAge())) {
            return 1;
        } if (this.age == student.age) {
            return this.name.compareTo(student.name);
        }
        return -1;
    }
}

在这里插入图片描述
TreeSet排序的第二种方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让集合具备比较性。在集合初始化就有了比较方式。这时就需要定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
注意:当两种排序都在存在时,以外部比较器为主。

public class SetDemo
{
    public static void main(String[] args)
    {
        TreeSet treeSet = new TreeSet(new MyCompare());
        treeSet.add(new Student("zhangsan", 19));
        treeSet.add(new Student("zhangsan", 50));
        treeSet.add(new Student("lisi", 22));
        treeSet.add(new Student("lisi", 40));

        for(Iterator iterator = treeSet.iterator();iterator.hasNext();) {
            System.out.println(iterator.next());
        }
    }
}

class Student implements Comparable{

    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        if (!(o instanceof Student)) {
            throw new RuntimeException("不是学生对象!");
        }
        Student student = (Student)o;
        if (this.age > (student.getAge())) {
            return 1;
        } if (this.age == student.age) {
            return this.name.compareTo(student.name);
        }
        return -1;
    }
}

class MyCompare implements Comparator {

    @Override
    public int compare(Object o1, Object o2) {
        Student student1 = (Student)o1;
        Student student2 = (Student)o2;


        int num = student1.getAge() - student2.getAge();
        if (num == 0) {
            return student1.getName().compareTo(student2.getName());
        }
        return num;
    }
}

在这里插入图片描述
Map集合
我们接下来说一说集合中的另一个接口Map。Map集合存储着键值对,一对一对往里存,并且还要保证键的唯一性。该集合不用迭代器进行取出元素。
Map集合的常见子类:

  1. HashTable:底层使用的是哈希表数据结构,不可以存入null键或null值(当key或者value为null时,运行时会抛出NullPointerException),线程同步(jdk1.0)。
  2. HashMap:底层使用的是哈希表数据结构,允许存入null值或null值,线程不同步(jdk1.2)。
  3. TreeMap:底层使用的二叉树,线程不同步。可以用于对Map集合中的键进行排序。

我们可以发现,该集合和Set集合很像,其实Set底层就是使用了Map集合。
Map集合常用的方法:
put(K key, V value);如果添加时,出现相同的键,那么后添加的值会覆盖原有键对应值。并返回覆盖那个值。
clear();删除集合里所有的元素。
remove();根据key值删除某一元素。
boolean containsKey(Object value);
boolean containskey(Object key);
boolean isEmpty();
get(Object key):可以通过get方法返回值来判断一个键是否已经存在,通过返回的null判断。
value();用来获取Map集合中所有的值。
Map集合的两种取出方法:
entrySet():将Map集合中的映射关系存入到set集合中,而这个关系的数据类型就是:Map.Entry.
keySet():将Map中所有的键都存入到Set集合,因为Set具备迭代器,所有可以用迭代的方式取出所有的键,如果使用get方法,获取的是每一个键对应的值。
keySet()用例

public static void main(String[] args) {
        HashMap map = new HashMap<String, String>();

        map.put("1", "张三");
        map.put("2", "李四");
        map.put("3", "王五");
        map.put("4", "刘六");

        // 先获取map集合中所有键的集合
        Set<String> keySet = map.keySet();
        // 有了Set集合,就可以获取其迭代器
        for(Iterator<String> iterator = keySet.iterator();iterator.hasNext();) {
            String key = iterator.next();
            System.out.println("key:" + key + "value:" + map.get(key));
        }
        System.out.println("---------------------------------");
        for(String key : keySet) {
            System.out.println("key:" + key + "value:" + map.get(key));
        }
    }

打印结果:
在这里插入图片描述
我们可以通过下图来简单了解一下keySet取值方式
在这里插入图片描述
entrySet用例
public static void c(String[] args) {
HashMap map = new HashMap<String, String>();

    map.put("1", "张三");
    map.put("2", "李四");
    map.put("3", "王五");
    map.put("4", "刘六");

    // 将Map集合中的映射关系取出,存入Set集合中。
    Set<Map.Entry<String, String>> entrySet = map.entrySet();
    for(Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();iterator.hasNext();) {
        Map.Entry<String, String> entry = iterator.next();
        System.out.println(entry.getKey() + entry.getValue());
    }
}

在这里插入图片描述
我们可以通过下图来简单了解一下entry取值的方式
在这里插入图片描述
HashMap练习

每一个学生都有对应的归属地
学生Student,地址String
学生属性:姓名,年龄
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。

  1、描述学生
  2、定义Map容器,将学生作为键,地址作为值,存入。
  3、获取Map集合中的元素。
public class Demo1 {
    public static void main(String[] args) {
        HashMap<Student, String> map = new HashMap();
        map.put(new Student("阿波罗", 6782), "大地之神");
        map.put(new Student("阿瑞斯", 2000), "火星");
        map.put(new Student("阿迪斯", 899), "冥王星");
        map.put(new Student("阿波罗", 6782), "太阳星");

        // 使用keySet方式取出
        Set<Student> set = map.keySet();
        for(Student key : set) {
            System.out.println(key + ":" + map.get(key));
        }
        System.out.println("-----------------------------------");
        // 使用entrySet方式取出
        Set<Map.Entry<Student, String>> entries = map.entrySet();
        for(Iterator<Map.Entry<Student, String>> iterator = entries.iterator();iterator.hasNext();) {
            Map.Entry entry = iterator.next();
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }

    }
}

class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

TreeMap练习

获取字符串中每个字母出现的次数

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入字符串");
        String str = scanner.nextLine();
        char[] chars = str.toCharArray();
        TreeMap<Character, Integer> treeMap = new TreeMap<>();
        Set<Character> set = treeMap.keySet();
        for(char ch : chars) {
            if (set.contains(ch)) {
                int count = treeMap.get(ch);
                treeMap.put(ch, ++count);
            } else {
                treeMap.put(ch, 1);
            }
        }

        for(char ch : set) {
            System.out.print(ch + "(" + treeMap.get(ch) + ")");
        }
    }

Collections工具类
我们来看看Collections和Collection的区别:
Collections是不属于java的集合框架,它是集合类的一个工具类/帮助类。此类不能被实例化,此类是服务于Collection框架。
Collection是基本的集合接口,继承它的接口有List、Set。
例如:当我们要创建一个集合且该集合中的元素并不保证唯一性,我们会选择List集合,但又对该集合中的元素进行排序,却发现List集合不能对元素排序。(TreeSet集合可以对元素进行排序,但不能存在重复数据)。于是java提供了集合框架的工具类。
该类中的方法都是静态
sort(List<T> list):根据元素的自然顺序 对指定列表按升序进行排序。
addAll(Collection<? super T> c, T... elements):向目标集合添加若干元素。
binarySearch(List<? extends Comparable<? super T>> list, T key) 使用二分搜索法搜索指定列表,以获得指定对象的下标。

public class TreeMapDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        Collections.addAll(list, "aa", "z", "ggg", "qq", "ssss", "lllll", "ssss", "ggg", "asss");
        // 如果自己不定义比较器,会默认按照字母升序
        Collections.sort(list, new MyCompare());
        // 使用二分法找到该元素的下标,注意,使用该方法查找的集合,必须是有序集合,即得先用sort方法排序
        System.out.println(Collections.binarySearch(list, "ggg"));
        System.out.println(list);
    }
}
class MyCompare implements Comparator<String> {
    @Override
    public int compare(String str1, String str2) {
        if(str1.length() == str2.length()) {
            return 0;
        }
        return str1.length() > str2.length() ? 1:-1;
    }
}

4
[z, aa, qq, ggg, ggg, ssss, ssss, asss, lllll]

fill(List<? super T> list, T obj) 使用指定元素替换指定列表中的所有元素。
replaceAll(List<T> list, T oldVal, T newVal) 使用另一个值替换列表中出现的所有某一指定值。
reverse(List<?> list) 反转指定列表中元素的顺序。
reverseOrder() 返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值