7.JAVA容器


传送门


07 JAVA容器

1.容器概念

  如果并不知道程序运行会需要多少对象,或者需要更复杂方式存储对象,就需要使用Java集合框架。

2.容器API

  Java集合框架提供了一套性能优良、使用方便的接口和类,位于java.util包中。其中,Collection接口存放单一数据Map接口存放键值对(k-v)数据
在这里插入图片描述
Collection接口

  • 子接口

    • List

      • ArrayList
      • LinkedList
    • Set

      • HashSet
      • TreeSet
  • 迭代器

    • Iterator接口
    • Iterable接口
    • 增强for循环
  • 比较器:当存储某些元素的时候,需要对集合中的元素进行排序,此时需要比较器

    • 内部比较器:Comparable接口
    • 外部比较器:Comparator接口
  • 泛型

    • 泛型类
    • 泛型接口
    • 泛型方法
  • 数据结构

    • 数组
    • 链表
    • 哈希表
    • 红黑树

3.Collection接口

  集合作为容器应该具有(不一定全有)的功能:增删改查。Collection接口存储一组不唯一、无序的对象。集合的基本操作有:增加、删除、判断、取出。
在这里插入图片描述

/*
 * java集合框架:
 *   Collection:存放单一的值
 *       特点:
 *           1.可以存放不同类型的数据,而数组只能存放固定类型的数据
 *           2.当使用ArrayList子类实现的时候,初始化长度为10,当长度不够的时候使用grow方法自动进行扩容操作
 *
 *       api方法:
 *         增加:
 *           add:要求必须传入的参数为Object对象,因此,当写入基本数据类型的时候包含了自动拆箱和自动装箱的过程
 *           addAll:添加另一个集合的元素到此集合中
 *         删除:
 *           clear:只是清空集合中的元素,但是此集合对象并没有被回收
 *           remove:删除指定元素
 *           removeAll:从此集合中删除指定集合中包含的所有元素
 *           removeIf:从集合中删除给定预期的所有元素
 *         判断(查询数据):
 *           contains:判断集合中是否包含指定的元素值
 *           containsAll:判断此集合中是否包含另一个集合
 *           equals:比较两个集合的元素是否相等
 *           hashcode:返回集合中元素对应的hashcode
 *           isEmpty:判断集合是否为空
 *           retainAll:保留此列表中包含在指定集合中的元素
 *           size:返回当前集合的大小
 *        集合转数组的操作
 *           toArray:将当前集合转换为数组
 * */
package com.mashibing;

import java.util.ArrayList;
import java.util.Collection;


public class CollectionsDemo {
    public static void main(String[] args) {
        //新建可动态修改数组ArrayList
        Collection collection = new ArrayList();
        collection.add(1);
        //collection.add(new Integer(1));  上述步骤涉及自动装箱,将基本数据类型转换为包装类
        collection.add(true);
        collection.add("abc");
        System.out.println(collection);

        //在某个固定位置添加元素
        //需要先进行强制类型转换,因为add(int index, E element)不是Collection中的方法而是ArrayList中的方法
        ((ArrayList) collection).add(0,"mashibing");
        System.out.println(collection);

        Collection collection1 = new ArrayList();
        collection1.add('a');
        collection1.add('b');
        collection1.add('c');
        collection1.add('d');

        //添加另一个集合的元素到此集合中
        collection.addAll(collection1);
        System.out.println(collection);

        //清空元素
//        collection.clear();
//        System.out.println(collection);

        //判断某个元素是否包含在集合中
        System.out.println(collection.contains('a'));

        //判断此集合中是否包含另一个集合
        System.out.println(collection.containsAll(collection1));

        //判断集合是否为空
        System.out.println(collection.isEmpty());

        //删除指定元素
        collection.remove('a');
        System.out.println(collection);
        System.out.println(collection1);

        //保留此集合中包含在指定集合中的元素
        System.out.println(collection.retainAll(collection1));
        System.out.println(collection);

        //将集合转换为数组
        Object[] objects = collection.toArray();
        System.out.println(objects);

    }
}
[1, true, abc]
[mashibing, 1, true, abc]
[mashibing, 1, true, abc, a, b, c, d]
true
true
false
[mashibing, 1, true, abc, b, c, d]
[a, b, c, d]
true
[b, c, d]
[Ljava.lang.Object;@14ae5a5

4.Iterator接口

  所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的子类实例对象。Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。所有的集合类均未提供相应的遍历方法,而是把遍历交给迭代器完成。迭代器为集合而生,专门实现集合遍历。Iterator接口定义了如下方法

  • boolean hasNext();
    判断是否有元素没有被遍历

  • Object next();
    返回游标当前位置的元素并将游标移动到下一个位置

  • remove();
    删除游标左面的元素,在执行完next之后该操作只能执行一次

/*
* 在java代码中包含三种循环的方式:
*   - do...while
*   - while
*   - for
* 还有一种增强for循环的方式,可以简化循环的编写
*
* 在所有的集合类都默认实现了Iterable的接口,实现此接口意味着具备了增强for循环的能力,也就是for-each
*   增强for循环本质上使用的也是iterator的功能
*       - iterator():返回迭代器
*       - forEach():对Iterable的每个元素执行给定操作,直到所有元素都被处理或者引发异常
* 在iterator的方法中,要求返回一个Iterator的接口子类实例对象,此接口中包含了
*       - hasNext():首先判断是否有值,如果有值则调用next()方法
*       - next()
* */
package com.mashibing;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorDemo {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);
        //for循环
        for (int i = 0;i < arrayList.size();i++) {
            System.out.println(arrayList.get(i));
        }

        //迭代器:iterator
        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        //增强for循环
        for (Object i : arrayList) {
            System.out.println(i);
        }
    }
}

其中,ArrayList类中iterator方法实现为:

public Iterator<E> iterator() {
        return new Itr();
    }
    
private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

其对应结构图为:
在这里插入图片描述

4.1 ListIterator

  在迭代时,不可能通过集合对象的方法(al.add(?))操作集合中的元素,会发生并发修改异常。所以,在迭代时只能通过迭代器的方法操作元素,但是Iterator的方法是有限的,只能进行判断(hasNext),取出(next),删除(remove)的操作。如果想要在迭代的过程中向集合中添加,修改元素等就需要使用在使用ListIterator接口中的方法
在这里插入图片描述

在这里插入图片描述

  • ListIterator迭代器提供了向前和向后的两种遍历方式。是通过cursor和lastret的指针来获取元素值及向下的遍历索引。当使用向前遍历的时候,必须保证指针在迭代器的结尾,否则,无法获取结果值。
package com.mashibing;

import java.util.ArrayList;
import java.util.ListIterator;


public class IteratorDemo {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);

        //迭代器:iterator
        ListIterator iterator = arrayList.listIterator();
        while (iterator.hasNext()) {
            Object o = iterator.next();
            //删除数组中的元素
            if (o.equals(1)) {
                iterator.remove();
            }
            System.out.println(o);
        }

        System.out.println("------------------");
        //增强循环
        for (Object o : arrayList) {
            System.out.println(o);
        }

        System.out.println("------------------");
        //从后往前遍历
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previous());
        }
    }
}
1
2
3
4
------------------
2
3
4
------------------
4
3
2

4.2 上机练习

  创建一个Dog类,包含昵称、颜色两属性;创建测试类,完成以下需求:

  • 把多个Dog信息添加到集合中
  • 查看Dog的数量及所有Dog的信息
  • 删除集合中部分Dog的元素
  • 判断集合中是否包含指定Dog

Dog.java:

package com.mashibing;

import java.security.Principal;
import java.util.Objects;

public class Dog {
    private String name;
    private String color;

    //无参构造方法
    public Dog() {

    }

    //有参构造方法
    public Dog(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    //重写toString方法,打印具体值
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                '}';
    }

    //重写
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Dog dog = (Dog) o;
        return Objects.equals(name, dog.name) && Objects.equals(color, dog.color);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, color);
    }
}

ListTest.java:

package com.mashibing;

import javax.xml.transform.Source;
import java.util.ArrayList;
import java.util.List;

public class ListTest {
    public static void main(String[] args) {
        List list = new ArrayList();
        Dog d1 = new Dog("大黄","red");
        Dog d2 = new Dog("二黄","blue");
        Dog d3 = new Dog("三黄","yellow");

        //把多个Dog信息添加到集合中
        list.add(d1);
        list.add(d2);
        list.add(d3);

        //查看Dog的数量及所有Dog信息
        System.out.println(list);
        System.out.println(list.size());

        //删除集合中部分Dog元素
        list.remove(d1);
        System.out.println(list);

        //判断集合中是否包含指定Dog
        System.out.println(list.contains(d2));

        Dog d4 = new Dog("二黄","blue");
        //在未重写equals方法前,比较的是对象地址;在重写equals方法后,比较的是两个对象的属性值
        System.out.println(list.contains(d4));


    }
}
[Dog{name='大黄', color='red'}, Dog{name='二黄', color='blue'}, Dog{name='三黄', color='yellow'}]
3
[Dog{name='二黄', color='blue'}, Dog{name='三黄', color='yellow'}]
true
true

5.Iterable接口

  可以使用Iterator遍历的本质是实现Iterable接口。

6.Set接口

  Set接口存储一组唯一、无序的对象。存入和取出的顺序不一定一致。操作数据的方法与List类似,Set接口不存在get()方法。
在这里插入图片描述

6.1 HashSet

  HashSet采用Hashtable哈希表(HashMap)存储结构。优点是添加速度快、查询速度快、删除速度快。缺点是无序。其中,LinkedHashSet采用哈希表存储结构,同时使用链表维护次序,其添加顺序是有序的。

Person.java:

package com.mashibing;

import java.util.Objects;

public class Person {
    private String name;
    private int age;

    public Person() {

    }

    public Person(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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

主程序:

package com.mashibing;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/*
* 1.Set中存放的是无序、唯一的元素,
* 2.Set不可以通过下标获取对应位置的元素的值,因为Set存放的是无序的元素
* 3.使用treeSet底层的实现是treemap;利用红黑树来进行实现
* 4.设置元素时,如果自定义对象,会查找对象中的equals和hashcode方法。如果没有,比较的是对象的地址
* 5.树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器
* */
public class SetDemo {
    public static void main(String[] args) {
        Set set = new HashSet();
        set.add("123");
        set.add(1);
        set.add(true);

        System.out.println(set);

        //iterator迭代器
        Iterator iterator = set.iterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println("---------------------------------");
        //将while循环改成for循环,会节省内存空间
        for (Iterator iter = set.iterator();iter.hasNext();) {
            System.out.println(iter.next());
        }
        
        HashSet hashSet = new HashSet();
        hashSet.add(new Person("zhangsan",12));
        hashSet.add(new Person("zhangsan",12));
        hashSet.add(new Person("lisi",13));
        
        System.out.println(hashSet);
    }
}
[1, 123, true]
1
123
true
---------------------------------
1
123
true 
[com.mashibing.Person@a8e9e1d9, com.mashibing.Person@623659b]

HashSet是如何保证元素的唯一性的呢
  是通过元素的两个方法:hashCode和equals方法来完成。如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashCode值不同,不会调用equals方法。

Hash表原理
在这里插入图片描述

6.2 TreeSet接口

  TreeSet接口采用二叉树(红黑树)的存储结构。优点是有序(排序后的升序)查询速度比List快。缺点是查询速度没有HashSet快。红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体性能上来说优于AVL树。
在这里插入图片描述

/*
* 使用treeSet底层的实现是treemap;利用红黑树来进行实现,
* 树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器
*   比较器分类:
*       内部比较器:定义在元素的类中,通过实现Comparable接口中的comparaTo方法进行实现
*       外部比较器:定义在当前类中,通过实现Comparator接口来实现,但是要将该比较器传递到集合中
*                 new TreeSet(new SetDemo());
*       外部比较器可以定义为工具类,此时所有需要比较的规则如果一致的话,可以复用;而内部比较器
*       只有在存储当前对象的时候才可以使用。
*       如果两者同时存在,使用外部比较器
*       当使用比较器的时候,不会调用equals方法
*/

Person.java

package com.mashibing;

import java.time.OffsetDateTime;
import java.util.Objects;

public class Person implements Comparable {
    private String name;
    private int age;

    public Person() {

    }

    public Person(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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    //定义比较器,此比较器按照name的长度进行比较
    @Override
    public int compareTo(Object o) {
        Person p = (Person) o;
        if (p.name.length() > this.name.length()) {
            return -1;
        } else if (p.name.length() < this.name.length()) {
            return 1;
        } else {
            return 0;
        }
    }

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

主程序

package com.mashibing;

import java.util.TreeSet;

public class SetDemo {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        //必须放置同一类型的数据
        treeSet.add(34);
        treeSet.add(1);
        treeSet.add(65);
        System.out.println(treeSet);
        
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Person("zhangsan",12));
        treeSet.add(new Person("zhangsan",12));
        treeSet.add(new Person("lisi",13));
        treeSet.add(new Person("wangwu",13));
        treeSet.add(new Person("maliu",13));
        System.out.println(treeSet);
    }
}
[1, 34, 65]
//只打印一个"zhnagsan",compareTo方法中兼具去重功能
[Person{name='lisi', age=13}, Person{name='maliu', age=13}, Person{name='wangwu', age=13}, Person{name='zhangsan', age=12}]

外部比较器的实现

Person.java:

package com.mashibing;

import java.util.Objects;

public class Person  {
    private String name;
    private int age;

    public Person() {

    }

    public Person(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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    //定义比较器,此比较器按照name的长度进行比较
//    @Override
//    public int compareTo(Object o) {
//        Person p = (Person) o;
//        if (p.name.length() > this.name.length()) {
//            return -1;
//        } else if (p.name.length() < this.name.length()) {
//            return 1;
//        } else {
//            return 0;
//        }
//    }

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

主程序:

package com.mashibing;

import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;
/*
* 使用treeSet底层的实现是treemap;利用红黑树来进行实现,
* 树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较;如果是引用类型的话,需要自定义比较器
*   比较器分类:
*       内部比较器:定义在元素的类中,通过实现Comparable接口中的comparaTo方法进行实现
*       外部比较器:定义在当前类中,通过实现Comparator接口来实现,但是要将该比较器传递到集合中
*                 new TreeSet(new SetDemo());
*       外部比较器可以定义为工具类,此时所有需要比较的规则如果一致的话,可以复用;而内部比较器
*       只有在存储当前对象的时候才可以使用。
*       如果两者同时存在,使用外部比较器
*       当使用比较器的时候,不会调用equals方法
*/
public class SetDemo implements Comparator<Person> {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new SetDemo());
        treeSet.add(new Person("zhangsan",19));
        treeSet.add(new Person("zhangsan",12));
        treeSet.add(new Person("lisi",15));
        treeSet.add(new Person("wangwu",13));
        treeSet.add(new Person("maliu",17));

        System.out.println(treeSet);
    }

    @Override
    public int compare(Person o1, Person o2) {
        if (o1.getAge() > o2.getAge()) {
            return -1;
        } else if (o1.getAge() < o2.getAge()) {
            return 1;
        } else {
            return 0;
        }
    }
}
[Person{name='zhangsan', age=19}, Person{name='maliu', age=17}, Person{name='lisi', age=15}, Person{name='wangwu', age=13}, Person{name='zhangsan', age=12}]

7.Comparable接口

  所有可以排序的类都实现了java.lang.Comparable 接口,Comparable接口中只有一个方法:public int compareTo(Object obj);。实现了Comparable 接口的类通过实现 comparaTo 方法从而确定该类对象的排序方式。该方法有以下几种情况:

  • this == obj

    返回0

  • this > obj

    返回正数

  • this < obj

    返回负数

实例见上述代码

8.List接口

  List接口存储一组不唯一(可重复)、有序(插入顺序)的对象。List接口的方法如下:(凡是可以操作索引的方法都是该体系特有的方法)

  • add(element):在list尾部添加元素

  • add(index,element):在指定索引的位置上插入元素

  • addAll(index,Collection):在指定的引的位置上插入整个集合的元素

  • addAll(Collection):在结束插入整个集合的元素

  • copyof(Collection):从一个集合复制到另一个集合里面

  • remove(index):根据索引删除指定的元素
  • clear():删除list中的所有元素

  • set(index,element) :使用element替换指定索引位置上的元素

  • get(index):获取指定索引位置的元素
  • contains(Object o):判断list中是否包含指定元素
  • containsAll(Collection):判断list中是否包含指定集合中的所有元素
  • equals(Object o):判断两个对象元素是否相等
  • isEmpty():判断list是否为空

8.1 ArrayList

  ArrayList实现了长度可变的数组,在内存中分配连续的空间。

  • 优点:遍历元素和随机访问元素的效率比较高(数组的原因)
  • 缺点:添加和删除需要移动大量移动元素,效率低,按照内容查询效率低
    在这里插入图片描述
/*
 * java集合框架:
 *   List:存放单一的值
 *       特点:
 *           1.可以存放不同类型的数据,而数组只能存放固定类型的数据
 *           2.当使用ArrayList子类实现的时候,初始化长度为10,当长度不够的时候使用grow方法自动进行扩容操作
 * */

使用

package com.mashibing;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ListResourceBundle;


public class ListDemo {
    public static void main(String[] args) {
        List list = new ArrayList();

        list.add("a");
        list.add(1);
        list.add("a");
        list.add(true);
        System.out.println(list);

        //get(index)获取某个位置的元素,不能超过索引边界
        System.out.println(list.get(0));

        //indexOf(Object o):返回指定元素的索引(从前找)
        System.out.println(list.indexOf("a"));

        //lastIndexOf(Object o):返回指定元素的索引(从后找)
        System.out.println(list.lastIndexOf("a"));

        //set(index,E):使用element替换指定索引位置上的元素
        list.set(0,"mashibing");
        System.out.println(list);

        //subList(begin,end):截取从begin到end-1的list
        List list1 = list.subList(0,2);
        System.out.println(list1);

        //of:JDK12
        List<Object> of = List.of(1,2,3,4);
        System.out.println(of);
    }
}
[a, 1, a, true]
a
0
2
[mashibing, 1, a, true]
[mashibing, 1]
[1, 2, 3, 4]

8.2 LinkedList

  LinkedList采用链表存储方式。又分为单向链表、双向链表

  • 优点:插入、删除元素时效率比较高
  • 缺点:遍历和随机访问元素效率低下
    在这里插入图片描述
    LinkedList特有的方法
    在这里插入图片描述
package com.mashibing;

import java.util.LinkedList;

/*
*   LinkedList拥有更加丰富的方法实现,需要使用的时候查询api即可,不需要记忆
* */
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(123);
        linkedList.add(false);
        linkedList.add("abc");
        linkedList.add(123);

        System.out.println(linkedList);
        //往链表指定位置添加元素
        linkedList.add(2,"mashibing");
        System.out.println(linkedList);

        //往链表头部添加元素
        linkedList.addFirst("1111");
        System.out.println(linkedList);

        //往链表尾部添加元素
        linkedList.addLast("2222");
        System.out.println(linkedList);

        //获取链表的第一个元素
        System.out.println(linkedList.element());

        //get(index)获取链表指定位置的元素
        System.out.println(linkedList.get(0));

        //indexOf(O)获取指定元素的下标位置(从前找)
        System.out.println(linkedList.indexOf(123));

        //lastindexOf()获取指定元素的下标位置(从后找)
        System.out.println(linkedList.lastIndexOf(123));

        //offer(E)添加元素
        linkedList.offer("3333");
        System.out.println(linkedList);

        //peek获取链表元素
        System.out.println(linkedList.peek());

        //poll()获取链表元素
        System.out.println(linkedList.poll());
    }
}
[123, false, abc, 123]
[123, false, mashibing, abc, 123]
[1111, 123, false, mashibing, abc, 123]
[1111, 123, false, mashibing, abc, 123, 2222]
1111
1111
1
5
[1111, 123, false, mashibing, abc, 123, 2222, 3333]
1111
1111

8.3 vector

  1. Vector也是List接口的一个子类实现
  2. Vector跟ArrayList一样,底层都是使用数组进行实现的
  3. 面试经常问区别:
    • ArrayList是线程不安全的,效率高;Vector是线程安全的,效率低
    • ArrayList在进行扩容操作时,扩容至原容量的1.5倍;Vector在进行扩容时,扩容至原容量的2倍

9.泛型

  为什么需要泛型?

  • 解决数据数据类型不统一产生的异常
  • 使用泛型可以更好地去保护数据类型
/*
* 当做一些集合的统一操作时,需要保证集合的类型是统一的,此时,需要泛型来限制
*   优点:
*       1.数据安全
*       2.获取数据时,效率比较高
*   给集合中的元素设置相同的类型就是泛型的基本需求
*   在定义对象的时候,通过<>中设置合理的类型来进行实现,相当于类型需要用户动态传参来设置
*
* 泛型的高阶应用:
*   1.泛型类
*       在定义类的时候,在类名的后面添加<E(E还是A只是起到占位的作用)>;类中的方法的返回值类型和属性的类型都可以使用泛型
*   2.泛型接口
*       在定义接口的时候,在接口的名称后添加<E.K.V.A.B>
        1.子类在进行实现的时候,可以不填写泛型的类型,此时,在创建具体的子类对象时才决定使用什么类型
        2.子类在实现泛型接口的时候,只在实现父类的接口的时候指定父类的泛型类型即可,此时,测试方法中的泛型类型必须要跟子类保持一致
*   3.泛型方法
*       在定义方法的时候,指定方法的返回值和参数是自定义的占位符,可以是类名中的T,也可以是自定义的Q,
*       只不过在使用Q的时候需要使用<Q>定义在返回值的前面
*       好处:由传递进方法的参数来决定参数的类型
*   4.泛型的上限
*       工作中不会用到
*       如果父类确定了,所有的子类都可以直接使用
*   5.泛型的下限
*       工作中不会用到
*       如果子类确定了,子类的所有父类都可以直接传递参数使用
* */

泛型讲解实例

FanXingClass.java:

package com.mashibing;

public class FanXingClass <A>{
    private int id;
    private A a;

    public int getId() {
        return id;
    }

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

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

    public void show() {
        System.out.println("id:"+id+"A:"+a);
    }

    public A get() {
        return a;
    }

    public void set(A a) {
        System.out.println("执行set方法:"+a);
    }
}

FanXingInterface.java:

package com.mashibing;

public interface FanXingInterface<B> {

    public B test();

    public void test2(B b);
}

FanXingInterfaceSub1.java

package com.mashibing;

public class FanXingInterfaceSub1<B> implements FanXingInterface<B>{
    @Override
    public B test() {
        return null;
    }

    @Override
    public void test2(B o) {
        System.out.println(o);
    }
}

FanXingInterfaceSub2.java:

package com.mashibing;

public class FanXingInterfaceSub2 implements FanXingInterface<String>{
    @Override
    public String test() {
        return null;
    }

    @Override
    public void test2(String o) {
        System.out.println(o);
    }
}

FanXingMetho.java:

package com.mashibing;

public class FanXingMethod<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public <Q> void show(Q q) {
        System.out.println(q);
        System.out.println(t);
    }
}

FanXingTest.java:

package com.mashibing;

import java.lang.ref.SoftReference;


public class FanXingTest {
    public static void main(String[] args) {

        //1.泛型类的使用
        FanXingClass<String> fanXingClass = new FanXingClass<String>();
        fanXingClass.setA("mashibing");
        fanXingClass.setId(1);
        fanXingClass.show();

        FanXingClass<Integer> fanXingClass1 = new FanXingClass<Integer>();
        fanXingClass1.setId(34);
        fanXingClass1.setA(2);
        fanXingClass1.show();

        FanXingClass<Person> fanXingClass2 = new FanXingClass<Person>();
        fanXingClass2.setA(new Person("aaa",12));
        fanXingClass2.setId(3);
        fanXingClass2.show();
        System.out.println(fanXingClass2.get());
        fanXingClass2.set(new Person("bbb",14));


        //2.泛型接口的使用1
        FanXingInterface<String> fanXingInterface = new FanXingInterfaceSub1<String>();
        fanXingInterface.test2("abc");

        //泛型接口的使用2
        FanXingInterface fanXingInterface1 = new FanXingInterfaceSub2();
        fanXingInterface1.test2("123");

        //3.泛型方法
        FanXingMethod<String> fanXingMethod = new FanXingMethod<>();
        fanXingMethod.setT("ttt");
        fanXingMethod.show(123);
        fanXingMethod.show(true);

    }

}
id:1A:mashibing
id:34A:2
id:3A:Person{name='aaa', age=12}
Person{name='aaa', age=12}
执行set方法:Person{name='bbb', age=14}
abc
123
123
ttt
true
ttt

9.1 使用泛型集合解决实际问题

  • 声明员工类Employee包含如下属性:id,name,age,gender(枚举类型)
  • 声明程序员类SE,含有属性popularity人气值
  • 声明项目经理类PM,含有属性workOfYear工作年限
  • 程序员与项目经理都继承自Employee

需求说明:

  • 使用泛型集合ArrayList,LinkedList,HashSet,TreeSet完成员工的添加、删除;
  • 判断,集合中元素个数的判断

10.Map接口

  Map接口存储一组键值对象,提供key到value的映射。

  • HashMap:底层结构是哈希表

    • Key无序且唯一
    • Value无序不唯一
  • LinkedHashMap:底层结构是链表

    有序的HashMap,速度快

  • TreeMap:底层结构是红黑树

    有序,速度没有hash快

问题:Set与Map有什么关系

  • 采用了相同的数据结构,Set集合只用于map的key
/*
* map存储的是k-v键值对映射的数据
*   实现子类:
*       HashMap:数组+链表(1.7);数组+链表+红黑树(1.8)
*       LinkedHashMap:链表
*       TreeMap:红黑树
*
*   基本api操作:
*       增:
*           put(k,v):添加数据
*       删:
*           clear():清空map中的元素
*           remove():删除指定元素
*       改:
*
*       查:
*           isEmpty():判断map是否为空(查)
*           containsKey():判断map中是否含有某个key值
*           containsValue():判断map中是否含有某个value值
*           get():获取map中某个key值对应的value值
*           entrySet():
*   Map.entry表示的是K-V组合的一组映射关系,key和value成组出现
*   Hashmap与Hashtable的区别:
*       - HashMap线程不安全,效率高;Hashtable线程安全,效率低
*       - Hashmap中key和value都可以为空;Hashtable中key和value都不可以为空
*
* */

10.1 Map中的方法及其实例

在这里插入图片描述
MapDemo.java:

package com.mashibing.map;

import java.util.*;

public class MapDemo {

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

        //put(key,value)添加元素
        map.put("a",1);
        map.put("b",2);
        map.put("c",3);
        map.put("d",4);
        System.out.println(map);

        //isempty()判断是否为空
        System.out.println(map.isEmpty());

        //size:大小
        System.out.println(map.size());

        //map
//        map.clear();
//        System.out.println(map);

        //判断:containsKey和containsValue
        System.out.println(map.containsKey("a"));
        System.out.println(map.containsValue(1));

        //get()获取对应key的value值
        System.out.println(map.get("a"));
        System.out.println(map.getOrDefault("e",-1));

        //remove():删除元素
        map.remove("a");
        System.out.println(map);
        
        //遍历操作
        Set<String> keys = map.keySet();
        for(String key :keys) {
            System.out.println(key+"="+map.get(key));
        }
        //只能获取对应的value值,不能根据value值获取key
        Collection<Integer> values = map.values();
        for(Integer i:values) {
            System.out.println(i);
        }

        //迭代器
        Set<String> keys2 = map.keySet();
        Iterator<String> iterator = keys2.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            System.out.println(key+"="+map.get(key));
        }

        //entrySet
        //Map.Entry<String, Integer>:泛型套了一个泛型
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
        while(iterator1.hasNext()) {
            Map.Entry<String, Integer> next = iterator1.next();
            System.out.println(next.getKey()+"--"+next.getValue());
        }
    }
}
{a=1, b=2, c=3, d=4}
false
4
true
true
1
-1
{b=2, c=3, d=4}
b=2
c=3
d=4
2
3
4
b=2
c=3
d=4
b--2
c--3
d--4
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幼稚的人呐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值