A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 yqw_gz_java 于 2019-3-7 15:32 编辑

[AppleScript] 纯文本查看 复制代码
day02【Collection、泛型】
## 主要内容

- Collection集合
- 迭代器(遍历集合)
- 增强for(foreach)
- 泛型

## 教学目标

- [ ] 能够说出集合与数组的区别
- [ ] 说出Collection集合的常用功能
- [ ] 能够使用迭代器对集合进行取元素
- [ ] 能够说出集合的使用细节
- [ ] 能够使用集合存储自定义类型
- [ ] 能够使用foreach循环遍历集合
- [ ] 能够使用泛型定义集合对象
- [ ] 能够理解泛型上下限
- [ ] 能够阐述泛型通配符的作用

# 第一章 Collection 集合

## 1.1 集合概述

```java
什么是集合
    * 就是一个容器,可以存储多个数据。

数组和集合的区别
    * 数组的长度固定,集合的长度是可变。
    * 数组可以存储基本数据类型,也可以存储引用数据类型,集合只能存储引用数据类型
    * 数组只能存储同一种数据类型,而集合可以存储多种数据类型(不建议)

集合的分类
    * 单列集合:Collection:每次存储元素时只存储一个
    * 双列集合:Map:每次存储元素时存储两个元素。
```

## 1.2  Collection集合体系

```java
* Colletion:是所有单列的集合的父类。
    * List
        * ArrayList
        * LinkedList
        * Vector(过时了)
    * Set
        * HashSet
        * LinkedHashSet
```

## 1.3 Collection 常用方法

```java
public boolean add(E e) 添加元素
public void clear()     清空集合中的元素
boolean remove(E e)     删除指定的元素,删除成功返回true,否则false,只删除第一次出现的元素。
boolean contains(E e)   判断集合中是否包含指定的元素,包含返回true,否则false
public boolean isEmpty()  判断集合是否为空(元素个数是否等于零),为空返回true,否则false
public int size()       获得集合元素的个数
public Object[] toArray()  将集合转换为数组
```

- 示例代码

```java
public class CollectionDemo02 {
    public static void main(String[] args){
        // 创建集合对象
        Collection<String> co = new ArrayList<>();
        // 添加元素
        co.add("aa");
        co.add("bb");
        co.add("cc");
        co.add("aa");
        System.out.println(co); // [aa, bb, cc, aa]
        // 集合转数组
        Object[] objs =  co.toArray();
        System.out.println(Arrays.toString(objs)); // [aa, bb, cc, aa]

        // 删除指定元素:aa
        System.out.println(co.remove("aa")); // true
        System.out.println(co);

        // 判断集合中是否包含元素:aa
        System.out.println(co.contains("aa")); // false


        // 清空集合中的元素
        co.clear();
        /*co.add("dd");*/
        System.out.println(co);

        // 判断集合是否为空
        System.out.println(co.isEmpty());
        if (co.isEmpty()){

        }
    }
}
```

## 1.4 使用集合存储自定义对象

# 第二章 Iterator迭代器

### 2.1 什么是迭代器

```java
什么是迭代器
    * 一个用来遍历集合的对象,该对象是实现了Iterator接口。
    * 只要是实现了Iterator接口的对象都是迭代器对象。

如何获得迭代器
    * 通过调用集合对象的该方法:Iterator<E> iterator()

Iterator接口中的常用方法
    * boolean hasNext(); 判断是否有下一个元素,如果有则返回true,否则false
    * E next(); 先将指针下移指向下一个元素,然后将当前指针指向位置的元素作为返回值。

迭代器的使用注意事项
    * java.util.NoSuchElementException:没有元素异常
        * 如果没有元素可迭代了仍然调用next方法获得元素,则会抛出该异常。
```

### 2.2 迭代器的好处

```java
1. 屏蔽了众多集合的内部实现,对外提供统一的遍历方式。
2. 只要是单列集合都可以使用迭代器遍历
```

### 2.3 Iterator常用方法

```java
* boolean hasNext(); 判断是否有下一个元素,如果有则返回true,否则false
* E next(); 先将指针下移指向下一个元素,然后将当前指针指向位置的元素作为返回值。
```

### 2.4 Iterator示例代码

```java
public class IteratorDemo01 {
    public static void main(String[] args){
        // 创建集合对象
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");

        // 使用循环改进
        Iterator<String> it =  list.iterator();
        while(it.hasNext()){ // true
            System.out.println(it.next());
        }

        /* 没有使用循环
        // 使用迭代器遍历集合
        Iterator<String> it =  list.iterator(); //  new Itr();

        System.out.println(it.hasNext()); // true
        System.out.println(it.next());    // aa

        System.out.println(it.hasNext()); // true
        System.out.println(it.next());    // bb

        System.out.println(it.hasNext()); // true
        System.out.println(it.next());    // cc

        System.out.println(it.hasNext()); // true
        System.out.println(it.next());    // dd

        System.out.println(it.hasNext()); // false
        System.out.println(it.next());    // dd
        */

        // 普通for遍历
       /* for(int index = 0;index < list.size();index++){
            // 根据索引获得集合
            String str = list.get(index);
            System.out.println(str);
        }*/
    }
}
```

![](/Users/pkxing/Documents/88期就业班/就业班-day02-Collection、泛型/笔记/迭代器遍历集合.png)

# 第三章 增强for(foreach)

### 3.1 增强for概述

```java
* JDK1.5新特性
* 专门用来遍历集合和数组的
* 本质:迭代器
```

### 3.2 增强for格式

```java
for(数据类型 变量名: 数组名或集合名){

}
```

### 3.3 增强for示例代码

#### 练习1:遍历数组

```java
public class ForEachDemo01 {
    public static void main(String[] args){
        // 定义一个整型数组
        int[] arr = {1,2,3,4,5,6};
        // 使用增强for遍历数组
        /*
         for(数据类型 变量名: 数组名或集合名){

        }
         */
        for (int num : arr){
            System.out.println(num);
            num += 10;
        }
        System.out.println("------------");
        for(int num:arr){
            System.out.println(num);
        }
    }
}
```

![](/Users/pkxing/Documents/88期就业班/就业班-day02-Collection、泛型/笔记/增强for遍历数组.png)

#### 练习2:遍历集合

```java
public class ForEachDemo02 {
    public static void main(String[] args){
        // 增强for遍历集合:集合存储自定义对象
        test01();
        // 增强for遍历集合:集合存储字符串
        test02();
    }

    /*
        增强for遍历自定义对象
     */
    public static void test02(){
        // 创建集合对象
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("小泽"));
        list.add(new Student("小苍"));
        list.add(new Student("小波"));
        list.add(new Student("小玉玉"));

        // 使用增强for遍历
        for(Student stu: list){
            System.out.println(stu);
            stu.setName("小野");
        }
        System.out.println("-------------");
        // 使用增强for遍历
        for(Student stu: list){
            System.out.println(stu);
        }
    }

    // 增强for遍历集合
    public static void test01(){
        // 创建集合对象
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");

        for(String str: list){
            System.out.println(str);
        }
    }
}
```

### 



# 第四章 泛型

## 3.1  泛型在集合中使用

```java
泛型的概述
    * JDK1.5新特性。
    * 泛型可以使用在方法中,类上,接口上。

泛型在集合中使用的好处
    * 将运行期错误转换为编译器错误,增强了集合的安全性。
    * 避免了类型强制转换的麻烦。

泛型在集合中的使用注意事项
    * 在泛型中,没有多态的概念,要么指定左边,要么两边都指定相同的数据类型。
    * 在JDK1.7之前,必须两边都指定相同的数据类型。
```

- 示例代码

```java
public class CollectionDemo {
    public static void main(String[] args){
        // 创建集合对象
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        // list.add(123);

        for(String str:list){
            System.out.println(str.length());
        }

        // 遍历集合
        for (Object obj:list) {
            // 向下转型为字符串
            String str = (String) obj;

            System.out.println(str.length());
        }
    }
}
```

## 3.2  泛型的定义与使用(了解)

### 3.2.1 泛型方法

#### 泛型方法引入

- 定义一个方法接收一个任意类型的参数,返回值类型与实际参数类型一致。 

```java
什么是泛型
    * 数据类型参数化。

泛型方法的引入
    * 定义一个方法接收一个任意类型的参数,返回值类型与实际参数类型一致。

泛型的概述
    * JDK1.5新特性。
    * 泛型可以使用在方法中,类上,接口上。
    * 泛型变量可以理解为是一种数据类型的占位符。
    * 泛型变量还可以理解为一种数据类型的变量。
    * 泛型变量的命名规则:只要是合法的标识符就可以,一般会使用一个大写字母表示
        常用的泛型变量的名字:T, K, V,E

泛型方法的概念
    * 在定义方法时定义了泛型变量的方法则称为泛型方法。

泛型方法的定义格式
    * 修饰符 <T> 返回值类型 方法名(参数列表){}

泛型方法的注意事项
    * 泛型变量的具体数据类型是在调用该方法时由调用者传递参数决定。
        * 参数是什么类型,则泛型变量的具体数据类型就是什么类型。
    * 泛型变量的具体数据类型不能是基本数据类型,如果要使用基本数据类型,要使用对应的包装类类型。
```

#### 示例代码

```java
public class Demo01 {
    public static void main(String[] args){
        String str =  test("abc");
        Integer in = test(123);

        Student stu = test(new Student());

        int age = 100;
        System.out.println(age);
    }

    public static void sum(int a,int b){

    }

    /*
        泛型方法
     */
    public static <T> T test(T param){

        return param;
    }
}
```

#### 泛型方法练习

```java
- 定义一个数组工具类MyArrays
- 提供两个成员方法,方法参数接收一个任意类型的数组
  - 一个方法的功能是将数组的元素反转.
  - 一个方法的功能是将数组的元素拼接成一个字符串返回。
    - 字符串格式:"[1,2,3,4,5]" 
```

- 代码实现

```java
/**
- 提供两个成员方法,方法参数接收一个任意类型的数组
     - 一个方法的功能是将数组的元素反转.
     - 一个方法的功能是将数组的元素拼接成一个字符串返回。
     - 字符串格式:"[1,2,3,4,5]"
*/
public class MyArrays {

    // 一个方法的功能是将数组的元素反转.
    public static <T> void reverse(T[] arr){
        for(int i = 0,j = arr.length - 1; i < j; i++,j--){
            T temp = arr;
            arr = arr[j];
            arr[j] = temp;
        }
    }

    // 一个方法的功能是将数组的元素反转.
    // "[1,2,3,4,5,]"
    public static <T> String toString(T[] arr){
        // 创建可变字符串
        StringBuilder sb = new StringBuilder("[");
        for(T t:arr){
            sb.append(t).append(",");
        }
        // 删除最后一个,
        sb.deleteCharAt(sb.length()-1);
        sb.append("]");
        return sb.toString();
    }
}

public class Demo02 {
    public static void main(String[] args){
        // 创建字符串数组
        String[] strs = {"a","b","c"};
        // 创建整型数据
        Integer[] arr = {1,2,3,4,5,6};
        /*
        // 创建数据工具类型对象
        MyArrays myArrays = new MyArrays();
        myArrays.reverse(strs);*/

        System.out.println("反转前:"+ Arrays.toString(strs));
        // 反转字符串数组元素
        MyArrays.reverse(strs);
        System.out.println("反转后:" + MyArrays.toString(strs));

        System.out.println("反转前:"+MyArrays.toString(arr));
        // 反转整型数组元素
        MyArrays.reverse(arr);
        System.out.println("反转后:"+MyArrays.toString(arr));

    }
}
```

### 3.2.2 泛型类

```java
什么是泛型类
    * 在类定义时定义了泛型变量的类就是泛型类

泛型类的定义格式
    * class 类名<T>{
        // 可以将泛型变量T当成一种数据类型使用
     }

泛型类的注意事项
    * 泛型变量的具体数据类型是由创建对象时由使用者决定,如果没有指定具体数据类型则默认是Object
    * 静态方法不能使用类上定义的泛型变量,如果该方法要使用泛型变量,则需要将该方法定义为泛型方法。
```

- 示例代码

```java
/**
    泛型类定义
*/
public class MyArrays<T>{

    // 一个方法的功能是将数组的元素反转.
    public static <T> void reverse(T[] arr){
        for(int i = 0,j = arr.length - 1; i < j; i++,j--){
            T temp = arr;
            arr = arr[j];
            arr[j] = temp;
        }
    }

    // 一个方法的功能是将数组的元素反转.
    // "[1,2,3,4,5,]"
    public String toString(T[] arr){
        // 创建可变字符串
        StringBuilder sb = new StringBuilder("[");
        for(T t:arr){
            sb.append(t).append(",");
        }
        // 删除最后一个,
        sb.deleteCharAt(sb.length()-1);
        sb.append("]");
        return sb.toString();
    }

    public void xxx(){

    }
}

public class Demo01 {
    public static void main(String[] args){
        // 创建字符串数组
        String[] strs = {"a","b","c"};
        // 创建整型数据
        Integer[] arr = {1,2,3,4,5,6};
        // 创建泛型类对象
        MyArrays<String> myArrays01 = new MyArrays<>();
        // 此时通过对象myArrays01调用方法,方法中的泛型变量的具体数据类型是:String
        myArrays01.reverse(strs);


        // 创建泛型类对象
        MyArrays<Integer> myArrays02 = new MyArrays<>();
        // 此时通过对象myArrays02调用方法,方法中的泛型变量的具体数据类型是:Integer
        myArrays02.reverse(arr);


        MyArrays myArrays03 = new MyArrays();
    }
}
```

### 3.2.3 泛型接口

```java
什么是泛型接口
    * 在定义接口的同时定义了泛型变量的接口

泛型接口的定义格式
    * interface 接口名<T>{
        // 将泛型变量T当成一种数据类型使用
    }

泛型接口的实现方式
    * 方式1:实现接口的同时指定泛型变量的具体数据类型(不推荐使用,不够灵活)
    * 方法2:实现接口时不指定泛型变量的具体数据类型,将实现类定义为泛型类,
            由使用者创建泛型类对象时指定泛型变量的具体数据类型。(推荐使用)
```

- 示例代码

```java
/**
    Dao:数据访问层接口
    泛型接口

    表现层
    业务层
    数据访问层:直接跟数据库打交道,对数据库执行增删改查操作的。
*/
public interface Dao<T>{
    // 增
    public void save(T t);
    // 改
    public void update(T t);
}

/**
        实现接口的同时指定泛型变量的具体数据类型
*/
public class ProductDao implements Dao<Product> {
    @Override
    public void save(Product product) {
        System.out.println("保存产品信息...");
    }

    @Override
    public void update(Product product) {
        System.out.println("更新产品信息...");
    }
}

/**
    实现接口的同时指定泛型变量的具体数据类型
*/
public class StudentDao implements Dao<Student> {
    @Override
    public void save(Student student) {
        System.out.println("保存学生信息....");
    }

    @Override
    public void update(Student student) {
        System.out.println("更新学生信息....");
    }
}

/**
实现接口时不指定泛型变量的具体数据类型,将实现类定义为泛型类,
    由使用者创建泛型类对象时指定泛型变量的具体数据类型。
*/
public class BaseDao<T> implements Dao<T> {
    @Override
    public void save(T t) {

    }

    @Override
    public void update(T t) {

    }
}

public class Demo01 {
    public static void main(String[] args){
        // 创建学生对象
        Student stu = new Student();
        // 创建Dao接口的实现类对象
        StudentDao stuDao = new StudentDao();
        // 保存学生
        stuDao.save(stu);

        // 创建产品对象
        Product p = new Product();
        // 创建Dao接口的实现类对象
        ProductDao pdDao = new ProductDao();
        // 保存产品
        pdDao.save(p);


        // 创建BaseDao对象
        BaseDao<Student> baseDao01 = new BaseDao<>();
        // 保存学生
        baseDao01.save(stu);

        // 创建BaseDao对象
        BaseDao<Product> baseDao02 = new BaseDao<>();
        baseDao02.save(p);
    }
}
```

## 3.3  泛型上下限(了解)

### 3.3.1 泛型上下限引入

```java
- 需求1
        - 定义一个方法可以接收任意类型的集合对象
        - 集合对象只能存储Integer或者是Integer的父类数据。

- 需求2
        - 定义一个方法可以接收任意类型的集合对象
        - 集合对象只能存储Number或者是Number的子类数据。
```

### 3.3.2 泛型上下限格式

```java
? : 泛型通配符  代表可以匹配任意数据类型。
泛型上限:? extends Number 可以接收Number或Number的子类类型的数据
泛型下限:? super Integer  可以接收Integer或Integer的父类类型的数据。

泛型通配符注意事项
    * ? 一般不会单独使用,一般会结合泛型上下限使用。
    * ? 不能用来定义泛型方法,泛型类,泛型接口

? 和 泛型变量T 的区别
    ? 不需要定义就可以使用,T 需要先定义再使用
    ? 在方法体不能当成一种数据类型使用,泛型变量T可以当成一种数据类型使用。
```

### 3.3.3 示例代码

```java
public class Demo01{
    public static void main(String[] args){

        ArrayList<String> list01 = new ArrayList<>();
        ArrayList<Integer> list02 = new ArrayList<>();
        ArrayList<Object> list03 = new ArrayList<>();
        ArrayList<Number> list04 = new ArrayList<>();
        ArrayList<Long> list05 = new ArrayList<>();

        // test01(list01); // 编译失败
        test01(list02); // 编译通过
        test01(list03); // 编译通过
        test01(list04); // 编译通过

        // test02(list01);  // 编译失败
        test02(list02);  // 编译通过
        // test02(list03);  // 编译失败
        test02(list04);  // 编译通过
        test02(list05);  // 编译通过*/
    }


    public static void test02(ArrayList<? extends Number> list) {

    }

    public static void test01(ArrayList<? super Integer> list) {

    }

}
```

# 小结

```java
Collection:所有单列集合的父类
        Collection集合的继承体系
                Collection:
                        List:ArrayList,LinkedList,Vector(过时)
                        Set:HashSet,LinkedHashSet
        Collection集合常用方法
                void add(E e);添加元素
                void clear();清空元素
                boolean remove(Object e);删除指定的元素,成功返回true,否则false
                boolean isEmpty(); 判断集合是否为空,空返回true否则false
                Object[] toArray();集合转数组
                boolean contains(Object e);判断集合中是否包含指定元素,包含返回true,否则false。
                int size();获得元素个数
                
迭代器概述
        一个用来遍历集合的对象
        该对象实现了Iterator接口

如何获得迭代器对象
        * 通过调用集合对象iterator()方法获得。
        
Iterator接口常用方法
        boolean hasNext(); 判断是否有下一个元素,有返回true,否则false
        E next(); 将指针下移指向下一个元素,并返回当前指针指向位置的元素。
        
迭代器的好处
        * 屏蔽了众多集合的内部实现,对外提供统一的遍历方式。
        * 所有的单列集合都可以使用迭代器遍历。

增强for概述
        * JDK1.5新特性,专门用来遍历集合和数组的,本质是:迭代器
增强for格式
        * for(数据类型 遍历名:数组名或集合名){}
        * 注意事项:在遍历集合过程中不能对集合元素进行增删操作,否则会出现并发修改异常。
泛型概述
        * JDK1.5新特性
        * 泛型可以使用在方法上,类上,接口上。
        * 泛型变量可以理解为是一种数据类型的占位符,也可以理解为是一种数据类型的变量。
        
泛型方法概述:在定义方法时定义了泛型变量的类
泛型方法的定义格式:修饰符 <泛型变量T> 返回值类型  方法名(参数列表){}
泛型方法注意事项:泛型变量的具体数据类型是由调用者调用方法传参决定。

泛型类概述:在定义类时定义了泛型变量的类
泛型类定义格式:class 类名<泛型变量T>{ }
泛型类注意事项
        泛型类上泛型变量的具体数据类型是创建对象时由使用者指定,如果没有指定,则默认是Object
        静态方法不能使用类上定义的泛型变量,如果要使用,则需要将该方法定义为泛型方法。
        
泛型接口概述:在定义接口时定义了泛型变量的接口
泛型接口的定义格式:interface 接口名<泛型变量T>{}
泛型接口的实现方式
        实现接口同时指定泛型变量的具体数据类型(不够灵活)
        实现接口时不指定泛型变量的具体数据类型,将该实现类定义泛型类,由使用者创建实现类对象时指定泛型变量的                具体数据类型。        
        
泛型上下限
        ? 通配符,可以匹配任意类型数据
        ? extends Number: 可以接收Number或Number子类数据
        ? super Integer: 可以接收Integer或Integer的父类数据
```

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马