java集合框架笔记

java集合框架笔记

集合

什么是集合?

概念:集合是对象的容器,实现了对对象常用的操作。

和数组的区别

1.数组的长度固定,集合长度不固定。

2.数组可以存储基本类型和引用类型,集合只能存储引用类型、

使用前注意导入相应的包 – java.util *

Collection体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6xREBAC-1622650775788)(D:\git\Git\Typora\Typora\1998506-20200830225616629-1434055405.png)]

Collection父接口:

特点:代表任意一组类型的对象,无序,无下标,不能重复。

创建集合的方法: Collection collection = new ArrayList(); --导入java.util.ArrayList

需要掌握:

  1. 增加元素 ------ add方法

  2. 删除元素 -------- remove方法 (删除的是对象 object,因为无下标) clear方法(完全删除)

  3. (重点) 遍历元素

    1.使用增强for(无下标)

    for (Object object:collection) { 输出		
    

​ 2.使用迭代器遍历(迭代器是专门用来遍历集合的一种方式)

​ 1.hasNext(); --//有无下一个元素

​ 2. next(); – 获取下一个元素;

​ 3. remove(); – // 删除当前元素

Iterator it = collection.iterator();
while(it.hasNext()){
    //注意 不能使用collection方法删除元素
    String s = (String) it.next(); 强制转换
     //输出 s
	// 可以使用 it.remove()方法删除元素,但不能使用collection.remove()删除元素,会报并发修改异常

}

  1. 判断 是否存在某一元素 或是否为空

    代码 collection.contains();

    ​ collection.inEmpty();

List子接口

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

创建集合对象

List list = new ArrayList<>();

常用方法

1.添加元素— list.add();

2.删除元素 —

​ 1.使用索引删除 list.remove(索引);

​ 当删除数字与索引矛盾时,对数字进行强制转换 list.remove((Object) 20).— list.remove(new integer(20));

  1. 遍历元素(重点)

  2. 使用for循环

    for(int i=0;i<list.size();i++){
        sout(list.get(i));
    }
    

    2.使用增强for

    for (Object object : list){
        sout(object)
    }
    

    3.使用迭代器

    Iterator it = list.iterator();
    while(it.hasNext()){
        sout(it.next());
        
    }
    

    4.使用列表迭代器

    (注意与迭代器的区别) 列表迭代器可以向前或者向后的遍历,增加,删除,修改元素。

    ListIterator lit = list.listIterator();
    System.out.println("---使用列表迭代器从前往后-------");
            while(lit.hasNext()){
                System.out.println(lit.nextIndex()+":"+lit.next());
                // nextIndex 是下一个的序号标
    
            }
     System.out.println("---使用列表迭代器从后往前-------");
    while(lit.hasPrevious()){
        sout(lit.previousIndex() + ":" + lit.previous() );
    }
    

    5.判断

    sout(list.contains(object)) // 确定的名字
    sout(list.isEmpty()) 是否为空
    

    6.获取下标索引

    list.indexOf();
    
    

    7.返回子集合sublist(x,y) --左开右闭

    List SubList = list.subList(x,y);
    sout(SubList);
    
    

    List 实现类

    ArrayList (重点)

    1. 数组结构实现,必须要连续空间,查询快,增删慢

    2. 运行效率快,线程不安全。

      Vector

      1. 数组结构实现,查询快,增删慢

      2. 版本,运行

        LinkedList

        双向链表结构实现,无需连续空间,增删快,查询慢

      ArrayList

      创建集合 ArrayList arrayList() = new ArrayList();

      1. 添加元素: arrayList.add();

      2. 删除元素: arrayList.remove();

        重写了equals(this == obj)方法

        public boolean equals(Object obj){
          //1 判断是不是同一个对象
          if(this == obj){
            return true;
          }
          //2 判断是否为空
          if(obj == null){
            return false;
          }
          //3 判断是否是Student类型
          if(obj instanceof Student){
            Student == (Student)obj;
            //4 比较属性
            if(this.name.equals(s.getName()) && this.age == s.getAge()){
              return true;
            }
          }
          //5 不满足条件返回false
          return false;
        }
        

遍历元素(重点)

1.使用迭代器

Iterator it = arrayList.iterator();
while(it.hasNext()){
  Student s = (Student)it.next(); //强转
}

2.列表迭代器

ListIterator li = arrayList.listIterator();
while(li.hasNext()){
  Student s = (Student)li.next(); //从前往后遍历
}

while(li.hasPrevious()){
  Student s = (Student)li.previous();//从后往前遍历
}

4.判断

arrayList.contains()

arrayList.isEmpty();

5.查找

arrayList.indexOf();

— 源码分析

DEFAULT_CAPACITY = 10; //默认容量
//注意:如果没有向集合中添加任何元素时,容量0,添加一个后,容量为10
//每次扩容是原来的1.5倍
elementData存放元素的数组
size 实际元素个数

vector

创建集合 – Vector vector = new Vector();

大部分与List相同,特别点:可以使用枚举器遍历

Enumeration en = vector.elements();
while(en.hasmoreElements()){
    String o = (String)en.nextElements();
    sout(o);
}

LinkedList

创建链表集合 LinkedList li = new LinkedList<>();

常用方法与list

泛型

  1. 本质是参数化类型,把类型作为参数传递

  2. 常见形式有泛型类,泛型接口,泛型方法

  3. 语法: T成为类型占位符。表示一种引用类型,可以用多个逗号隔开

  4. 好处: 1.提高代码重用性。2.防止类型转换异常,提高代码安全性

    泛型类

    //写一个泛型类
    public class MyGeneric<T>{
        //1.创建变量
        T t;
        // 2.泛型作为方法的参数
            public void show(T t){
            	sout(t);
        }
        //3.泛型作为方法的返回值
        public T getT(){
            return t;
        }
    }
    
    //使用泛型类
    public class TestGeneric{
      public static void main(String[] args){
        //使用泛型类创建对象
        // 注意: 1. 泛型只能使用引用类型
        //			 2. 不用泛型类型对象之间不能相互赋值
        MyGeneric<String> myGeneric = new MyGeneric<String>();
        myGeneric.t = "hello";
        myGeneric.show("hello world!");
        String string = myGeneric.getT();
        
        MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();
        myGeneric2.t = 100;
        myGeneric2.show(200);
        Integer integer = myGeneric2.getT();
        
      }
    }
    

泛型接口

语法:接口名

注意: 不能泛型静态常量

泛型方法

语法:返回值类型

public class MyGenericMethod{
  //泛型方法
  public <T> T show(T t){
    sout("泛型方法" + t);
    return t;
  }
}

//调用
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("字符串");// 自动类型为字符串
myGenericMethod.show(200);// integer类型
myGenericMethod.show(3.14);// double类型

泛型集合

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

特点:

  • 编译时即可检查,而非运行时抛出异常
  • 访问时,不必类型转换(拆箱)
  • 不同泛型之间应用不能相互赋值,泛型不存在多态

Set集合

Set子接口

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

​ 方法:全部继承字Collection的方法

 //创建集合
        Set<String> set = new HashSet<>();
        // 1.添加元素 --无序
		//删除
		// 遍历
        //1.使用增强for
		//2.使用迭代器
		 //判断

Set实现类

### HashSet 重点

基于HashCode计算元素存放位置

​ 当存入元素的哈希码相同时,会调用equals方法确认,若结果为true,则拒绝存入

​ HashSet集合的使用,存储结构(哈希表):(数组加链表加红黑树)

//新建集合
        HashSet<String> hashSet = new HashSet<String>();
        // 1.添加元素
//删除
//遍历
        //3.1 增强for
		 //3.2 迭代器
HashSet 的使用
存储结构: 哈希表(数组加链表+红黑树)
存储过程(重复依据)1)。根据HashCode,计算保存的位置
(2)。再执行equals方法,如果equals为true,则认为是重复,否则,形成链表

    实现类
     HashSet<Person> persons = new HashSet<Person>();
        //1.添加数据
        //遍历
//3.1 增强for
//3.2 迭代器
 //判断 contains , isEmpty();

一个小问题://注:假如相同属性便认为是同一个对象,该怎么做?

答案:可以重写hashCode和equals代码:

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Person other = (Person) obj;
    if (age != other.age)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}
//为什么使用pirme = 31?
1.31是一个质数,这样的数字在计算时可以尽量减少散列冲突。
2.可以提高执行效率,因为31*i=(i<<5)-i,31乘以一个数可以转换成移位操作,这样能快一点;但是也有网上一些人对这两点提出质疑。

TreeSet

  • 基于排序顺序实现不重复。
  • 实现了SortedSet接口,对集合元素自动排序。
  • 元素对象的类型必须实现Comparable接口,指定排序规则。
  • 通过CompareTo方法确定是否为重复元素。
使用TreeSet保存数据
存储结构:红黑树
要求:元素必须要实现Comparable接口 compareTo()方法返回值为0,认为是重复元素
    //创建集合
        TreeSet<Person> persons = new TreeSet<>(); //有创建Person类
基本操作与Conection一致

查看Comparable接口的源码,发现只有一个compareTo抽象方法,在/Person/的类中实现它:

public class Person implements Comparable<Person>{
    @Override
	//1.先按姓名比
	//2.再按年龄比
	public int compareTo(Person o) {
		int n1=this.getName().compareTo(o.getName());
		int n2=this.age-o.getAge();
		return n1==0?n2:n1;
	}
}

除了实现Comparable接口里的比较方法,TreeSet也提供了一个带比较器Comparator的构造方法,使用匿名内部类来实现它:

/**
 * TreeSet的使用
 * Comparator:实现定制比较(比较器)
 */
public class Demo5 {
	public static void main(String[] args) {
		TreeSet<Person> persons=new TreeSet<Person>(new Comparator<Person>() {
			@Override
			public int compare(Person o1, Person o2) {
				// 先按年龄比较
				// 再按姓名比较
				int n1=o1.getAge()-o2.getAge();
				int n2=o1.getName().compareTo(o2.getName());
				return n1==0?n2:n1;
			}			
		});
		Person p1=new Person("tang",21);
		Person p2=new Person("he", 22);
		Person p3=new Person("yu", 21);
		persons.add(p1);
		persons.add(p2);
		persons.add(p3);
		System.out.println(persons.toString());
	}
}

接下来我们来做一个小案例:

/**
 * 要求:使用TreeSet集合实现字符串按照长度进行排序
 * helloworld tangrui hechengyang wangzixu yuguoming
 * Comparator接口实现定制比较
 */
public class Demo6 {
	public static void main(String[] args) {
		TreeSet<String> treeSet=new TreeSet<String>(new Comparator<String>() {
			@Override
			//先比较字符串长度
			//再比较字符串
			public int compare(String o1, String o2) {
				int n1=o1.length()-o2.length();
				int n2=o1.compareTo(o2);
				return n1==0?n2:n1;
			}			
		});
		treeSet.add("helloworld");
		treeSet.add("tangrui");
		treeSet.add("hechenyang");
		treeSet.add("yuguoming");
		treeSet.add("wangzixu");
		System.out.println(treeSet.toString());
        //输出[tangrui, wangzixu, yuguoming, hechenyang, helloworld]
	}
}

Map体系接口

Map接口的特点:

​ 1.用于存储任意键值对(key-value)

​ 2.键: 无序,无下标,不允许重复(唯一)

​ 3.值:无序,无下标,允许重复、

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fi8MFhw0-1622650775791)(C:\Users\阳爹\Desktop\fe47000396f10c5dba2a.png)]

Map集合概述

特点:存储一对数据(key-value),无序,无下标,键不可重复、

导入包

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Map接口的使用
特点:1.存储键值对。2.键不能重复,值可以重复,3.无序
    //创建Map集合
        Map<String,String> map = new HashMap<>();
 //2.删除// map.remove("cn");
//遍历
        // 3.1使用keySet()
 Set<String> keyset = map.keySet();
		 //3.2使用entrySet方法
 Set<Map.Entry<String,String>> entries = map.entrySet();
 //判断
        System.out.println(map.containsKey("cn"));
        System.out.println(map.containsValue("泰国"));

Map集合的实现类

HashMap集合的使用(重点)
存储结构:哈希表(数组加链表加红黑树)
使用key可 hashcode和equals作为重复 保证没有重复

  //创建集合
        HashMap<Student,String> students =new HashMap<Student,String>();
//创建hashmap之后没有添加元素 table=null, size=0。 目的:节省空间
        //添加元素 - put();
//2.删除
//3.遍历
        //3.1 使用keySet();
 for(Student key:students.keySet()){
            System.out.println(key.toString() + students.get(key));

        }
//3.2使用entrySet();
 for (Map.Entry<Student,String> entry:students.entrySet()
             ) {
            System.out.println(entry.getKey() + entry.getValue());

            
        }
//4.判断
        System.out.println(students.containsKey(new Student("孙悟空",100)));

        System.out.println(students.containsValue("杭州"));
  • HashMap源码分析
  • 默认初始化容量:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    • 数组最大容量:static final int MAXIMUM_CAPACITY = 1 << 30;
  • 默认加载因子:static final float DEFAULT_LOAD_FACTOR = 0.75f;

  • 链表调整为红黑树的链表长度阈值(JDK1.8):static final int TREEIFY_THRESHOLD = 8;

  • 红黑树调整为链表的链表长度阈值(JDK1.8):static final int UNTREEIFY_THRESHOLD = 6;

  • 链表调整为红黑树的数组最小阈值(JDK1.8):static final int MIN_TREEIFY_CAPACITY = 64;

  • HashMap存储的数组:transient Node<K,V>[] table;

  • HashMap存储的元素个数:transient int size;

    • 默认加载因子是什么?
      • 就是判断数组是否扩容的一个因子。假如数组容量为100,如果HashMap的存储元素个数超过了100*0.75=75,那么就会进行扩容。
    • 链表调整为红黑树的链表长度阈值是什么?
      • 假设在数组中下标为3的位置已经存储了数据,当新增数据时通过哈希码得到的存储位置又是3,那么就会在该位置形成一个链表,当链表过长时就会转换成红黑树以提高执行效率,这个阈值就是链表转换成红黑树的最短链表长度;
    • 红黑树调整为链表的链表长度阈值是什么?
      • 当红黑树的元素个数小于该阈值时就会转换成链表。
    • 链表调整为红黑树的数组最小阈值是什么?
      • 并不是只要链表长度大于8就可以转换成红黑树,在前者条件成立的情况下,数组的容量必须大于等于64才会进行转换。

    HashMap的数组table存储的就是一个个的Node<K,V>类型,很清晰地看到有一对键值,还有一个指向next的指针(以下只截取了部分源码):

    static class Node<K,V> implements Map.Entry<K,V> {
          final K key;
          V value;
          Node<K,V> next;
      }
    
HashSet源码分析

了解完HashMap之后,再回过头来看之前的HashSet源码,为什么放在后面写你们看一下源码就知道了(部分):

public class HashSet<E>
      extends AbstractSet<E>
      implements Set<E>, Cloneable, java.io.Serializable
  {
      private transient HashMap<E,Object> map;
      private static final Object PRESENT = new Object();
      public HashSet() {
          map = new HashMap<>();
      }
  }

可以看见HashSet的存储结构就是HashMap,那它的存储方式是怎样的呢?可以看一下add方法:

public boolean add(E e) {
      return map.put(e, PRESENT)==null;
  }

很明了地发现它的add方法调用的就是map的put方法,把元素作为map的key传进去的。

Hashtable

  • JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。

  • 初始容量11,加载因子0.75。

    这个集合在开发过程中已经不用了,稍微了解即可。

Properties
  • Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。

它继承了Hashtable的方法,与流关系密切,此处不详解。

TreeMap

实现了SortedMap接口(是Map的子接口),可以对key自动排序

/**
 * TreeMap的使用
 * 存储结构:红黑树
 */
public class Demo3 {
	public static void main(String[] args) {
		TreeMap<Student, Integer> treeMap=new TreeMap<Student, Integer>();
		Student s1=new Student("tang", 36);
		Student s2=new Student("yu", 101);
		Student s3=new Student("he", 10);
		//1.添加元素
		treeMap.put(s1, 21);
		treeMap.put(s2, 22);
		treeMap.put(s3, 21);
		//不能直接打印,需要实现Comparable接口,因为红黑树需要比较大小 - 改写compareTo方法(下面)
		System.out.println(treeMap.toString());
		//2.删除元素
		treeMap.remove(new Student("he", 10));
		System.out.println(treeMap.toString());
		//3.遍历
		//3.1 使用keySet()
		for (Student key : treeMap.keySet()) {
			System.out.println(key+" "+treeMap.get(key));
		}
		//3.2 使用entrySet()
		for (Entry<Student, Integer> entry : treeMap.entrySet()) {
			System.out.println(entry.getKey()+" "+entry.getValue());
		}
		//4.判断
		System.out.println(treeMap.containsKey(s1));
		System.out.println(treeMap.isEmpty());		
	}
}

在学生类中实现Comparable接口:

public class Student implements Comparable<Student>{
    @Override
    public int compareTo(Student o) {
        int n1=this.id-o.id;
        return n1;
}

除此之外还可以使用比较器来定制比较

TreeMap<Student, Integer> treeMap2=new TreeMap<Student, Integer>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        // 略
        return 0;
    }			
});

Collections工具类

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

方法: //sort排序 //binarySearch 二分查找 返回下标 // copy复制 //reverse() 反转

//补充:list转成数组 //数组转成集合//把数组转成集合,这个集合是一个受限制的集合,不能增加和删除

//把基本类型数组转成集合时,需要修改为包装类型

public class demo4 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(10);
        list.add(78);
        list.add(8);
        //sort排序
        System.out.println("排序之前" + list.toString());
        // Collections.sort(list);
        System.out.println("排序之后" + list.toString());

        //binarySearch 二分查找 返回下标
        int i = Collections.binarySearch(list, 10);
        System.out.println(i);
        // copy复制
        List<Integer> dest = new ArrayList<>();
        for (int j = 0; j < list.size(); j++) {
            dest.add(0);

        }
        Collections.copy(dest, list); //要求集合大小一样
        System.out.println(dest.toString());

        //reverse() 反转
        Collections.reverse(list);
        System.out.println(list.toString());
        //shuffle 打乱
        Collections.shuffle(list);
        System.out.println("打乱之后" + list.toString());

        //补充:list转成数组
        System.out.println("---------list转成数组-----");

        Integer[] arr = list.toArray(new Integer[4]);
        System.out.println(arr.length);
        System.out.println(Arrays.toString(arr));
        //数组转成集合
        System.out.println("-----数组转成集合------");
        String[] names = {"张三","例子","李四"};
        List<String> list2 = Arrays.asList(names);
        System.out.println(list2);
        //把数组转成集合,这个集合是一个受限制的集合,不能增加和删除

        System.out.println("-----");
        //把基本类型数组转成集合时,需要修改为包装类型
        Integer[] nums = {100,200,300,400};
        List<Integer> list3 = Arrays.asList(nums);
        System.out.println(list3);
    }
}
erse(list);
        System.out.println(list.toString());
        //shuffle 打乱
        Collections.shuffle(list);
        System.out.println("打乱之后" + list.toString());

        //补充:list转成数组
        System.out.println("---------list转成数组-----");

        Integer[] arr = list.toArray(new Integer[4]);
        System.out.println(arr.length);
        System.out.println(Arrays.toString(arr));
        //数组转成集合
        System.out.println("-----数组转成集合------");
        String[] names = {"张三","例子","李四"};
        List<String> list2 = Arrays.asList(names);
        System.out.println(list2);
        //把数组转成集合,这个集合是一个受限制的集合,不能增加和删除

        System.out.println("-----");
        //把基本类型数组转成集合时,需要修改为包装类型
        Integer[] nums = {100,200,300,400};
        List<Integer> list3 = Arrays.asList(nums);
        System.out.println(list3);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值