Bootstrap

JavaSE基本知识补充(第二篇)-集合!!重点

 

目录

 

集合!!重点

1. 常用API

2. List集合

1. 概念

2. List的迭代器

3.List集合特点:

 4. ArrayList

5. LinkedList

6.Vector

7. 泛型

7.2 自定义的泛型

3. Set

1. 概念

2. Hashset:

特点:

equals()作用:

 3. LinkedHashSet

特点:

4. TreeSet

4.1 排序比较

特点:


集合!!重点

        集合的长度是可变的,数组的长度是不可变的。集合提供了丰富的API。

collection集合:

        list set 队列

        ArrayList最常用 LinkedList Vector

        HashSet最常用 TreeSet LinkedHashSet

数组回顾    int[] arr={1,8,9}   int[] arr=new int[3]    int[] arr=new int[]{1,2,5}  

java数据类型  2

         基本数据类型  引用数据类型

        byte  short  int  long  float   double  boolean   char

        数组  类  接口

1. 常用API

  • 添加相关的方法

        add(E e)   确保此 collection 包含指定的元素(可选操作)

        addAll(Collection<? extends E> c)  

        将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。

  • 删除相关的方法

        clear()  移除此 collection 中的所有元素(可选操作)。

        remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。

        removeAll(Collection<?> c) 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。

  • 判断相关的方法

        contains(Object o) 如果此 collection 包含指定的元素,则返回 true。

        containsAll(Collection<?> c) 如果此 collection 包含指定 collection 中的所有元素,则返回 true。

        isEmpty() 如果此 collection 不包含元素,则返回 true。

  • 数组的转换相关方法

        toArray()  返回包含此 collection 中所有元素的数组。

2. List集合

1. 概念

        List是有序的集合,就像我们的数组一样。我们可以把list理解为是一个长度可变的数组,而且提供了丰富的api。List的集合底层就是数组。

public static void main(String[] args) {

    //创建一个list的集合
    List list = new ArrayList();
    //向末尾添加元素
    list.add("吴用"); //0
    list.add("刘唐"); //1
    list.add("宋江"); //2

    System.out.println(list);
    //我们在1处的索引位置来插入元素,我们插入一个元素的话,改索引后面的元素都会向后移动一位
    list.add(1, "晁盖");
    System.out.println(list);

    //创建一个集合
    List list1 = new ArrayList();
    list1.add("阮小五");
    list1.add("阮小二");
    list1.add("阮小⑦");

    list.addAll(list1);
    System.out.println(list);



}


public static void main(String[] args) {

    //创建一个list的集合
    List list = new ArrayList();
    //向末尾添加元素
    list.add("吴用"); //0
    list.add("刘唐"); //1
    list.add("宋江"); //2

    System.out.println(list);
    //我们在1处的索引位置来插入元素,我们插入一个元素的话,改索引后面的元素都会向后移动一位
    list.add(1, "晁盖");
    System.out.println(list);

    //创建一个集合
    List list1 = new ArrayList();
    list1.add("阮小五");
    list1.add("阮小二");
    list1.add("阮小⑦");

    list.addAll(list1);
    System.out.println(list);



}

2. List的迭代器

 Iterator<E>

iterator() 返回在此 collection 的元素上进行迭代的迭代器。

 

        迭代器也是一个一个遍历的,不用for循环

通过ListIterator的方式遍历:

ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){//判断是否有下一个值
    //获得迭代的元素
    String str = (String) listIterator.next();//取下一个值
    if("刘唐".equals(str)){
        //我们不能在一边遍历的时候一边操作集合,这样有多线程的并发问题
        //list.add("白胜");
        //迭代器可以给我们提供了一个add方法让我们避免并发问题,但是添加的时候本次遍历不生效
        listIterator.add("白胜");//这次遍历没有
    }
    System.out.println(str);

}
System.out.println(list);

        我们可以使用for循环来动态的遍历List集合  普通for循环不支持并发操作。

//int size = list.size();
//for循环对list的变量, 我们可以使用动态获得集合的长度的方式来遍历
for (int i = 0; i < list.size(); i++) {
    //根据索引来获得对应的元素
    String str  = (String) list.get(i);
    if("刘唐".equals(str)){
        list.add("阮小五");
    }
    System.out.println(str);
}

3.List集合特点:

  1. 有序集合
  2. 元素可以重复 有索引,根据索引区分
  3. 长度可变
  4. 底层实现为数组

 4. ArrayList

        ArrayList的底层是数组的原理。

        ArrayList中的元素是可以重复

        是有序的集合,长度不固定。

        不是线程安全的。-- 性能高

        效率高。

长度的变化:

        ArrayList在添加数据的时候初始的长度是10,后续会以5个长度来扩充集合的长度。

 

ArrayList不是线程安全的集合,适合不要求线程安全的需求来实现。

        好处是性能高。

        缺点就是线程不安全,可能带来数据不准确。

                如果线程要是同步的话,性能就会变低。  适合查

并发

同步    多线程

        卫生间,独立的,一个,单线程

        公共卫生间,多线程。效率高

5. LinkedList

Linked也不是线程安全的。

  1. 底层结构是链表实现
  1. 适合做增删改的业务场景
  2. 线程不安全
  3. 有序集合但是更适合增删改

链表:储存了元素和前后的地址

LinkedList是链表为原理,添加修改删除的性能高。

栈:先进后出

队列:先进先出

6.Vector

  •         Vector底层也是数组。
  •         线程安全,支持多线程并发访问
  •         可以存储任意类型对象,包括null
  •         自定扩容,扩容机制是增量为当前容量的一半

public static void main(String[] args) {
    Vector v = new Vector();
    v.add("宋江");
    v.add("晁盖");
    v.add("刘唐");
    System.out.println(v);


    Object o = v.get(1);
    //Object o1 = v.elementAt(1);
    System.out.println(o);
    System.out.println("--------------分割线-----------------");

    for (int i = 0; i < v.size(); i++) {
        Object o1 = v.get(i);
        System.out.println(o1);
    }
    System.out.println("--------------分割线-----------------");

    Enumeration elements = v.elements();//枚举
    while(elements.hasMoreElements()){
        Object o1 = elements.nextElement();//获取枚举对象
        System.out.println(o1);
    }
}

7. 泛型

        泛型就是在集合中指定存储的数据类型,而且只能存储这种类型,在List<类型>必须要指定, ArrayList<>可以指定也可以不指定。基本数据类不能作为泛型。

public static void main(String[] args) {
    //定义一个集合里面指定只能存储一种数据类型
    List<String> list = new ArrayList<>();

}

迭代器: 

public static void main(String[] args) {
    //定义一个集合里面指定只能存储一种数据类型
    List<String> list = new ArrayList<>();
    //调用集合
    list.add("亮亮");
    list.add("腻腻");
    list.add("腻腻1");
    list.add("腻腻2");
    list.add("腻腻3");

    //创建一个迭代器对象
    Iterator<String> iterator = list.iterator();
    while(iterator.hasNext()){
        //获得到String类型
        String next = iterator.next();
        System.out.println(next);
    }


}

7.2 自定义的泛型

在自定义泛型时

语法:

        class/interface 类名/接口名 <T>{

        

        }

        T只是泛型的一个标准,使用什么字符都可以,但是都要大写,不要使用特殊字符,建议用T。

自定义泛型类

public class GenericTest<T> {

    //定义一个泛型的属性
    private T t;

    public T getT() {
        return t;
    }

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

测试

public static void main(String[] args) {
    GenericTest<String> gt = new GenericTest<>();

    gt.setT("哈哈");
    //获得对应的泛型的结果
    String t = gt.getT();

    //指定泛型是Integer类型
    GenericTest<Integer> gt1 = new GenericTest<>();
    gt1.setT(1);
    Integer t1 = gt1.getT();

    //指定泛型是Integer类型的数组
    GenericTest<Integer[]> gt2 = new GenericTest<>();
    gt2.setT(new Integer[]{1, 2, 4});
    Integer[] t2 = gt2.getT();



    //测试2个泛型
    GenericTest1<String, Integer> gtt1 = new GenericTest1<>("亮哥", 30);

    GenericTest1<String, Date> gtt2 = new GenericTest1<>("亮哥", new Date());

}

3. Set

1. 概念

Set:

        Set是Collection的子接口

        无序性,无重复的元素

        Set是个接口,不能直接创建对象,需要实现类来创建对象

Set的实现类是HashSet,  linkedhashset,  treeset

2. Hashset:

特点:

  • 1.元素唯一性
  • 2.无序性
  • 3.允许null存在一个
  • 4.不是线程安全(效率高)
  • 5,底层实现是数据结构是哈希表(哈希表依赖的两个方法:hashcode()和equals()方法)

(一般规则:对象的equals是true的话,hashcode需要相同,但是hashcode相同的对象不一定equals相同,这就是所谓的冲突现象,但是有不同的解决方法。你的hashCode()方法设计的好就会减少冲突。)

public static void main(String[] args) {

    /**
     * set是无序的
     * set的元素是不可重复的,如果重复了就会自动的去掉
     * set只能有一个null
     */
    Set<String> set = new HashSet<>();
    //给set添加元素
    set.add("董卓");
    set.add("张让");
    set.add("何进");
    set.add("李肃");
    set.add(null);
    System.out.println(set);
}

        添加的时候回去判断比对有没有一样的,如果有一样的,就会覆盖掉。

我们对set的唯一性深究一下

 如果对象的hash值和equals都相等那么就是重复的对象。

equals()作用

每个类都有这个方法(不仅是字符串类)都是集成object类,默认和==一样比较指向是否相同。
  • 字符串中对这个方法进行了重写,仅比较值。
  • 重写equals还需要重写 hashcode(),相当于身份证号码。 因为 hashmap 的使用需要这两个方法配合。
面试题还会问 如何打配合,hashmap存放数据原理。
  • 基本数据类型 只能用==号比较,比较的就是值,它里面没有equals方法。
  • 引用数据类型 用==比较的是地址。用equals不一定比较的是值,因为根类Object类比较的是地址。实现类重写不一定写的比较的就是值。
类属于引用数据类型
  •  字符串重写:

  • 所有类的根类object:

 

所有类都继承object,在不改写equals方法时,比较的是地址。

但是每写一个实现类,他都会重写equals.

public static void main(String[] args) {

   //创建一个存储Person对象的集合
    Set<Person> set = new HashSet<>();
    set.add(new Person("孔明", 26));
    set.add(new Person("刘备", 28));
    set.add(new Person("关羽", 27));
    set.add(new Person("张飞", 25));
    set.add(new Person("张飞", 25));

    System.out.println(set);
}

如果没有重写,比较的是地址,就不一样。因为是new出来的。

 3. LinkedHashSet

特点:

1.元素唯一性

2.有序的

3.允许null存在一个(因为不能重复)

4.不是线程安全(效率高)

5,底层数据结构由链表和哈希表组成。

LinkedHashSet和HashSet来对比就是多了一个顺序。应用的不多。

public static void main(String[] args) {
    Set<String> set = new LinkedHashSet<>();
    set.add("董卓");
    set.add("张让");
    set.add("何进");
    set.add("李肃");
    set.add(null);
    System.out.println(set);
}

4. TreeSet

4.1 排序比较

放在TreeSet里的类都必须实现Comparable接口

类如果要实现比较的规则都会实现Comparable接口

String对CompareTo的实现

TreeSet的特点

特点:

1.元素唯一性

2.可自定义排序的(两种  Comparable接口  自己定义比较类实现Comparator比较器接口

3.不允许null存在

4.不是线程安全

5,treeset集合中的包装类都必须实现Comparable接口。

6,底层数据结构是红黑树。(是一种自平衡的二叉树)

 字符串已经实现了Comparable接口。

 @Override
    public int compareTo(Student o) {
        //做年龄的差
        int flag = this.age - o.age;
        if(flag == 0){
            flag = this.name.compareTo(o.name);
        }
        return flag;
    }

;