用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
# finally -> 02 【Collection、泛型】 ## 1.集合 ### 1.1集合与数组 ##### 集合的概述: 1. 数组是一种容器,集合也是一种容器,都可以存放多个数据。 2. 数组的长度一旦确定,运行期间不可改变;但是大多数集合的长度可以变化。 3. 曾经已经学习过的ArrayList类,只是多种集合当中的一种而已。 4. 数组当中的数据类型必须统一,但是集合当中的元素“可选统一”。 创建集合的时候,可以写一个泛型<>,代表集合当中统一的数据类型是什么。 如果集合创建的时候,没有写<>,那么所有数据类型都可以放进来,都将会处理成为Object。 ### 1.2 Collection接口常用方法 java.util.Collection接口当中规定的常用集合方法有: public boolean add(E e):把指定的参数元素,添加到集合中;返回添加动作是否成功。 public boolean remove(Object e):根据参数指定的元素内容,从集合当中删除元素;返回删除是否成功。 public boolean contains(Object e):判断集合是否包含指定的元素。 public boolean isEmpty():判断集合是否为空白(一个元素都没有)。 public void clear():清空集合当中所有的元素内容。 public int size():获取集合的长度尺寸。 public Object[] toArray():将集合转换成为数组形式。 ##### `注意事项`: 对于remove方法和contains方法来说,参数是Object类型。这里是如何得知两个对象是否“相同”的呢?由equals和hashCode两个方法共同决定。 ### 1.3迭代器 并不是所有的集合都有索引值,所以对于Collection接口来说,普通的for循环索引i那种方式不一定适用。 有一个叫做“迭代器”的小东东,非常好用,专门用来遍历集合的。无论是什么集合,只要是Collection的实现类,都可以用。 ##### `使用步骤:` 1. 根据集合获取一个对应的迭代器(注意不是自己new的,而是从集合当中获取的。) 2. 通过迭代器,看看有没有下一个。 3. 如果有下一个,通过迭代器获取下一个,并且向后移动一个位置。 4. 上述2-3步骤是一个循环,直到没有下一个为止。(while循环。) java.util.Iterator<T>接口代表迭代器,其中有两个常用的方法: boolean hasNext():`判断有没有下一个元素`` T next():获取下一个,并且向后移动一个位置 ##### 注意: 在使用迭代器遍历集合的过程当中,一定要避免直接通过集合改变其中元素的个数。否则就会导致ConcurrentModificationException并发修改异常。 ### 1.4增强for循环 增强for循环(昵称也叫做for-each循环)是JDK 1.5添加的特性之一。 for (数据类型 变量名称 : 数组) { // ... } 其中的数据类型并不一定是int,不代表索引值。 含义:用左边的变量,分别得到右侧数组当中的每一个数据值。 ##### 备注: 这其实只是一个语法糖。对于数组来说,增强for循环底层其实就是一个普通的for循环。 增强for循环照样也可以支持集合。 for (数据类型 变量名称 : 集合) { // ... } ##### 备注: 这其实也是一种语法糖,对于集合来说,底层其实就是迭代器,只是表面上增强for循环的写法简单而已。 ##### 在使用增强for循环的时候,注意事项: 1. 支持数组,其实是一个语法糖,底层就是普通的fori循环。 2. 支持java.lang.Iterable接口对象,其中就包含了集合。因为这个接口规定了一项能力: public Iterator<T> iterator():获取迭代器的方法。 3. 支持集合,也是一个语法糖。底层就是在使用迭代器。 4. 增强for循环当中没有索引值,所以就无法直接修改数组或集合中的内容。【重点】 `基本数据类型存储的就是数据值`, `引用数据类型存储的是地址值`。 ##### 备注: 集合当中保存的其实都是对象的【地址值】。 增强for循环没有索引值,所以基本数据类型的数据值不能变,同时引用数据类型的地址值不能变 ## 2.泛型 ### 2.1泛型概述 ##### 使用泛型的好处: 1. 保证类型统一,确保类型安全。 2. 将可能发生的类型安全问题,从运行期提前到编译期。(有问题尽量在javac的时候就暴露出来最好,别等到java运行时再暴露) 3. 省去向下转型的麻烦。 4. 让代码模板化。 ##### `自定义泛型的三种用法`: 1. 泛型类 2. 泛型接口 3. 泛型方法 ### 2.2泛型类定义 自定义一个泛型类 修饰符 class 类名称<泛型> { // ... } 泛型的名称用什么都可以,一般推荐使用大写字母。 泛型代表一种尚不确定的类型,所有本类范围之内都能用这个泛型当做不确定的类型进行使用。 什么时候才能确定这个泛型? 当创建泛型类对象的时候,就可以确定。 ##### 定义一个泛型接口 修饰符 interface 接口名称<泛型> { // ... } 含义和泛型类是完全相同的:本接口之内泛型通用。 ##### `时候确定接口的泛型` 1. 实现类在实现接口的时候,直接指定具体泛型。 2. 实现类仍然不指定具体泛型,那么实现类也必须是一个泛型类。 ##### 注意: 对于泛型类/泛型接口来说,泛型是在本类/本接口当中全局通用。 ##### `泛型方法的格式:` 修饰符 <泛型> 返回值类型 方法名称(参数类型 参数名称) { 方法体 } ##### 备注: 这个泛型定义在方法上,所以只有当前这个方法自己专用。别人不能用。 ### 2.3泛型的通配符 泛型的通配符其实就是一个问号:【?】 作用:用来被动匹配任何一种泛型。 ##### 注意事项: 1. 一旦使用了泛型?通配符进行匹配接收,那么遍历的时候就只能当做Object,因为不确定泛型到底传进来的是谁。 2. 这个通配符问号,只能在匹配接收的时候使用,不能在定义泛型的时候使用。 对于泛型的通配符问号,有两种特殊写法: ##### 上下限,上下界。 ##### <?>:随便,谁都行。 <? extends 类>:可以是指定的类,或者其子类。(上限,最高不能超过这个类。) <? super 类>:可以是指定的类,或者其父类。(下限,最低不能超过这个类。)