Bootstrap

Java学习之集合2

集合:

1.ArrayList集合类

import java.util.ArrayList;

public class Demo01ArrayList {
    public static void main(String[] args) {
        /*
            ArrayList类概述
                底层数据结构是数组,查询快,增删慢
            TODO 方法
                插入数据时不会对插入的数据进行自然排序或字典排序
                add(index,value)  => 指定下标添加数据时,指定下标最大只能再当前ArrayList最大下标后+1  并且可以实现插入数据
                remove() => 根据下标或数据删除
         */
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(0,2);
        arrayList.add(1,3);
        arrayList.add(2,10);
        arrayList.add(1,30);
        System.out.println(arrayList);

        /*
            TODO 删除数据
                 Integer 包装类数据在传递数据调用函数时,优先调用符合要求的函数,如果不符合再考虑自动拆箱
         */
        Integer integer =3;
        arrayList.remove(integer);
        System.out.println(arrayList);


    }
}

2. Vector

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.ListIterator;
import java.util.Vector;

public class DemoVector {
    public static void main(String[] args) {
        /* TODO   public class Vector<E> extends AbstractList<E>
                  为什么需要使用Vector?
                  Vector是同步的线程安全的。 如果不需要线程安全的实现,建议使用ArrayList代替Vector
         */

        Vector<String> vector = new Vector<>();
        vector.add("张三");
        vector.add("李四");
        vector.add("王五");
        //整个逻辑相当于迭代器遍历
        //Enumeration 接口位于 java.util 包中,它是一个传统的、古老的接口,
        // 提供了两个主要的方法:hasMoreElements() 和 nextElement()。
        //使用在诸如 Vector 和 Properties 这些传统类所定义的方法中
        //Vector的elements()方法返回一个枚举器,可以用来遍历Vector中的元素。
        Enumeration<String> elements = vector.elements();

        // addElement() 方法在功能上与 add(Object) 方法相同。
        // add() 方法返回 true/false 但 addElement() 方法不返回任何值。
        vector.addElement("赵六");
        while (elements.hasMoreElements()) {
            String name = elements.nextElement();
            if ("李四".equals(name)){
                //对于迭代器进行遍历数据删除时,只能使用迭代器中的remove方法进行删除
                //可直接使用vector.remove()进行删除
                vector.remove("李四");
            }
            System.out.println();
        }

        // 获取第一个及最后一个元素
        System.out.println(vector.firstElement());
        System.out.println(vector.lastElement());

        // 指定下标位置插入数据
        vector.insertElementAt("麻七",2);
        System.out.println(vector);

        /*
            演示ArrayList的ConcurrentModificationException
                ArrayList 获取到 iterator 迭代器之后,改变了当前ArrayList中的数据长度
                没有通过iterator的next方法中对于长度的检查
                    要求 iterator 创建后原先的ArrayList长度不能发生变化
                    final void checkForComodification() {
                        if (modCount != expectedModCount)
                            throw new ConcurrentModificationException();
                    }
         */
        ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        ListIterator<String> iterator = list.listIterator();
        list.add("3");
        list.add("4");
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }


    }
}

3. LinkedList

import java.util.LinkedList;

public class DemoLinkedList {
    public static void main(String[] args) {
        /*
            TODO:LinkedList 底层为链表,增删快
         */
        LinkedList<Object> linkedList = new LinkedList<>();
        linkedList.add("1");
        linkedList.addFirst("2");
        linkedList.addLast("3");
        System.out.println(linkedList);  // [2, 1, 3]

        System.out.println(linkedList.getFirst());
        System.out.println(linkedList.getLast());

        //poll是队列数据结构实现类的方法,从队首获取元素,同时获取的这个元素将从原队列删除
        System.out.println(linkedList.poll());// 2

        //检索并删除此列表的第一个元素,如果此列表为空,则返回null
        System.out.println(linkedList.pollFirst());// 1

        //pop是栈结构的实现类的方法,表示返回栈顶的元素,同时该元素从栈中删除,
        // 当栈中没有元素时,调用该方法会发生异常
        System.out.println(linkedList.pop());// 3

        System.out.println(linkedList);
        linkedList.removeFirst();
        linkedList.removeLast();

       
    }
}

4.泛型

import java.util.ArrayList;

public class DemoGenerics {
    public static void main(String[] args) {
        /*
            TODO 泛型
                1.为什么需要泛型?
                   1.  对于有时调用某个类中的方法时,方法的参数类型需要明确,但是为了方法的使用广泛,
                        那么该方法的参数类型不能写死 而Java是一种强类型语言,必须要表示其类型是什么
                            所以需要使用某种 标记 来表示其类型
                   2. 对于集合在添加数据时,如果对数据不进行限制,那么对于其具体的元素只能泛化为Object的子类
                            实际使用时需要对其元素的类型进行明确,一般情况下,一个容器中,保存的数据应该为同一种类型
                   总结:泛型可以对类型进行控制
                2.泛型的书写格式
                   使用 <> 进行表示 并可以对 类进行修饰传参 / 方法进行修饰 / 变量

                泛型 可以表述一种未知的类型,可以增加方法的灵活性

         */
        ArrayList arrayList = new ArrayList();
        arrayList.add(1);
        arrayList.add("字符串");

        for (Object o : arrayList) {
            System.out.println(o);
        }

        /*
            TODO 当在类名旁使用<类型>进行表述时,就限定其 T = 类型
         */
        A<String> stringA = new A<>("张三");
        A<Name> nameA = new A<>(new Name("李", "亮"));
        nameA.name.printInfo();


        new B().fun("这是B类中的泛型方法");
        String string = new B().fun1("String");
        Integer integer = 1;
//        new B().<String>fun(integer);
        new B().<String>fun("integer");

        B b = new B();
        b.fun2(new Cat());

    }
}

class A<T> {
    T name;

    /*
        TODO A类的有参构造使用了 T 作为其参数类型
             T同时也是当前 A类中的一个属性
     */
    public A(T t) {
        this.name = t;
    }
}

class B {
    // TODO  public <E> 用于限制方法在调用时,对其中的参数进行限制类型
    public <E> void fun(E e) {
        System.out.println(e);
    }

    public <F> F fun1(F f) {
        return f;
    }

    // TODO 对于T泛型要求为一个动物
    public <T extends Animal> void fun2(T t) {
        t.eat();
        t.run();
    }
}


abstract class Animal {
    public abstract void run();

    public abstract void eat();
}

class Cat extends Animal {

    @Override
    public void run() {
        System.out.println("猫可以走猫步...");
    }

    @Override
    public void eat() {
        System.out.println("🐱爱吃鱼...");
    }
}

class JJLCat extends Cat{
    final String type = "金吉拉";
    String name;

    public JJLCat(String name) {
        this.name = name;
    }
}


class Name {
    String xing;
    String ming;

    public Name(String xing, String ming) {
        this.xing = xing;
        this.ming = ming;
    }

    public void printInfo() {
        System.out.println("在下免贵姓" + xing + "名" + ming);

    }
}

5. ArrayList forEach() 方法

import java.util.ArrayList;
import java.util.function.Consumer;

public class DemoFor {
    public static void main(String[] args) {
        ArrayList<Integer> integers = new ArrayList<>();
        integers.add(1);
        integers.add(2);
        integers.add(4);

        //增强For循环遍历集合
        for (Integer integer : integers) {
            System.out.println(integer);
        }

//        integers.listIterator().for

        /*
           iterator方法是属于 Iterable 的 生成一个迭代器
               迭代器在有些情况下,因为可以维护一个指针,
                    并且有时并不需要将所有的数据全部获取到之后再再去进行数据遍历
                          可能有时是数据获取一条,再遍历一条  这样提升了效率 也节约了内存空间
         */
        integers.iterator();

  /* TODO
        forEach() 方法用于遍历动态数组中每一个元素并执行特定操作。
        forEach() 方法的语法为:
        arraylist.forEach(Consumer<E> action)/
         */
        integers.forEach(
                // TODO  Consumer 表示一个消费器 用于获取ArrayList中的每个元素
                new Consumer<Integer>() {
                    /*
                        accept 方法用于接收每个元素 会将 ArrayList中的每一个元素 传入到  elem 变量中
                            每个元素调用一次 accept 函数
                     */
                    @Override
                    public void accept(Integer elem) {
                        System.out.println("accept被执行了一次:" + elem * 3);
                    }
                }
        );


    }
}

6.可变长参数

import java.util.Arrays;
import java.util.List;

public class MoreParameter {
    public static void main(String[] args) {
//        3,4,5,6,7,8
        int[] ints = {3,4,5,6,7,8};
        System.out.println(ints);
        System.out.println(compute1(ints));
        System.out.println(compute2(3,4,5,6,7,8));

        // TODO   Arrays.<String> 中的String可以去除,是因为编译时,可以根据传入的数据推导出来 T 但是建议加上
        List<String> stringList = Arrays.<String>asList("a", "b", "c");
        System.out.println(stringList);

    }
    /*
        TODO 在做数据计算时,如果需要对多个值进行求积计算,那么如何操作?
     */
    public static int compute1(int[] allData){
        int res = 1;
        for (int data : allData) {
            res *= data;
        }
        return res;
    }

    // TODO Java中给定了一个可变长参数 格式为 类型... 实际上就是一个数组
    //    可以避免一些无效的数组变量创建
    public static int compute2(int... allData){
        System.out.println(allData); // [I @4554617c 数组
        return 1;
    }

}

7.Set

package com.shujia.day09_ArrayList_Set;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;

public class Demo09Set {
    public static void main(String[] args) {
        /*
            Set集合中不包含重复元素,并且是无序的
         */
        Set<String> stringSet = new HashSet<String>();
        stringSet.add("2");
        stringSet.add("3");
        stringSet.add("2");  // 去重了
        stringSet.add("4");
        System.out.println(stringSet);

        for (String value : stringSet) {
            System.out.println(value);
        }

        /*TODO
            自定义类进行数据保存Set
                对于自定义类添加到Set中时,会按照对象的内存地址进行等值判断后去重
                    判断是通过 equals 方法 => 自定义类会继承Object默认使用 == 地址判断
         */

        Set<Data> data = new HashSet<>();
        Data data1 = new Data("1");
        data.add(data1);
        data.add(new Data("2"));
        data.add(data1);
        data.add(new Data("1"));
        data.add(new Data("3"));  // 重写 equals 后根据属性 value 进行比较
        System.out.println(data);
        System.out.println(data.size());


        for (Data datum : data) {
            System.out.println(datum.value);
        }

    }
}
class Data{
    String value;

    public Data(String value) {
        this.value = value;
    }

    //重写equals()方法,使其符合所要的判断逻辑
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Data data = (Data) o;
        return Objects.equals(value, data.value);
    }

    //Objects.hash() 可以接受一个或多个对象并为它们提供哈希码
    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
}

8. HashSet

import java.util.HashSet;

public class DemoHashSet {
    public static void main(String[] args) {
        /*
            TODO 由于integers数据对其调用HashCode函数得到的结果和数值一样
                    那么在Hash表中存储的位置是根据Hash结果进行定位的,所以相邻的数值存储位置也是相邻的

            TODO  HashSet如何保证元素唯一性
                    底层数据结构是哈希表(元素是链表的数组)
                    哈希表依赖于哈希值存储
                    添加功能底层依赖两个方法:
                        int hashCode()
                        boolean equals(Object obj)
                    如果hashCode相同,那么并不一定说明两个数据就一定一样,( x=数据  y=hashCode)
                            同时在存储时经过取余计算,两个不同的数据也有可能得到相同的位置数据
                            所以需要再通过等值判断

         */
        HashSet<Integer> integers = new HashSet<>();
        integers.add(2);
        integers.add(1);
        integers.add(5);
        integers.add(4);
        integers.add(6);
        System.out.println(integers); // [1, 2, 4, 5, 6]

        HashSet<String> strHash = new HashSet<>();
        strHash.add("11");
        strHash.add("10");
        strHash.add("8");
        strHash.add("0");
        strHash.add("a");
        System.out.println(strHash); // [11, 0, a, 8, 10]

        Integer integer1 = 1;
        Integer integer2 = 2;

        System.out.println(integer1.hashCode()); // 1
        System.out.println(integer2.hashCode()); // 2

    }
}

9. LinkedHashSet

import java.util.LinkedHashSet;

public class DemoLinkedHashSet {
    public static void main(String[] args) {
        /*
           TODO LinkedHashSet:
                元素有序唯一
                由链表保证元素有序 => 只能保证其添加顺序 =>
                由哈希表保证元素唯一
         */
        LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add(2);
        linkedHashSet.add(1);
        linkedHashSet.add(5);
        linkedHashSet.add(4);
        linkedHashSet.add(6);
        System.out.println(linkedHashSet); //  [2, 1, 5, 4, 6]


    }
}
;