[java]7、Collection集合

2021-10-07  本文已影响0人  史记_d5da

1、集合和数组的区别

数组的长度是固定的。集合的长度是可变的。
数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

2、分类

1、集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection和双列集合java.util.Map

3、 Iterator迭代器

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
Iterator接口的常用方法如下:
public E next():返回迭代的下一个元素。
public boolean hasNext():如果仍有元素可以迭代,则返回 true。

public class IteratorDemo {
    public static void main(String[] args) {
        // 使用多态方式 创建对象
        Collection<String> coll = new ArrayList<String>();

        // 添加元素到集合
        coll.add("串串星人");
        coll.add("吐槽星人");
        coll.add("汪星人");
        //遍历
        //使用迭代器 遍历   每个集合对象都有自己的迭代器
        Iterator<String> it = coll.iterator();
        //  泛型指的是 迭代出 元素的数据类型
        while(it.hasNext()){ //判断是否有迭代元素
            String s = it.next();//获取迭代出的元素
            System.out.println(s);
        }
    }
}

3、泛型

含有泛型的方法,在调用方法的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型

public class Demo01 {
    // 定义一个含有泛型类型的方法
    public <E> void method(E e) {
    }
} 

2、泛型的通配符
代表任意的数据类型
不能创建对象使用,只能作为方法的参数使用
例如
定义一个方法,能遍历所有类型的ArrayList集合
这个时候我们不知道ArrayList集合使用什么数据类型,可以泛型的通配符?来接收数据类型
泛型没有继承的概念

public static void printArray(ArrayList<?> list) {
    Iterator<?> it = list.iterator();
    while (it.hasNext()) {
        System.out.println(it.next());
    }
}

3、通配符高级使用----受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限下限
泛型的上限
格式类型名称 <? extends E > 对象名称
意义只能接收 E 及其子类
泛型的下限
格式类型名称 <? super E > 对象名称
意义只能接收E及其父类型

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement(list1);
    getElement(list2);//报错
    getElement(list3);
    getElement(list4);//报错
  
    getElement2(list1);//报错
    getElement2(list2);//报错
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}

4、Set接口

set接口特点
1)、不允许存储重复元素
2)、没有索引,没有带索引的方法,也不能使用普通的for循环
HashSet特点:
1)、不允许存储重复的元素
2)、没有索引,没有带索引的方法,也不能使用普通的for循环
3)、是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4)、底层是一个hash表结构(查询的速度非常快)
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出啦得到地址,不是数据实际存储的物理地址)
int hasCode()返回该对象的哈希码值
HashSet集合存储数据的结构(哈希表)
jdk1.8版本之后
哈希表 = 数组 + 链表;
哈希表 = 数组 + 红黑树(提高查询的速度)

哈希表
3、Hash存储过程
HashSet<String> set = new HashSet<>();
String s1 = new String( original: "abc");
String s2 = new String( original: "abc");
set.add(s1);
set.add(s2);
set.add("种地");
set.add("通话");
set.add("abc");
System.out.println(set); 

Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals方法,判断元素是否重复
set.add(s1);
add 方法会调用s1的hashCode方法,计算字符串"abc"的哈希值,哈希值是96354在集合中没有找到96354这个元素,会把s1存储到集合中
set.add(s2);
add方法会调用s2的hashCode方法,计算字符串"abc"的哈希值是96354,在集合中找到相同的hash值,发现有哈希冲突,s2会调用equals方法和哈希值相同的元素进行比较,s2.equals(s1),返回true,两个元素的哈希值相同,就不会把元素存储到集合中。

5、可变参数

使用前提:
当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数

public static int add(int ...arr) {
    System.out.println(arr); //[I@2ac1fd4 底层是一个数组]
    System.out.println(arr.length);
    return 0;
}

6、map

1、Map集合的第一种遍历方式:通过键找值的方式
Map集合中的方法:
Set<K> keySet() 返回此映射中包含的键的 Set 视图。
实现步骤:
1)、使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
2)、遍历set集合,获取Map集合中的每一个key
3)、通过Map集合中的方法get(key),通过key找到value

//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖",165);
map.put("林志玲",178);

//1.使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
Set<String> set = map.keySet();

//2.遍历set集合,获取Map集合中的每一个key
//使用迭代器遍历Set集合
Iterator<String> it = set.iterator();
while (it.hasNext()){
     String key = it.next();
     //3.通过Map集合中的方法get(key),通过key找到value
     Integer value = map.get(key);
     System.out.println(key+"="+value);
}
System.out.println("-------------------");
//使用增强for遍历Set集合
for(String key : set){
     //3.通过Map集合中的方法get(key),通过key找到value
     Integer value = map.get(key);
     System.out.println(key+"="+value);
}
System.out.println("-------------------");
//使用增强for遍历Set集合
for(String key : map.keySet()){
     //3.通过Map集合中的方法get(key),通过key找到value
     Integer value = map.get(key);
     System.out.println(key+"="+value);
}

2、Map集合遍历的第二种方式:使用Entry对象遍历
Map集合中的方法:
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的 Set 视图。
实现步骤:
1)、使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
2)、遍历Set集合,获取每一个Entry对象
3)、使用Entry对象中的方法getKey()和getValue()获取键与值

//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖",165);
map.put("林志玲",178);

//1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
Set<Map.Entry<String, Integer>> set = map.entrySet();

//2.遍历Set集合,获取每一个Entry对象
//使用迭代器遍历Set集合
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while(it.hasNext()){
      Map.Entry<String, Integer> entry = it.next();
      //3.使用Entry对象中的方法getKey()和getValue()获取键与值
      String key = entry.getKey();
      Integer value = entry.getValue();
      System.out.println(key+"="+value);
}
System.out.println("-----------------------");
for(Map.Entry<String,Integer> entry:set) {
      //3.使用Entry对象中的方法getKey()和getValue()获取键与值
      String key = entry.getKey();
      Integer value = entry.getValue();
      System.out.println(key+"="+value);
}

3、Hashtable
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程结合,速度慢
HashMap:底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢。
HashMap集合(之前学的所有的集合):可以存储null值;null键
Hashtable集合,不能存储null值;null键
Hashtable和Vector集合一样,在jdk1.2版本被先进的集合取代
Hashtable的子类Properties依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合
4、JDK9新特性:of
List接口、Set接口、Map接口:里边增加了一个静态的方法of,可以给集合一次性添加多个元素
static<E> List<E> of (E ... elements)
使用前提:当集合中存储的元素个数已经确定了,不在改变时使用
注意:
1)、of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
2)、of方法的返回值是一个不能改变的集合,集合不能在使用add,put方法添加元素,会抛出异常
3)、Set接口和Map接口在调用of方法的时候,不能有重复元素,否则会抛异常

List<String> list = List.of("a", "b", "a", "c", "d");
System.out.println(list);//[a, b, a, c, d]
//list.add("w");//UnsupportedOperationException:不支持操作异常

//Set<String> set = Set.of("a", "b", "a", "c", "d");//IllegalArgumentException:非法参数异常,有重复的元素
Set<String> set = Set.of("a", "b", "c", "d");
System.out.println(set);
//set.add("w");//UnsupportedOperationException:不支持操作异常

//Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20,"张三",19);////IllegalArgumentException:非法参数异常,有重复的元素
Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
System.out.println(map);//{王五=20, 李四=19, 张三=18}
//map.put("赵四",30);//UnsupportedOperationException:不支持操作异常

7、Debug

Debug调试程序:
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处
执行程序:
f8:逐行执行程序
f7:进入到方法中
shift+f8:跳出方法
f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
ctrl+f2:退出debug模式,停止程序
Console:切换到控制台

上一篇下一篇

猜你喜欢

热点阅读