java集合框架

java集合框架

  • 概念:对象的容器,定义了对多个对象进行操作的常用方法。可以实现数组的功能。

  • 和数组的区别:

  1. 数组长度固定,集合长度不固定
  2. 数组可以存储基本数据类型和引用数据类型,集合只能存储引用数据类型(存储基本数据类型自动装箱)

Collection类

所有集合类的父接口

集合体系结构:包括List接口和Set接口的区别

Collection特点:代表一组任意类型的对象,无序、无下标

各元素对象之间没有指定的顺序,允许有重复元素和多个Null元素对象。所以不可以排序,也不可以找出第几个第几个元素。

方法:

        Collection collection = new ArrayList();
        //添加
        collection.add("苹果");
        collection.add("西瓜");
        collection.add("葡萄");
        System.out.println(collection.size());
        System.out.println(collection);//相当于调用toString
//        删除
        collection.remove("苹果");
        System.out.println(collection);
//        清除
//        collection.clear();

//        遍历
//        方法一,因为collection无下标所以不要用for-i
        for (Object o : collection) {

        }
//        方法二:迭代器(专门遍历集合的一种方式),Iterator是一个接口
        Iterator it = collection.iterator();
        //是否有下一个元素
        it.next();
        it.remove();//迭代器中只能用这种方法删除,不能用本来的删除,删除的是栈存储的地址,通过equals方法
        while (it.hasNext()){
            //等于下一个元素
            String s =(String) it.next();
            System.out.println(s);
        }


//        判断
        System.out.println(collection.contains("葡萄"));
		System.out.println(collection.isEmpty());

/*
3
[苹果, 西瓜, 葡萄]
[西瓜, 葡萄]
葡萄
true
false

List类

特点:有序、有下标、元素可以重复

在拥有父类的方法之外,List特有方法

另外List也有特殊的迭代器列表迭代器ListIterator可以向前或者向后遍历:

List list = new ArrayList();
//       添加
        list.add(0,"苹果");
        list.add("西瓜");
// 列表迭代器
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()){
            System.out.println(listIterator.nextIndex()+":"+listIterator.next());
        }
        System.out.println("------从后往前---------------");
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.nextIndex()+":"+listIterator.previous());
        }

        //查询位置
        System.out.println(list.indexOf("苹果"));

/*
0:苹果
1:西瓜
------从后往前---------------
2:西瓜
1:苹果
0

list删除数字:

List list = new ArrayList();
list.add(1);
list.add(2);
//直接输入数字会被认为是下标,又因为集合的基本数据类型经过了装箱,所以这样写
list.remove((Object)1);或者new Integer(1)也可以
System.out.println(list);
//[2]

其他方法不再演示

List的实现类:ArrayList,Vector,LinkedList

ArrayList类

  • 以数组结构实现,查询快、增删慢
  • 运行效率快、线程不安全
  • List的实现类
ArrayList arrayList = new ArrayList();

一些源码分析:

  1. 默认容量:DEFAULT_CAPACITY = 10,没添加如何元素0,大于10就是元素个数;
  2. 存放元素的数组:elementData
  3. 实际元素个数:size

Vector类

  • 数组结构实现,查询快、增删慢
  • 运行效率慢、线程安全
  • 用的少
  • List的实现类

创建方法同上,方法自己看文档

LinkedList类

  • 链表结构(双向链表)实现,增删快、查询慢。

增删改查方法类似上面,不在赘述

至于链表结构学了c或者数据结构应该都懂吧

泛型

本质上是参数化类型,把类型当做参数传递

常见形式有泛型类、泛型接口和泛型方法

语法:

<T,...>,T是类型占位符,表示一种引用类型,可以写多个

作用:

提高代码重用性

防止类型转换异常,提高安全性

泛型类

public class MyGeneric <T>{
    T t;
    public  void show(T t){
//        T t1 = new T();  这是不合法,不能new因为不确定类型
        System.out.println(t);
    }

    public T getT(){
        return  t;
    }

    public static void main(String[] args) {
        //泛型类中必须是引用数据类型,基本数据类型就用包装类。右边的String可写可不写
        MyGeneric<String> myGeneric = new MyGeneric<String>();
        myGeneric.t="hello";
        System.out.println(myGeneric.t);
        myGeneric.show("大家好");
        
    }
}
/*
hello
大家好

泛型接口

泛型接口基本和泛型类类似,只不过其他类实现它时传入引用类型但是当实现泛型接口时也不确定如下,后面声明类的时候再传

public class  Student  implements MyGeneric<String>{}
public class  Student<T>  implements MyGeneric<T>{}

泛型方法

public class MyGeneric {
    //先声明泛型方法,之后可以返回类型或者在参数使用泛型
    public <T>  T show(T t){
        return t;
    }

    public static void main(String[] args) {
        MyGeneric myGeneric = new MyGeneric();
//        泛型类型由传入的数据类型决定
        myGeneric.show("大家好");
        myGeneric.show(1);

    }
}

泛型好处

  • 提高重用性

  • 防止类型转换异常

泛型集合

参数化类型、类型安全的集合,强制集合元素的类型必须一致

ArrayList<String> list = new ArrayList<String>();
//不写泛型默认是Object

当不使用泛型时

ArrayList list = new ArrayList();
list.add("aa");
list.add(1);
for (Object o : list) {
    String s= (String) o;
}
/*
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')

Set类

特点:无序、无下标、元素不可重复

各元素对象之间没有指定的顺序,不允许有重复元素,最多允许有一个Null元素对象

一个不包含重复元素的Collection,方法和Collection完全一样

继承Collection,是接口

        Set<String> set = new HashSet<>();
//        增删改查同Collection

Set的实现类:HashSet,TreeSet

HashSet类

  • 基于HashCode计算元素的存放位置
  • 存储结构:哈希表(数组+链表+红黑树)
  • 当存入的一个元素时如果对应哈希码数组位置为空直接存入,如果已有元素会调用equals进行确认,如果为true,则拒绝存入;为false,存储在数组同一个位置与已有元素形成链表(返回哈希值,有方法hashCode)(另外删除等其他方法时同理也是通过hashCode和equals方法)
HashSet<String> hashSet = new HashSet<>();

TreeSet类

  • 基于排序顺序实现元素不重复
  • 实现了SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • 通过Comparable的一个compareTo方法确定是否为重复元素
  • 存储结构:红黑树结构(二叉查找树的一种)
TreeSet<String> treeSet = new TreeSet<>();
treeSet.add("b");
treeSet.add("a");
treeSet.add("c");
treeSet.add("c");
System.out.println(treeSet);
//根据字典序排序,重复的不添加
//out:[a, b, c]

删除等操作类似

要求:TreeSet如果要装入对象,对象必须实现Comparable(泛型接口)重写compareTo方法

public class  Student  implements  Comparable<Student>{
    String name="11";
    int age=11;
    //先按姓名再按照年龄比,相同返回0
    @Override
    public int compareTo(Student o) {
        //String的compareTo:相同返回0
        int n1 = this.name.compareTo(o.name);
        int n2 = this.age-o.age;
        //如果name相同n2否则返回n1
        return  n1==0 ? n2:n1;
    }
    
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet<>();
        Student s1 = new Student();
        treeSet.add(s1);
    }
}
//删除等其他操作同理

Comparator和Comparable

上文提到如果TreeSet要装入自定义的类的话需要实现Comparable类,事实上也可以通过实现Comparator装入

  • Comparable:可比较的
  • Comparator:实现定制比较(比较器)
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        //比较方法:自己根据项目要求写,相同返回0,上面Comparable的compareTo也是同理
        return 0;
    }
});
Student s1 = new Student();
treeSet.add(s1);

Map集合

特点:

  1. 用来存储键值对
  2. 键:无序、无下标、不允许重复
  3. 值:无序、无下标、运行重复
  4. 是接口

常用方法:

Map<String,String> map = new HashMap<>();
map.put("CHA","中国");
map.put("USA","美国");
map.put("UK","英国");
//替换掉键值对上一个值
map.put("UK","联合王国");

System.out.println(map.size());
System.out.println(map.toString());
//删除
map.remove("UK");
System.out.println(map.toString());
//使用KeySet()遍历:得到一个存储了键的Set
System.out.println("keySet遍历-----------------");
Set<String> keySet = map.keySet();
for (String s : keySet) {
    //get通过键得到值
    System.out.println(s+":"+map.get(s));
}
//使用entrySet方法遍历:得到一个存储键值对的Map.Entry:效率更高
System.out.println("entrySet方法遍历-------------");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
    System.out.println(entry.getKey()+":"+entry.getValue());
}
//判断
System.out.println(map.containsKey("USA"));
System.out.println(map.containsValue("英国"));

/*
3
{USA=美国, UK=联合王国, CHA=中国}
{USA=美国, CHA=中国}
keySet遍历-----------------
USA:美国
CHA:中国
entrySet方法遍历-------------
USA:美国
CHA:中国
true
false


Map集合的实现类:HashMap,Hashtable,TreeMap

HashMap类

  • 运行效率高,线程不安全;运行使用null作为key或者value
  • 实现Map
  • 存储结构:哈希表
  • 区别于hashset(默认容量10,但是元素个数<0时为空Hashmap一样)默认容量16,加载因子(元素大于容量的0.75(阈yu值)开始扩容,扩容为阈值两倍)0.75,链表长度或者数组长度大于一定数目时链表可能变成红黑树。jdk1.8之前是头插入,之后是尾插入
HashMap<String,String> hashMap = new HashMap<>();

方法和Map方法一样,

存储方式看hashSet,完全类似,使用key的hashcode和equals比较

另外HashSet源码实际上用的就是HashMap

Hashtable类

  • 线程安全,运行效率慢,不允许null作为key或者value
  • 用的少
  • 存储结构是哈希表
  • 子类Properties

方法类似不在赘述

Proeryies类

要求key和value都是String。通常用于配置文件读取

是Hashtable的子类

这里暂且忽略

TreeMap类

  • 实现了SortedMap接口(一个Map的子接口),可以对key自动排序
  • 存储结构:红黑树
  • 类似TreeSet存储类需要实现Comparable泛型接口(或者Comparable),重写相应方法
TreeMap<Student,String> treeMap = new TreeMap<>();


public class  Student  implements  Comparable<Student>{}

Collections工具类

集合工具类,定义了除了存取以外的集合常用方法

全是静态方法

List<Integer> list = new ArrayList<>();
    list.add(20);
    list.add(5);
    list.add(12);
    //sort排序:默认升序,可以直接通过Comparator自定义比较方法
        Collections.sort(list);
//        Collections.sort(list, new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                return 0;
//            }
//        });
        System.out.println(list);
//        binarySearch查找:找到返回下标否则返回负值
        int i=Collections.binarySearch(list,12);
        System.out.println(i);
//        copy复制:必须要集合一样大,直接这样是不行的,需要如下
        List<Integer> list1 = new ArrayList<>();
        //大小添加到3
        for (int j = 0; j < 3; j++) {
            list1.add(0);
        }
        Collections.copy(list1,list);
        System.out.println(list1);
//        reverse反转
        Collections.reverse(list1);
        System.out.println(list1);
//        shuffle打乱
        Collections.shuffle(list);
        System.out.println(list);
/*
[5, 12, 20]
1
[5, 12, 20]
[20, 12, 5]
[5, 20, 12]

list和数组之间的相互转换

    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
//    list转数组:右边括号内Integer个数小于或等于list个数左边得到就是list个数
//        大于list个数在list个数基础上补null到该个数
    Integer[] arr = list.toArray(new Integer[0]);
    //数组需要这种方式,不能直接打印
    System.out.println(Arrays.toString(arr));
//    数组转集合
    String[] name = {"张三","李四"};
    //受限集合不能添加或删除
    List<String> list1 =  Arrays.asList(name);
    System.out.println(list1);
    //基本类型数组转的时候需要封装类
    Integer[] a = {1,2,3};
    List<Integer> list2 = Arrays.asList(a);

/*
[1, 2]
[张三, 李四]
[1, 2, 3]

热门相关:仙城纪   修仙界最后的单纯   重生当学神,又又又考第一了!   无限杀路   重生之至尊千金