JAVA集合

11. 集合

11.1 泛型
11.1.1 泛型的定义

泛型:泛指的类型,可以将类型在类与类、方法、接口之间进行传递,类似于方法的传参,其类型由使用方决定

定义了泛型的方法、类、接口称泛型方法、泛型类、 泛型接口,定义时被定义在类名、接口名的后面,小括号、大括号的前面,定义泛型方法时则放在返回值类型之前。当使用泛型类、泛型接口时,需指定泛型的类型,否则默认为Object类型,而在泛型方法中,不能显式设置泛型的类型,必须将泛型在参数中体现出来,⾄少需要有⼀个参数是泛型类型的。。泛型只能被设置为引用数据类型,不能是基本数据类型。

泛型的类型名字,遵循大驼峰命名法,但一般情况下泛型都只用一个大写字母表示。

11.1.2 泛型的使用

例:定义泛型类和泛型接口:

class Person<T,M,D>{
    
}
interface Test<E>{
    void show(E e);
}
class Man extends Person<String>{
    
}
class Woman<E> extends Person<E>{
    
}
class Test1 implements Test{
    @Override
    public void show(Object e){}
}
public class Program3 {
	public static void main(String[] args) {
		Person<String> xiaoming = new Person();
	}
}

下面的例子演示了如何使用泛型方法打印不同字符串的元素:

public class GenericMethodTest
{
   // 泛型方法 printArray                         
   public static < E > void printArray( E[] inputArray )
   {
      // 输出数组元素            
         for ( E element : inputArray ){        
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }

    public static void main( String args[] )
    {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

        System.out.println( "Array integerArray contains:" );
        printArray( intArray  ); // 传递一个整型数组

        System.out.println( "\nArray doubleArray contains:" );
        printArray( doubleArray ); // 传递一个双精度型数组

        System.out.println( "\nArray characterArray contains:" );
        printArray( charArray ); // 传递一个字符型型数组
    } 
}

下面是定义泛型方法的规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的)。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型只能在当前方法、类、接口中使用,不能被继承;继承自泛型类、泛型接口的子类必须指定父类泛型的具体类型。
  • 泛型方法方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
  • 在使用泛型类和泛型接口时需显式标出泛型的类型,而在方法中则必须在方法声明时就在参数中体现泛型类型,在使用泛型方法时根据其参数类型隐式标出泛型的类型。
11.1.3 泛型限定

在调用泛型对象给另一个泛型类型赋值时,需明确泛型的类型,此时在<>内有以下限定:

符号含义
?通配
super 类名A泛型可以是A类及其父类
extends泛型可以是A类及其子类
11.2 集合简介

是一个存储数据的容器,

集合框架被设计成要满足以下几个目标。

  • 该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
  • 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
  • 对一个集合的扩展和适应必须是简单的。

集合与数组的区别:

  1. 数组长度不可变,集合长度可变,并可以及时调整
  2. 数组中可以存储任意数据类型的元素,而集合中只能存储引用数据类型的元素(集合中可以存储包装类)。
  3. 数组方法单一,集合较灵活。

集合框架图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-raQN6S5C-1587711142146)(4.png)]

对集合的操作,按功能分为两大类:

1.增删改查

2.其他功能性操作

11.3 Collection接口

是集合框架中,单列集合的顶级接口,这个接口中定义了对单列集合进行的常规操作。

11.3.1 常用方法(重点在增删):
public static void main(String[] args) {
    //1.通过一个实现类向上转型来实例化一个Collection接口的对象
    Collection<Integer>collection = new ArrayList<>();
    Collection<Integer>collection2 = setData();
    //2.增:在集合末尾添加一个元素
    collection.add(10);
    //3.增:将目标参数集合的元素拼接到该集合的末尾
    collection.addAll(collection);
    //4.删:删除集合中首次出现的目标元素
    //返回值代表删除操作的结果
    boolean boolean4 = collection.remove(20);
    //5.删:删除该集合中所有的在目标集合中出现的所有元素
    boolean boolean5 = collection.removeAll(collection2);
    //6.删:删除满足条件的所有元素,例:删除集合中大于20的元素(重要)
    boolean boolean6 = collection.removeIf(ele->ele>20);
    //7.保留两个集合的交集
    collection.retainAll(collection2);
    //8.清空集合
    collection.clear();
    //9.判断集合中是否包含指定的元素
	boolean ret = collection.contains("Uncle wang");
	//10.判断参数集合中的每⼀个元素是否都在当前集合中包含
	boolean ret1 = collection.containsAll(list);
    //11.判断集合每索引位元素是否完全相同
    collection.equals(collection2);
    //12.返回该集合的元素数量
    int num10 = collection.size();
    //13.判断该集合是否为空
    boolean boolean11 = collection.isEmpty();
    //14.转成 Object 数组
    Object[] array = collection.toArray();
	//15.转成指定类型的数组
	String[] arr = collection.toArray(new String[0]);
    //16.判断集合是否完全相同(先大小,而后依次进行等值比较)
    collection.equals(collection2);
}
private static Collection<Integer> setData() {
    //实例化Collection集合
    Collection<Integer>List = new ArrayList<>();
    List.add(10);
    List.add(200);
    List.add(300);
    return List;
}
11.3.2 Collection集合的迭代

在进⾏集合的遍历的时候,⽅式其实很多。但是,基本上所有的遍历,都与 Iterable 接⼝有关。这个接

⼝提供了对集合集合进⾏迭代的⽅法。只有实现了这个接⼝,才可以使⽤增强for循环进⾏遍历。

  1. 增强for循环

    注意事项:增强for循环中不允许对集合中的元素(长度)进行修改,修改是无效的,否则会出现ConcurrentModificationException,因为不管是增强for循环和forEach都是底层的迭代器实现的,而迭代器是一旦生成,过程中的操作会影响迭代器的运行。

  2. 迭代器

    迭代器Iterator,是⼀个接⼝,Collection集合中有⼀个⽅法 iterator() 可以获取这个接⼝的实现类对象。在这个迭代器中,维护了⼀个引⽤,指向集合中的某⼀个元素。默认指向⼀个集合前不存在的元素,可以认为是下标为-1的元素。

    迭代器的⼯作原理(重点):循环调用 next() 方法进行向后的元素指向,并返回新的指向的元素。同时,在向后进行遍历的过程中,使用 hasNext() 判断是否还有下⼀个元素可以迭代。

    hasNext():判断迭代过程中是否存在下一元素(注意是下一元素而不是当前是否存在元素)

    iterator.next():让迭代器向后指向⼀位,并返回这⼀位的元素

    在迭代器使⽤的过程中,需要注意:

    1. 不允许对集合中的元素进行修改
    2. 不允许对集合的⻓度进⾏修改
    // 1、获取迭代器对象,这⾥的 iterator 是⼀个 Iterator 接⼝的实现类对象
    Iterator<String> iterator = collection.iterator();
    // 2、使⽤迭代器进⾏集合的遍历
    while (iterator.hasNext()) {
         // 让迭代器向后指向⼀位,并返回这⼀位的元素
         String element = iterator.next();
         System.out.println(element);
    }
    

    简单遍历方法(参数是lambda表达式):

    //collection.forEach(ele-> System.out.println(ele));
    collection.forEach(System.out::println);
    
11.4 List接口

List接口是Collection的子接口,继承其一切方法并添加了诸多新方法。

List集合的存储特点

11.4.1 List集合的存储特点

List 集合是Collection接⼝的⼀个子接⼝,继承到了⽗接⼝中所有的⽅法。

  1. List是一个有序的集合:元素添加的顺序和存储的顺序是一致的,因此在LIst集合中存在下标。
  2. List集合中的元素是不去重的(允许重复)。

常⻅的实现类有:ArrayList、LinkedList、Vector、Stack。

ArrayList:是使⽤数组存储数据的容器,查询效率⾼,增删效率低。

LinkedList:是使⽤双向链表存储数据的容器,增删效率⾼,查询效率低。

Vector:是⼀个古⽼的集合,JDK1.0版本时候出现,现在已经被ArrayList和LinkedList替代。

Stack:是⼀个古⽼的集合,JDK1.0版本时候出现,模拟栈结构存储数据。

11.4.2 常用方法
//1.实例化一个ArrayList对象并向上转型为List集合
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(30);
list.add(10);
//2.在当前索引位之后添加元素
list.add(20);
//3.在指定索引位添加元素
list.add(0,20);
//4.在指定索引位添加多个元素()
list.addAll(list);
list.addAll(1,list);
//5.删除索引位的元素(注意:List添加了根据索引值删除的方法,所以根据元素删除需要取元素值,与collection不同)
list.remove(2);
//6.删除元素:根据值删除
list.remove("lily");
list.remove(Integer.valueOf(50));
//7.修改目标索引位的元素
list.set(2, 50);
//8.修改元素:将集合中每个元素都带入apply(T)方法中,用返回值代替当前元素,例:返回(元素X10)
list.replaceAll(t->t*10);
//9.遍历集合,依次将每个元素都带入到方法中,例:依次输出各元素
list.forEach(System.out::println);
//10.截取集合中[fromIndex,toIndex)范围的元素作为新的集合返回
int fromIndex = 1,toIndex = 4;
list.subList(fromIndex,toIndex);  
//11.获取某个元素首次出现的下标
list.indexOf(Object o);
//12.获取某元素最后一次出现的下标
list.LastindexOf(Object o);

**Comparator:**用来做对象比较的函数式接口,里面只有一个抽象方法

int compare(T o1,T o2)
11.4.3 用List实现集合排序(重点):

用lambda表达式对Comparable接口进行重写再通过Arrays方法排序:

public class Program3 {
	public static void main(String[] args) {
		//1.实例化一个List集合
		List<Person>list = new ArrayList<>();
		//2.在集合中添加若干元素
		list.add(new Person("xiaoming", 18, 172));
		list.add(new Person("xiaobai", 22, 160));
		list.add(new Person("xiaohei", 22, 167));
		list.add(new Person("xiaohong", 24, 171));
		list.add(new Person("xiaohuang", 17, 186));
		list.add(new Person("xiaolv", 68, 145));
		list.add(new Person("xiaocheng", 38, 178));
		list.add(new Person("xiaozi", 28, 174));
		list.add(new Person("xiaolan", 78, 167));
		list.add(new Person("xiaohua", 8, 140));
		//需求一:按照年龄对集合元素升序排序
		//法一:自定义一个排序方法
		sort1(list);
		//法二:
		list.sort((o1,o2)->o1.getAge()-o2.getAge());
		//遍历集合
		list.forEach(System.out::println);
		//需求二:按照身高对集合元素降序排序
		list.sort((o1,o2)->o2.getHeight()-o1.getHeight());
		//需求三:以年龄升序为第一需求,身高降序为第二需求排序
		list.sort((o1,o2)->{
			if(o1.getAge()!=o2.getAge()) {return o1.getAge()-o2.getAge();}
			return o2.getHeight()-o1.getHeight();
		});
		list.forEach(System.out::println);
	}
	//自定义排序方法
	private static void sort1(List<Person> list ) {
		for(int i = 0;i<list.size()-1;i++) {
			int swapIndex = i;
			for(int j =i+1;j<list.size();j++) {
				if(compare(list.get(swapIndex),list.get(j))){
					swapIndex = j;
				}
			}
			if(swapIndex!=i) {
				Person temp = list.get(i);
				list.set(i,list.get(swapIndex));
				list.set(swapIndex, temp);
			}
		}
	}
	private static boolean compare(Person p1,Person p2) {
		return p1.getAge()>p2.getAge();
	}
}
class Person{
	private String name;
	private int age;
	private int height;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getHeight() {
		return height;
	}
	public void setHeight(int height) {
		this.height = height;
	}
	public Person(String name, int age, int height) {
		super();
		this.name = name;
		this.age = age;
		this.height = height;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", height=" + height + "]";
	}
	
}
11.4.4 List接口常用实现类:

1.ArrayList:是一个数组实现的集合,增删操作效率低,查询效率高。

2.LinkedList:是一个链表实现的集合,增删操作效率高,查询效率低。

11.4.5 集合的遍历
  1. 增强for循环

  2. forEach方法

  3. 迭代器

  4. 下标遍历

  5. 列表迭代器 ListIterator(重点)

    ListIterator是一个List集合特有的列表迭代器,继承自Iterator接口,添加了功能:

    1. 在迭代过程中使用add、set、remove 对集合元素进行修改**(只能通过迭代器中的方法进行修改)**。
    2. 可以使用hasPrevious和previous实现倒序迭代。
//实例化一个Listiterator迭代器对象
Listiterator<String> iterator = list.listIteratoe();
// 3、在迭代的过程中,修改集合
while (iterator.hasNext()) {
     // 向后指向⼀位,并返回当前指向的元素
     String ele = iterator.next();
     if (ele.equals("Vertu")) {
     // 在迭代的过程中,删除这个元素
     iterator.remove();
     // 在迭代的过程中,添加⼀个元素(加在当前迭代的这个元素的后⾯)
     iterator.add("HTC");
     // 在迭代的过程中,对当前迭代的元素进⾏修改
     iterator.set("Nokia");//注:如果这之前已经remove了当前元素,就不能再修改或添加了
     }
}
  • next:先向后挪动一位指向,再获取当前指向的元素
  • previous:先获取当前指向的元素,再向前挪动一个指向。

声明及迭代方法,例:

List<Integer> list = new ArrayList<>();
for(int i=0;i<10;i++) {
list.add(i+1);
}
//ListIterator:列表迭代器,是Iterator的子接口
ListIterator<Integer> iterator = list.listIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//从索引值(包括索引)开始往后赋值
ListIterator<Integer>listIterator = list.listIterator(5);
11.5 Set接口

Set接口是Collection的子接口

11.5.1 Set集合的存储特点:
  1. Set集合是无序的:元素添加的顺序与存储的顺序不一致。

    注:无序不代表随机,只是按照的存储规则无序。

  2. Set集合是去重的:不允许包含重复元素。

Set接口包含Collection接口的所有方法,没有新方法。

11.5.2 Set集合的去重原理
相同
不同
相同
不同
hashCode
equals
不同元素,不去重
相同元素,去重

Set去重默认是根据内存地址去重,如果需要根据内容判断去重,则需要重写去重方法。

关于hashCode和equals方法的设计,一般情况下都是与一些属性关联的。

在IDEA中Alt+Insert选择重写equals和hashCode方法选择默认模板并选择参数可以快捷重写去重方法。

重写一个hashSet的去重规则(重点,对于TreeSet无效),例:LinkedhashSet:有序的,因为增加维护了一个位置索引,效率略低于hashSet。

11.5.3 TreeSet的排序(重点)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hlGPpvJQ-1587711142149)(E:\文件夹目录\JAVA\课程基础\2.jpg)]

是Set接口的实现类,同时也是SortedSet接口的实现类,自带排序但必须先规定好排序规则。

TreeSet的底层是树;除了保留Set集合的存储特征外,还有一个重要的特征:数据是排序的

注意事项:如果需要保留比较规则校验相同的两个元素,则在定义比较规则最好返回非零数,如果不需保留,直接返回0。

排序一:自定义一种排序方式(此题以年龄升序),注:实现类需实现Comparable接口并重写compareTo方法。

使用场合:通用性,频繁使用同一比较规则时。

public class Program2 {
	public static void main(String[] args) {
		//1.实例化一个TreeSet对象
		TreeSet<Person>treeSet = new TreeSet<>();
		Collections.addAll(treeSet,
				new Person("xiaoming", 18, '男'),
				new Person("xiaohong", 20, '女'),
				new Person("xiaobai", 14, '男'),
				new Person("lilei", 50, '男')
				);
		treeSet.forEach(System.out::println);
	}
}
class Person implements Comparable<Person>{
    private String name;
    private int age;
    private char gender;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public char getGender() {
        return gender;
    }
    public void setGender(char gender) {
        this.gender = gender;
    }
    public Person(String name, int age, char gender) {
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]";
    }
    //重写去重原则中的hashCode方法:绝大部分情况下直接用Object.hash方法返回属性值生成的哈希值
    @Override
    public int hashCode() {
        return Objects.hash(name,age,gender);
    }
    @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 (gender != other.gender)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    //重写Comparable接口,使得Program2的树排序正常运行
    //根据需要返回this 和 o关于某属性的比较结果
    @Override
    public int compareTo(Person o) {
        return this.age-o.age;
    }
}

排序二:通过 TreeSet(Comparator comparator) 的构造方法,通过一个Comparator 的实现类对象实例化一个TreeSet,在comparator中,重新实现compare方法,优先于Comparable的比较规则。

使用场合:偶尔用到的与默认比较规则不同时。

public class Program2 {
	public static void main(String[] args) {
		//1.使用Comparator接口的实例化对象
		Comparator<Person>comparator = (o1,o2)->o1.getAge()-o2.getAge();
		//2.通过有参构造实例化一个TreeSet对象
		TreeSet<Person>treeSet = new TreeSet<>(comparator);
		Collections.addAll(treeSet,
				new Person("xiaoming", 18, '男'),
				new Person("xiaohong", 20, '女'),
				new Person("xiaobai", 14, '男'),
				new Person("lilei", 50, '男')
				);
		treeSet.forEach(System.out::println);
	}
}

TreeSet的去重规则:根据排序规则(Comparable或者Compartor)得到集合的同时做重复判断(返回值为0时,后存储的元素舍去)。

11.6 Collections工具类

Collections是一个用来操作集合的工具类。

List<String> list = new ArrayList<String>();
//常用方法
//1.向某个集合中批量添加元素
Collections.addAll(list,"xiaoming","liuhong","chenzhen","libai","sunwen");
//2.量的替换元素
Collections.replaceAll(list, 2, 20);
//3.每调用一次,对集合元素随机排列
Collections.shuffle(list);		//参数需要是List类型的
//4.使用目标元素填充整个集合
Collections.fill(list, "hello");
//5.将src中的数据拷贝到dest中(dest必须有足够的容量来存储src的数据)
Collections.copy(dest, src);
//6.线程不安全——>线程安全
List<String> synchronizedList= Collections.synchronizedList(list);
// Collections.synchronizedCollection() // 将⼀个线程不安全的Collection集合转成⼀个线程安全的集合
// Collections.synchronizedList() // 将⼀个线程不安全的List集合转成⼀个线程安全的集合
// Collections.synchronizedSet() // 将⼀个线程不安全的Set集合转成⼀个线程安全的集合
// Collections.synchronizedMap() // 将⼀个线程不安全的Map集合转成⼀个线程安全的集合
//以下方法均针对无序集合,例Set等有序集合,不能根据以下方法重新进行排序。
//7.集合倒序
Collections.reverse(list);
//8.1个集合中的最⼤元素,通过元素的Comparable 接⼝中的实现确定⼤⼩规则
int max = Collections.max(list); 
//8.2个指定的⼤⼩⽐较规则,找到⼀个集合中的最⼤元素
max = Collections.max(list, Integer::compareTo); 
//9.1合集合中的最⼩元素,通过元素的Comparable 接⼝中的实现确定⼤⼩规则
Collections.min(list); 
//9.2个指定的⼤⼩⽐较规则,找到⼀个集合中的最⼩元素
Collections.min(list, Integer::compareTo); 
//10.个集合中的元素随机打乱
Collections.shuffle(list); 
//11.个集合中指定的两个下标的值
Collections.swap(list, 2, 3); 
//12.对集合中的元素排序
//12.1按照集合实现的Comparable接口规则进行排序
Collections.sort(list);
//12.2按照指定的排序规则排序
Collections.sort(list, (o1,o2)->o1.compareTo(o2));
Collections.sort(list, (o1,o2)->o1.length-o2.length);
//13.二分查找法,从⼀个集合中查询元素
Collections.binarySearch(list, 10); 
11.7 Map接口

Map是一个无序的、存储双列数据的顶级接口。

  • Map中的每一个元素都是一个键值对。
  • 每个键都是唯一的,若存入已存在的键,则会用新值覆盖原来的值。
  • 在Map中也没有下标的概念。
Key(钥匙的Map保持型)Value(映射的值的类型)
123hello

常用Map方法:

  1. 构造方法:

    //1.通过无参构造实例化对象(如果没有默认的对键的排序规则,则实例化会报错)
    Map<String,Integer>map = new TreeMap<>();
    //2.通过有参构造确定排序依据来实例化对象
    //TreeMap(Comparator)
    Map<String,Integer>map = new TreeMap<>((o1,o2)->o1.length-o2.length);
    

    注意:如果根据键的排序规则,出现了去重现象,此时新值覆盖旧值。

  2. 增:

    // 1、实例化⼀个 Map 接⼝的实现类的对象,并向上转型为 Map 接⼝类型
    Map<String, String> map = new HashMap<>();
    // 2、增,向集合中添加⼀个键值对
    map.put("name", "xiaoming");
    map.put("age", "12");
    map.put("gender", "male");
    // 3、增,如果增的这个键在Map中已经存在,此时会⽤新的值覆盖原来的值
    map.put("age", "20");
    // 4、增,当这个键不存在的时候,才会增; 返回值是需添加的值。
    map.putIfAbsent("age", "30");
    // 5、增,从⼀个Map集合中添加键值对,如果两个Map中存在相同的键,则会⽤新值覆盖原来的值
    map.putAll(tmp);
    
  3. 删:

    // 6、删,按照键删除键值对
    map.remove("age");
    System.out.println(map);
    // 7、删,删除指定的键值对,只有当键和值都能够匹配上的时候,才会删除
    map.remove("name", "xiaobai");
    // 8、删,清空所有的键值对
    map.clear();
    
  4. 改:

    // 9、改,通过键,修改值
    map.replace("gender", "female");
    // 10、改,只有当键和值都能够匹配上,才会修改值
    map.replace("gender", "female", "Unknown");
    // 11、
    /*
     V apply(K key, V oldValue):
     将Map集合中的每⼀个键值对都带⼊到这个⽅法中,⽤返回值替换原来的值
    */
    // 需求: 将现在所有的成绩后⾯添加上"分"
    map.replaceAll((k, v) -> {
     if (k.matches("java|scala|linux|mysql|hadoop")) {
     return v + "分";
     }
     return v;
    });
    System.out.println(map);
    
  5. 查:

    // 12、查询(通过键,查询值)(如果不存在这个键,则结果是 null)
    String value = map.get("java1");
    // 13、查询(通过键查询值,如果不存在这个键,会返回默认的值(defaultVaule此时被设为0))
    String value2 = map.getOrDefault("java1", "0");
    
  6. 其他方法:

    // 1、判断集合中是否包含指定的键
    map.containsKey("java");
    // 2、判断集合中是否包含指定的值
    map.containsValue(98);
    // 3、获取集合中元素的数量(键值对的数量)
    map.size();
    // 4、判断集合是否是⼀个空集合
    map.isEmpty();
    // 5、获取所有的值
    Collection<Integer> values = map.values();
    //6.获取所有的键
    Set<String> keys = map.keySet();
    

Map集合的遍历

  1. 通过 keySet() 遍历

    // 2、获取由所有的 Key 组成的 Set 集合
    Set<String> keys = map.keySet();
    for (String k : keys) {
     System.out.println(String.format("key = %s, value = %s", k, map.get(k)));
    }
    System.out.println("--------------------------");
    
  2. 通过 entrySet() 遍历(需要用Map.Entry类型的对象存储单次遍历的一个键值对,以此进行增强for循环)

    /*
     3、
     Map.Entry<K,V> 是 Map 中的⼀个内部接⼝,⽤来描述集合中的⼀个键值对
     常⻅⽅法:
     1、getKey() 返回这个键值对中的键
     2、getValue() 返回这个键值对中的值
     3、setValue() 设置这个键值对中的值
     entrySet() 返回所有的Entry实现类对象组成的Set集合
    */
    Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
    for (Map.Entry<String, Integer> entry : entrySet) {
         String key = entry.getKey();
         Integer value = entry.getValue();
         //遍历时修改值
         //entry.setValue();
         System.out.println(String.format("key = %s, value = %s", key, value));
    }
    System.out.println("--------------------------");
    
  3. 通过 forEach() 遍历

    // 4、forEach
    /*
     BiConsumer<T, U> 是⼀个函数式接⼝,接⼝中只有⼀个⽅法 void accept(T t, U u)
     这⾥,forEach 的逻辑是:
     将键值对中的每⼀个键和值都带⼊到 accept ⽅法中
    */
    map.forEach((k, v) -> System.out.println(String.format("key = %s, value =%s", k, v)));
    

Map接口常见的实现类

  1. HashMap:是最常⽤的Map集合,底层实现采⽤的是哈希表,访问速度快。
  2. LinkedHashMap:底层实现是链表+哈希表,“有序”。
  3. TreeMap:底层实现是红⿊树,可以对集合中的元素,按照Key进⾏升序排序。排序的依据参考TreeSet,需要让Key对应的类实现 Comparable 接⼝,或者让 TreeMap 通过有参构造进⾏实例化。

HashMap和Hashtable的区别

  1. HashMap是线程不安全的集合,Hashtable是线程安全的集合。
  2. HashMap允许 null 键值,Hashtable不允许。
  3. HashMap是新版本的Map集合,Hashtable是旧版的。HashMap底层的算法效率⽐Hashtable⾼。
  4. HashMap的⽗类是 AbstractMap,Hashtable的⽗类是 Dictionary。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值