欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaSE基础语法--集合与容器使用

程序员文章站 2022-04-10 19:40:57
第七章:集合/容器集合:能动态增长长度,并且可以实现各种数据结构的容器,就是集合。Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中1.Collection接口数组的缺点: 长度一旦定义就不可变 , 结构单一 ,只存储类型相同的元素Collection(集合接口):不能实例化 集合可以存储引用类型(默认是Object类型),可以添加任何元素,它会先用valueOf()自动装箱,最好还是向集合中添加同一类型的元素1.基本方法public static void...

第七章:集合/容器

集合:能动态增长长度,并且可以实现各种数据结构的容器,就是集合。
Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中

1.Collection接口

数组的缺点: 长度一旦定义就不可变 , 结构单一 ,只存储类型相同的元素
Collection(集合接口):不能实例化 集合可以存储引用类型(默认是Object类型),可以添加任何元素,它会先用valueOf()自动装箱,最好还是向集合中添加同一类型的元素

1.基本方法

public static void main(String[] args) {
        // 通过子类创建父类对象
        Collection c = new ArrayList();

        // 向末尾添加元素
        c.add(2);
        c.add("3");
        c.add(4);
        c.add(3);
        c.add("6");
        c.add(true);// 它会先用valueOf()自动装箱
        System.out.println(c);

        // 删除指定元素,并且删除时需要与输入时的数据类型相同
        c.remove("3");
        System.out.println(c);

        // size()方法 得到集合的长度
        // length属性 得到数组的长度
        // length()方法 得到字符串的长度
        System.out.println(c.size());

        // isEmpty 是否为空
        System.out.println(c.isEmpty());

        // contains 是否包含
        System.out.println(c.contains(3));

        // clear 清空
//        c.clear();
//        System.out.println(c);

        // addAll 将一个集合添加到另一个集合中
        Collection c1 = new ArrayList();
        c1.add(7);
        c1.add(8);
        c1.add(9);
        c1.addAll(c);
        System.out.println(c1);

        // containsAll 集合 c1 是否包含集合 c
        System.out.println(c1.containsAll(c));

        // removeAll 删除集合c1中与c相同的元素
//        c1.removeAll(c);
//        System.out.println(c1);

        // retainAll c1中只保留c1与c的交集,有改变时返回true
        System.out.println(c1.retainAll(c));
        System.out.println(c1);

        // removeIf有选择地删除指定元素  匿名内部类过滤
        System.out.println(c1.removeIf(new Predicate() {
            @Override
            public boolean test(Object o) {
                return o.equals("6");
            }
        }));
    }

2.集合转数组 toArray( )

public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("1");
        c.add("2");
        c.add("3");
        c.add("4");

        // 第一种方式
        Object obj = c.toArray();
        System.out.println(obj.toString());

        // 第二种方式
        Collection<String> c1 = new ArrayList<String>();// JDK8以后如果前面写了,后面就不用写了。
        c1.add("5");
        c1.add("6");
        c1.add("7");
        c1.add("8");

        String[] s = c1.toArray(new String[c1.size()]);
        System.out.println(Arrays.toString(s));

3.数组转集合 asList(T… a)

public static void main(String[] args) {	
		// asList(T...a)数组转换列表
        Integer[] i = new Integer[]{1,2,4};
        List<Integer> list = Arrays.asList(i);
        System.out.println(list);

        // 可变长度参数,可同时传入多个参数
        // 本质是一个数组,一个参数列表只能有一个
        // 必须方法参数列表末尾,可以直接传一个数组。
        test(1,2,3,4);
    }

    public static void test(int...a){
        System.out.println("");
    }

4.特殊方法 sort( ),subList( ),removeRange( )

 public static void main(String[] args) {
        ArrayList a = new ArrayList();
        a.add("s");
        a.add("d");
        a.add("f");
        a.add("a");
        a.add("t");
        a.add("k");

        // 不能直接使用sort函数,需要创建一个比较类
        a.sort(new StringC());
        System.out.println(a);

        // 从集合中截取元素,包括开始,不包括结束
        System.out.println(a.subList(2,5));

        // 删除指定区间元素  包含开始,不包含结束
        CollectionDemo3 list = new CollectionDemo3();
        list.add("s");
        list.add("d");
        list.add("f");
        list.add("a");
        list.add("t");
        list.add("k");

        list.removeRange(0,3);
        System.out.println(list);
    }
排序所需要的比较类
public class StringC implements Comparator<String> {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
}

2.List接口

List:数据对象 有顺序可以重复
List继承了Collection接口,有三个实现的类,分别是下面的三个:
LinkedList:采用双向链表存储方式。插入、删除元素时效率比较高
Vector数组列表,同步锁,线程安全的,两倍扩容
ArrayList数组列表,数据采用数组方式存储,实现了长度可变的数组,一点五倍扩容。遍历元素与随机访问元素效率高

1.ArrayList

ArrayList: 数组列表,数据采用数组方式存储,实现了长度可变的数组,一点五倍扩容
在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高。(是我们最常用的)

    public static void main(String[] args) {
        // ArrayList的默认空间初始值是10,如果需要更大的空间,建议在一开始初始化的时候就设置新的空间大小。
        // ArrayList的常用方法
        ArrayList a1 = new ArrayList(100);
        a1.add(0,1);
        a1.add(1,3);
        a1.add(0,2);
        a1.add(1,4);
        a1.add(3,4);
        a1.add(3,2);
        a1.add(9);// 不加索引就是向末尾插入
        System.out.println(a1);// [2, 4, 1, 3]
        // 测试之前add()方法是赋值的意思,结果出来之后知道了,是以插入的方法进行赋值

        // get()方法是通过指定index索引得到数组元素
        System.out.println(a1.get(0));// 4

        // indexOf方法是 从头遍历寻找指定元素的索引值
        // 如果搜索的是数组中没有的值,那么会返回 -1
        // 如果有重复的元素,会返回距离头部最近的元素的索引
        System.out.println(a1.indexOf(4));

        // lastIndexOf 从尾遍历寻找指定元素的索引值
        // 如果搜索的是数组中没有的值,那么会返回 -1
        // 如果有重复的元素,会返回距离尾部最近的元素的索引
        System.out.println(a1.lastIndexOf(2));

        // remove 删除并返回指定位置的元素
        // 如果超过索引范围,就会抛出异常java.lang.IndexOutOfBoundsException
        System.out.println(a1.remove(2));
        System.out.println(a1);// [2, 4, 2, 4, 3]

        // set 修改指定索引的元素值
        // 如果超过索引范围,就会抛出异常java.lang.IndexOutOfBoundsException
        a1.set(3,9);
        System.out.println(a1);// [2, 4, 2, 9, 3]
    }

2.LinkedList

LinkedList:采用双向链表存储方式。插入、删除元素时效率比较高

 public static void main(String[] args) {
        LinkedList a = new LinkedList();

        // add 向指定索引处插入元素
        a.add(0,1);
        a.add(1,2);
        a.add(2,3);
        a.add(1,4);
        a.add(4,5);
        System.out.println(a);// [1, 4, 2, 3, 5]

        // addFirst  向头部插入指定元素
        a.addFirst(3);
        a.addFirst(0);
        System.out.println(a);// [0, 3, 1, 4, 2, 3, 5]

        // addLast  向尾部插入指定元素
        a.addLast(9);
        a.addLast(10);
        System.out.println(a);// [0, 3, 1, 4, 2, 3, 5, 9, 10]

        // remove 删除指定索引的元素
        // 超出索引位置会报错java.lang.IndexOutOfBoundsException
        a.remove(7);
        System.out.println(a);// [0, 3, 1, 4, 2, 3, 5, 10]

        // removeFirt  删除头部首个元素
        a.removeFirst();
        System.out.println(a);// [3, 1, 4, 2, 3, 5, 10]

        // removeLast  删除尾部首个元素
        a.removeLast();
        System.out.println(a);// [3, 1, 4, 2, 3, 5]

        // getFirst  获得头部的首个元素
        System.out.println(a.getFirst());// 3

        // getLast 获得尾部的首个元素
        System.out.println(a.getLast());// 5

        // 因为LinkedList 和 ArrayList实现了同一个接口List所以能调用的方法基本是一样的
        System.out.println(a.get(2));// 4
    }

3.Vector

vector: 底层也是数组实现的,可扩容,,多线程安全。(方法基本与ArrayList一样)

Vector<String> v = new Vector<>();
        v.add("1");
        v.add("3");
        v.add("2");
        v.add("2");
        v.add("4");
        System.out.println(v);//[1, 3, 2, 2, 4]

4.集合遍历

集合遍历:

  1. for循环
  2. foreach循环
  3. iterator迭代器
 public static void main(String[] args) {
        Vector<String> v = new Vector<>();
        v.add("1");
        v.add("3");
        v.add("2");
        v.add("2");
        v.add("4");
        System.out.println(v);//[1, 3, 2, 2, 4]

        // 集合迭代与遍历
        // for循环遍历
        for (int i = 0; i < v.size(); i++) {
            System.out.print(v.get(i));// 1324
            if(v.get(i).equals("2")){
                v.remove(i);
                /*
                * 删除元素后,长度减一,元素向前移动一位。
                * 想解决这个问题,可以在执行完删除操作后,i--
                * */
                i--;
            }
        }
        System.out.println();
        System.out.println(v);// [1, 3, 4]

        // foreach 遍历
        for(String vector : v){
            System.out.print(vector);// 遍历
            if(vector.equals("3")){
                v.remove(vector);
                break;
                /*
                * 如果删除元素就会抛出异常,即不允许在遍历过程中进行操作。
                * ConcurrentModificationException  表明不能修改
                * 如果必要进行删除,可以在删除元素后立即退出循环,这样就不会抛出异常。
                * */
            }
        }
        System.out.println();
        System.out.println(v);// [1, 4]

        // 迭代器 Iterator ——> 接口
        Iterator<String> iterator = v.iterator();
        while(iterator.hasNext()){// 是否还有元素
            String s = iterator.next();
            System.out.println(s);// 遍历
            iterator.remove();// 拿一个删除一个
                            // 必须使用Iterator专用删除方法,无需参数,不然也会抛出异常
            // 删除指定元素
//            if(iterator.equals("1")){
//                iterator.remove();
//            }
        }
    }

3.泛型

泛型:早期的Object类可以表示接收任何类型,但是在类型转换时,存在一定的隐患,因此出现了泛型
泛型类型可以添加任何元素,但只能是引用类型,例:Integer
泛型类型默认是 Object类型
泛型可以有多个,例如 在类声明时

/*
 * 泛型:早期的Object类可以表示接收任何类型,但是在类型转换时,存在一定的隐患,因此出现了泛型
 *      泛型类型可以添加任何元素,但只能是引用类型,例:Integer
 *      泛型类型默认是 Object类型
 *      泛型可以有多个,例如 在类声明时
 * */
public class GenericDemo<T> {
                    //  泛型在类声明中使用,可以是多个,例:<T,V,K>
    Object obj;


    public static void main(String[] args) {
        // 向上转型,没问题,但是向下转型可能会有问题
        GenericDemo generic = new GenericDemo();
        generic.obj = 1;
        generic.obj = "1";
        generic.obj = true;

        ArrayList arr = new ArrayList();
        arr.add(1);
        arr.add("2");
        arr.add(true);

        for (int i = 0; i < arr.size(); i++) {
            Object obj = arr.get(i);// 这样是没问题的
            System.out.print(obj);// 1, 2, true
        }
        System.out.println();

        for (int i = 0; i < arr.size(); i++) {
            // String s = arr.get(i);
            /*
             * 这样会直接编译报错,
             * 因为String类与Integer类和Boolean类都是Object类的子类,
             * 但是他们之间没有关联,是"平级的"
             * 因此会编译失败
             * */
            // 这种时候还想要遍历的话就需要加一个判断
            // 但是当一个集合中的数据类型过多的时候,这就会很麻烦
            Object obj = arr.get(i);
            if (obj instanceof String) {
                String s1 = (String) obj;
                System.out.println(s1);
            }
        }

        // 如果使用泛型的话就会直接确定集合元素的类型
        ArrayList<String> alist = new ArrayList<String>();
        // JDK-8 以后可以不用再写后面的类型
        // 类型不对的话,会在添加元素编译的时候直接报错
        // alist.add(1);
        // alist.add(true);
        alist.add("1");
        alist.add("2");
        alist.add("3");
        for (int i = 0; i < alist.size(); i++) {
            System.out.print(alist.get(i));
        }
    }

    // 泛型在方法中使用
    public T test(T t1) {
        return t1;
    }
}

4.Set接口

Set:接口,不允许重复元素

HashSet:无序(不是按照添加顺序排序,而是按照哈希值排序),不可重复

TreeSet:有序(按照元素的自然顺序存储,例如2,1,3——> 1,2,3)不可重复。数据类型必须 实现comparable接口 , 重写compareTo()

1.HashSet

hashSet:无序(不是按照添加顺序排序,而是按照哈希值排序),不可重复
哈希表加链表存储,同一位置可以存储不同内容的元素
底层为hashMap
public native hashcode(),native 意为调用本地系统方法

public static void main(String[] args) {
        Student s1 = new Student(1,"jim1");
        Student s2 = new Student(2,"jim1");
        Student s3 = new Student(3,"jim1");
        Student s4 = new Student(4,"jim4");

        // 添加时根据内容的hash值,再经过hash函数计算得到元素在hash表中存储的位置
        HashSet hashSet = new HashSet();
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        hashSet.add(s4);
        // 如果不在student类中重写hashcode(),那么就会调用Object中hashcode()方法算出对象(对象不同,哈希值就不同)的哈希值

        // 重写Object类中hashCode(),来自己根据对象中包含的内容计算hash值。
        // 向hashSet中添加元素是如何判断重复元素?
        // 底层是双保险,既要提高判断效率,又要安全可靠。
        /*
        * ① 首先通过hashcode()算出添加内容的哈希值,判断hash值在集合中是否存在,
        * 但是有时哈希值可能相同,但内容不同,因此并不安全
        * 效率高,但是可能会出现重复
        * ② 当哈希值相同时,就需要通过equals()足逐个判断元素内容是否相同。
        * 效率底,安全
        * */
        System.out.println(hashSet);
    }
Student类
public class Student {
    private int num;
    private String name;

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

    public Student() {
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

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

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

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

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

2.TreeSet

TreeSet:有序(按照元素的自然顺序存储,例如2,1,3——> 1,2,3)不可重复
数据类型必须 实现comparable接口 , 重写compareTo( )
底层为红黑树

public static void main(String[] args) {
        TreeSet<String> tset  = new TreeSet<String>();
        tset.add("c");
        tset.add("d");
        tset.add("b");
        tset.add("a");

        System.out.println(tset);//[a, b, c, d] 有序,按照内容的自然顺序排序

        // 自定义对象
        Student s1 = new Student(1,"stu1");
        Student s2 = new Student(2,"stu2");
        Student s3 = new Student(3,"stu3");
        Student s4 = new Student(4,"stu1");
        TreeSet<Student> ts = new TreeSet<Student>();

        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);

        // 自己定义的数据类型如果不实现comparable接口,并重写compareTo(),就会报错
        //          java.lang.ClassCastException
        System.out.println(ts);
    }
Student类
public class Student implements Comparable<Student>{
    private int num;
    private String name;

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

    public Student() {
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public int compareTo(Student o) {
        return this.name.compareTo(o.name);
    }

}

5.Map接口

Map:双列存储 ,键 – 值
键不能重复,而值可以重复
键相同时,后面的会将前面的键包括值覆盖
键值去重复 :hashcode (), equals( )
允许有一个为空的键, map.put(null,“q”)
分为三类:

  1. HashMap
  2. TreeMap
  3. Hashtable

1.HashMap

hashMap:无序(通过hashcode(),和equals() 去重复,添加元素)

public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("a", "a");
        map.put("a", "b");
        map.put("c", "c");
        map.put("s", "s");
        map.put("q", "q");
        // 为空的键
        //map.put(null, "q");

        // 清空所有键值对
        //map.clear();

        // 删除指定元素
        //map.remove("a");

        // 得到键为 a的键值对的值
        //System.out.println(map.get("a"));

        // 是否包含指定键
        //System.out.println(map.containsKey("f"));

        // 是否包含指定值
        //System.out.println(map.containsValue("s"));

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

        // 获取长度,即键值对个数
        System.out.println(map.size());
    }

2.TreeMap

treeMap:按照键的自然顺序排序,键的类型所属类必须实现comparable接口,TreeMap根据compareTo( )的逻辑对key进行排序。底层为红黑树。

public static void main(String[] args) {
        TreeMap<String,String> tree = new TreeMap<>();
        tree.put("b","b");
        tree.put("b","c");
        tree.put("a","x");
        tree.put("s","l");
        // 不允许重复,按照键的自然顺序排序
        System.out.println(tree);//{a=x, b=c, s=l}
    }

3.Hashtable

Hashtable: 线程安全的,按照添加顺序排序,底层也是哈希表加单链表
哈希碰撞:哈希值一样,内容不一样。

public static void main(String[] args) {
        Hashtable<String,String> able = new Hashtable<>();
        able.put("b","b");
        able.put("b","c");
        able.put("a","b");
        able.put("c","d");
        // 按照添加顺序排序
        System.out.println(able);// {b=c, a=b, c=d}
    }

4.Map集合遍历

1.keySet( )

获取键的集合;遍历键的集合,获取每一个键;根据键找值

// map遍历一 keySet
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            System.out.println(key + "==" + map.get(key));
        }
2.entrySet( )

获取所有键值对对象的集合;遍历键值对对象的集合,获取到每一个键对对象;根据键值对对象找键和值

// map遍历二  entrySet常用
        Set<Map.Entry<String, String>> entrySet1 = map.entrySet();
        for (Map.Entry<String, String> entrySet : entrySet1) {
            System.out.println(entrySet.getKey() + "==" + entrySet.getValue());
        }

6.Collections

Collections:对集合进行常规操作的类(工具类)

定义的静态方法分为两类:①同步集合对象的方法;②对List排序的方法

public static void main(String[] args) {
        ArrayList<String> arr = new ArrayList<>();
        arr.add("b");
        arr.add("v");
        arr.add("d");
        arr.add("s");

        ArrayList<String> list = new ArrayList<>();
        list.add("i");
        list.add("p");
        list.add("o");
        // 排序
        Collections.sort(arr);
        System.out.println(arr);//[b, d, s, v]
        // 二分搜索,前提是有序有序列表,搜索不到返回负数。
        System.out.println(Collections.binarySearch(arr,"v"));
        // 添加多个元素
        Collections.addAll(arr,"x","k","l");
        System.out.println(arr);//[b, d, s, v, x, k, l]
        // 复制一个列表到另一个列表。目的列表的长度应大于源列表
        Collections.copy(arr,list);
        //              目的  源列表
        System.out.println(arr);//[i, p, o, v, x, k, l]
        // 全部变为A
//        Collections.fill(arr,"A");
//        System.out.println(arr);//[A, A, A, A, A, A, A]
        // 回文
        Collections.reverse(list);
        System.out.println(list);//[o, p, i]
        // 交换两个位置的元素
        Collections.swap(arr,3,4);
        System.out.println(arr);//[i, p, o, x, v, k, l]
    }

若有错误,欢迎私信指正。

本文地址:https://blog.csdn.net/weixin_44734518/article/details/110147554

相关标签: 笔记 java