最全泛型和集合框架讲解(知识点+方法+示例)

一、认识集合

在开始之前我们先认识一下集合。
开发应用程序时,如果想存储多个类型的数据可以使用数组来实现;但是使用数组存在一些明显的缺陷

  1. 数组长度固定不变,不能很好的适应元素数量动态变化的情况
  2. 可以通过数组名.length来获取数组的长度,却无法直接获取数组中实际存储的元素个数
  3. 数组采用在内存中分配连续空间的存储方式存储,根据元素信息查找时效率比较低,需要多次比较
    针对这些缺陷,java结合框架提供了一套性能优良、使用方便的接口和类,即在这里我们即将讲解的内容。

二、List接口

Collection接口是最基本的集合接口,可以存储一组不唯一、无需的对象。而List接口正是继承自Collection接口,是一个有序集合,用户可以使用List接口中的元素,类似于数组中。List接口中允许存放重复元素,也就是说List可以存储一组有序、不唯一的对象。
改接口常用实现类有:ArrayList和LinkedList。

2.1.使用ArrayList类动态存储数据

ArrayList集合类:对数组进行封装,实现了长度可变的数组,而且和数组采用相同的存储方式,,在内存中分配连续的空间,它不等同于数组,ArrayList集合中可以添加任何 类型的数据,并且添加的数据类型都将转换成object类型,但是在数组中只能添加同意数据类型的数据。
~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~
ArrayList的常用方法(前面是返回值)

方法说明
boolean add(Object o)在列表的末尾添加元素o,其实索引位置从0开始
void add(int index,Object o)在指定的索引位置添加元素o,索引位置必须介于0和列表中元素个数之间
int size()返回列表中的元素个数
Object get(int index)返回指定索引位置处的元素,取出的元素时Object类型,使用前需要进行强制类型转换
void set(int index,Object obj)将index索引位置的元素替换为obj元素
boolean contains(Object o)判断列表中是否存在指定元素o
int indexOf(Object obj)返回元素在集合中出现的索引位置
boolean remove(Object o)从列表中删除元素o
Object remove(int index)从列表中删除指定位置的元素,其实索引位置从0开始

示例1:使用ArrayList常用方法动态操作数据一般的实现步骤如下:

  1. 导入ArrayList类
  2. 创建ArrayList对象,并添加数据
  3. 判断集合中是否包含某元素
  4. 移除索引为0 的元素
  5. 把索引为1的元素替换为其他元素
  6. 输出某个元素所在的索引位置
  7. 清空ArrayList集合中的数据
  8. 判断ArrayList集合中是否包含数据
    代码呈现
 import java.util.ArrayList;

public class Demo1 {
    public static void main(String[] args) {
        //导入ArrayList类
        ArrayList list = new ArrayList();
        //在数组中添加下面的内容
        list.add("张三丰");
        list.add("小龙女");
        list.add("郭靖");
        //判断数组中是否有小龙女
        System.out.println(list.contains("小龙女"));
        System.out.println("**************");
        //移除下标为0的内容,并判断数组中是否有以下内容
        list.remove(0);
        System.out.println(list.contains("张三丰"));
        //将索引位置为1的数据更改为黄蓉
        list.set(1,"黄蓉");
        System.out.println(list.contains("黄蓉"));
        System.out.println("******************");
        //遍历数组,并强制转换为String类型的元素
        for (int i = 0; i <list.size() ; i++) {
            String name = (String)list.get(i);
            System.out.println(name);
        }
        System.out.println("****************");
        //找出输出元素“小龙女”所在的索引位置,若集合中没有该元素。则输出的结果为-1
        System.out.println(list.indexOf("小龙女"));
        //清楚数组中的所有数据
        list.clear();
        System.out.println("*****************");
        //再次对数组中进行遍历
        for (Object obj:list) {
            String name = (String) obj;
            System.out.println(name);
        }
        System.out.println("***************");
        //判断数组是否为空
        System.out.println(list.isEmpty());

    }
}                                      

运用这一系列的代码来熟悉这些ArrayList的方法。

示例2:使用ArrayList集合存储新闻标题信息(包含ID、名称、创建者),输出新闻标题的总数量及新闻标题的名称。
实现步骤:

  1. 创建ArrayList对象,并添加数据
  2. 获取新闻标题的总数
  3. 遍历对象的集合,输出新闻标题名称

代码呈现
1.首先对题目要求的属性进行封装

import java.util.ArrayList;

public class NewsTitle {
    private int id;
    private String name;
    private String title;

    public NewsTitle(int id, String name, String title) {
        this.id = id;
        this.name = name;
        this.title = title;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

2.之后进行使用ArrayList集合存储标题信息

import java.util.List;

public class Test {
    public static void main(String[] args) {
        //创建新闻标题对象,NewsTitle为新闻标题类
        NewsTitle car = new NewsTitle(1, "管理员", "汽车");
        NewsTitle test = new NewsTitle(2, "管理员", "高考");

        //创建存储新闻标题的集合对象
        List newsTitleList = new ArrayList();
        //按照顺序依次添加新闻标题
        newsTitleList.add(car);
        newsTitleList.add(test);
        //获取新闻标题的总数,size返回元素中有多少个个数
        System.out.println("新闻标题数目为:"+newsTitleList.size()+"条");
        //遍历集合对象,输出新闻标题名称
        System.out.println("新闻标题名称为:");
        for (int i = 0; i <newsTitleList.size() ; i++) {
            NewsTitle title = (NewsTitle) newsTitleList.get(i);
            System.out.println(title.getTitle());
        }
    }
}

总结:
在ArrayList集合中可以存储任何类型的对象,在编程中将接口的引用指向实现类的对象是Java实现多态的一种形式,也是软件开发中实现低耦合的方式之一。这样的用法可以大大提高程序的灵活性。
ArrayList集合因为可以使用索引来直接获取元素,所以它的优点是遍历元素和随机访问元素的效率比较高。但是由于ArrayList集合采用了和数组相同的存储方式,在内存中分配连续的空间,因此在添加和删除非尾部元素时会导致后面所有元素的移动,这就造成在插入、删除等操作频繁的应用场景下使用ArrayList会导致性能低下。所以数据操作频繁时,最好使用LinkedList存储数据。

2.2使用LinkedList类动态存储数据

LinkedList类:它是接口的链接列表实现类。它支持实现所有List接口可选的列表的操作,并且允许元素值是任何数据,包括null。采用链表存储方式存储数据,优点在于插入、删除元素时效率比较高,但是LinkedList类的查找效率很低。
~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~ ~~~~
LinkedList一些独有方法

方法说明
void addFirst(Object obj)将指定元素插入到当前集合的首部
void addLast(Object obj)将指定元素插入到当前集合的尾部
Object getFirst()获得当前集合的第一个元素
Object getLast()获得当前集合的最后一个元素
Object removeFirst()移除并返回当前集合的第一个元素
Object removeLast()移除并返回当前集合的最后一个元素

示例3:使用LinkedList集合存储新闻标题(包含ID、名称、创建者),实现获取、添加及删除头条和末条新闻标题信息功能,并遍历集合。
实现步骤:

  1. 对属性进行封装
  2. 创建LinkedList对象并添加数据
  3. 添加头条和末条新闻标题信息
  4. 获取头条和末条新闻标题信息
  5. 删除头条和末条新闻标题
    代码呈现
package linkList;

public class NewsTitle {
    private int id;
    private String title;
    private String name;

    public NewsTitle(int id, String title, String name) {
        this.id = id;
        this.title = title;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package linkList;

import java.util.LinkedList;

public class Test {
    public static void main(String[] args) {

        //创建多个新闻标题对象
        NewsTitle car = new NewsTitle(1, "汽车", "管理员");
        NewsTitle medical = new NewsTitle(2, "医学", "管理员");
        NewsTitle fun = new NewsTitle(3, "娱乐", "管理员");
        NewsTitle gym = new NewsTitle(4, "健身房", "管理员");
        //创建存储新闻标题的集合对象并添加数据
        LinkedList list = new LinkedList();
        list.add(car);
        list.add(medical);
        //添加头条新闻标题和末条新闻标题
        list.addFirst(fun);
        list.addLast(gym);
        System.out.println("头条新闻标题和末条新闻标题已添加");
        //获取头条以及最末条新闻标题
        NewsTitle first = (NewsTitle) list.getFirst();
        System.out.println("头条的新闻标题为:"+first.getTitle());
        NewsTitle last = (NewsTitle)list.getLast();
        System.out.println("头条的末条标题为:"+last.getTitle());
        //删除头条和末条新闻标题
        list.removeFirst();
        list.removeLast();
        System.out.println("头条和末条新闻标题已经删除");
        System.out.println("遍历所有新闻标题");
        for (Object obj:list) {
            NewsTitle title = (NewsTitle)obj;
            System.out.println("新闻标题名称为:"+title.getTitle());
        }
    }
}

三、Set接口

set接口概述:
set接口是Collection接口的另外一个常用子接口,Set接口描述的是一种比较简单的集合。集合中的对象并不按特定的方式排序,并且不能保存重复的对象,也就是说Set接口可以存储一组唯一、无序的对象。
Set接口常用的实现类有HashSet。
使用HashSet类动态存储数据
使用HashSet集合类查找效率是很高的,HashSet类实现了Set接口,是使用Set集合时最常用的一个实现类。HashSet集合的特点如下:

  1. 集合内的元素是无序排列的
  2. HashSet类是非线程安全的
  3. 允许集合元素值为null

HashSet类的常用方法:

方法说明
boolean add(Object o)如果Set中尚未包含指定元素o,则添加指定元素o
void clear()从Set中移除所有元素
int size()返回Set中元素的数量(Set的容量)
boolean isEmpty()如果Set不包含任何元素,则返回true
boolean contains(Object o)如果Set包含指定元素o,则返回true
boolean remove(Object o)如果指定元素o存在于Set中,则将其移除

示例4:使用HashSet类的常用方法存储并操作新闻标题信息,并遍历集合(属性与之前示例一样)
实现步骤:

1.创建HashSet对象,并添加数据
2.获取新闻标题的总数
3.判断集合中是否包含汽车新闻标题
4.移除对象
5.判断集合是否为空
6.遍历集合

代码呈现
先进行封装

package hSet;

public class NewTitle {
    private int id;
    private String name;
    private String title;

    public NewTitle(int id, String name, String title) {
        this.id = id;
        this.name = name;
        this.title = title;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

2.使用集合存储对象

import linkList.NewsTitle;

import java.util.HashSet;
import java.util.Set;

public class Test {
    public static void main(String[] args) {


        //创建多个新闻标题对象
        NewTitle car = new NewTitle(1, "管理员", "汽车");
        NewTitle test = new NewTitle(2, "管理员", "高考");
        //创建存储新闻标题的集合对象
        Set set = new HashSet();
        //按照顺序依次添加新闻标题
        set.add(car);
        set.add(test);
        //获取新闻标题的总数
        System.out.println("新闻标题的总数为:"+set.size()+"条");
        //判断集合是否包含汽车新闻标题
        System.out.println("汽车新闻是否存在:"+set.contains(car));
        //移除高考对象,并判断集合是否为空
        set.remove(test);
        System.out.println("高考新闻标题已经删除");
        System.out.println("集合是否为空"+set.isEmpty());
        //遍历所有新闻标题
        for (Object obj:set) {
            NewTitle title = (NewTitle)obj;
            System.out.println(title.getTitle());
        }
    }
}

总结:
前面讲过List接口可以使用for循环和增强for循环两种遍历方式。使用for循环遍历时,通过get()方法取出每个对象,但由于HashSet类不存在get()方法,所以Set接口无法使用for循环遍历。当然,遍历集合还有一种常用的方式,就是使用Iterator接口。

四、Iterator接口

概述:此接口表示对集合进行迭代的迭代器。Iterator接口为集合而生,专门实现集合的遍历。此接口主要有如下两个方法:

  1. hasNext():判断是否存在下一个可访问的元素,如果仍有元素可以迭代,则返回true。
  2. next():访问要返回的下一个元素。

凡是由Collection接口派生而来的接口或者类,都实现了iterate()方法,iterate()方法返回一个Iterator对象。
示例5:使用Iterator接口遍历ArrayList集合
实现步骤:

  1. 导入Iterator接口。
  2. 使用集合的iterator()方法返回Iterator对象。
  3. while循环遍历。
  4. 使用iterator的hasNext()方法判断是否存在下一个可访问的元素。
  5. 使用Iterator的next()方法返回要访问的下一个元素。

代码呈现

package it;

import javax.lang.model.type.ArrayType;
import java.util.ArrayList;
import java.util.Iterator;

public class Iter {
    public static void main(String[] args) {
        //导入ArrayList接口并且添加数据
        ArrayList list = new ArrayList();
        list.add("郭靖");
        list.add("张三丰");
        list.add("小龙女");
        System.out.println("使用Iterator遍历分别是:");
        //获取集合迭代器Iterator
        Iterator it = list.iterator();
        //通过迭代器遍历
        while(it.hasNext()){
            String name = (String)it.next();
            System.out.println(name);
        }

    }
}

当然,通过迭代器遍历Set接口和示例5的过程是相似的。

五、Map接口

概述:Map接口存储一组成对的键(key)—值(value)对象,提供key到value的映射,通过key来检索。Map接口中的key不要求有序,不允许重复。value同样不要求有序,但允许重复。

Map接口的常用方法:

方法说明
Object put(object key ,object value)将相互关联的一个key与一个value放入该集合,若果此map接口中已经包含了key对应的value,则旧值将被替换
Object remove(Object key)如果当前集合中移除与指定key相关的映射,并返回该key关联的旧的value。如果key没有任何关联,则返回null
Object get(Object key)获得与key相关的value。如果该key不关联任何非null值,则返回null
boolean containsKey(Object key)判断集合中是否存在key
boolean containsValue(Object value)判断集合中是否存在value
boolean isEmpty()判断集合中是否存在元素
void clear()清除集合中的所有元素
int size()返回集合中的元素数量
Set keyset()获取所有key的集合
Collection values()获取所有value的集合

注意:Map接口中存储的数据都是键值对形式

5.1使用HashMap类动态存储数据

HashMap类优点:查询指定元素效率高
示例6:使用Hash类存储学生信息,要求可以根据英文名检索学生信息
实现步骤:

  1. 导入HashMap类
  2. 创建HashMap对象
  3. 调用HashMap对象的put()方法,向集合中添加数据。
  4. 输出学员个数
  5. 输出键集
  6. 判断是否存在Jack这个键,如果存在,则根据键获取相应的值。
  7. 判断是否存在Rose这个键,如果存在,则根据键获取相应的值。

代码呈现
给两个属性,分别是姓名和性别

package hMap;

public class Student {
    private String name;
    private String Sex;

    public Student(String name, String sex) {
        this.name = name;
        Sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return Sex;
    }

    public void setSex(String sex) {
        Sex = sex;
    }
}

使用HashMap存储数据

package hMap;

import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        //创建多个对象
        Student t1 = new Student("黎明","男");
        Student t2 = new Student("刘明","男");
        //创建保存“键值对”的集合对象
        Map students = new HashMap();
        //把英文名称与学员对象按照键值对的方式存储在HashMap中
        students.put("jack",t1);
        students.put("Rose",t2);
        //输出学员个数
        System.out.println("已添加"+students.size()+"个学员信息");
        //输出键集
        System.out.println("键集"+students.keySet());
        String key = "jack";
        //判断是否存在jack这个键,如果存在,则根据键获取相应的值
        if (students.containsKey(key)){
            Student student = (Student)students.get(key);
            System.out.println("英文名为:"+key+"的学员姓名为:"+student.getName());
        }
        String key2= "Rose";
        if (students.containsKey(key2)){
            Student student = (Student)students.get(key2);
            System.out.println("英文名为:"+key2+"的学员姓名为"+student.getName());
        }
    }
}

注意:
1.将数据添加到HashMap集合后,所有的数据类型将转换为Object类型,所以从其中获取数据时需要进行强制类型转换。
2.HashMap类不保证映射的顺序,特别是不保证顺序恒久不变。

5.2遍历HashMap集合时可以遍历键集和值集

示例7:遍历所有的学员的英文名及学员详细信息
实现步骤:

  1. 遍历键集
  2. 遍历值集

代码呈现
属性与之前示例一致

package hMap;

import java.util.HashMap;
import java.util.Map;

public class Test2 {
    public static void main(String[] args) {

        //创建多个对象
        Student t3 = new Student("王五", "男");
        Student t4 = new Student("李四", "女");
        //创建保存键值对的集合对象
        Map students = new HashMap();
        //把英文名称与学员对象按照键值对的方式存储在HashMap中
        students.put("JackeyLove",t3);
        students.put("knight",t4);
        //输出英文名
        for (Object key:students.keySet()
             ) {
            System.out.println("学生英文名为"+key.toString());
        }
        //输出学生详细信息
        for (Object value:students.values()
             ) {
            Student test = (Student)value;
            System.out.println("姓名"+test.getName()+"性别"+test.getSex());
        }
    }
}

六、Collection类

概述:
Collection类是Java提供的一个集合操作工具类,它包含了大量的静态方法,用于实现对集合元素的排序、查找和替换等操作。

6.1对集合元素进行排序与查找(sort、binarySearch)

排序是针对集合的一个常见需求,要排序就要知道两个元素哪个大哪个小,在java中,如果想实现一个类的对象之间比较大小,那么这个类就要实现comparable接口。此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo()方法被称为它的自然比较方法。此方法用于比较此对象与指定对象的排序,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
compareTo()方法的定义语法格式如下:
int compareTo(Object obj);
其中:

  1. 参数:obj即要比较的对象
  2. 返回值:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象返回不同的值

实现此接口的对象列表(和数组)可以通过Collection.sort()方法(和ArrayList.sort()方法)进行自动排序。下面我们通过一个示例来进行演示。
示例8:学生类Student类实现了Comparable接口,重写了compareTo()方法。通过比较学号实现对象之间的大小比较。
实现步骤:

  1. 创建Student类
  2. 添加属性:学号、姓名和性别
  3. 实现Compareable接口和compareTo()方法

代码呈现:

package coll;

public class Student implements Comparable{
    private int number;
    private String name;
    private String gender;

    public Student(int number, String name, String gender) {
        this.number = number;
        this.name = name;
        this.gender = gender;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public int compareTo(Object o) {
        Student student = (Student) o;
        //如果学号相等那么两者就是相等的
        if (this.number==student.number) {
            return 0;
        }else if (this.number>student.getNumber()){
            return 1;
        }else{
            return -1;
        }
    }
}

元素之间比较大小后,就可以使用Collection类的sort()方法对元素进行排序操作了。前面介绍过List接口和Map接口,Map接口本身是无序的,所以不能对map接口做排序操作;但List接口是有序的,所以对List接口进行排序。注意:List接口中存放的元素,必须是实现了Comparable接口的元素才可以。那么接下来就对其进行排序。
示例9:使用Collections类的静态方法sort()和binarySearch()对List集合进行排序和查找
实现步骤:

  1. 导入相关类
  2. 初始化数据
  3. 遍历排序前集合并输出
  4. 使用Collections类的sort()方法排序
  5. 遍历排序后集合并输出
  6. 查找排序后某元素的索引

代码呈现

package coll;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

public class Test {
    public static void main(String[] args) {
        Student t1 = new Student(3,"张三","男");
        Student t2 = new Student(2,"李四","男");
        Student t3 = new Student(5,"张春华","女");
        ArrayList list = new ArrayList();
        list.add(t1);
        list.add(t2);
        list.add(t3);
        System.out.println("--------排序前-----------");
        Iterator it = list.iterator();
        while(it.hasNext()){
            Student t = (Student)it.next();
            System.out.println(t.getNumber());
        }
        //使用  Collection类的sort方法对List进行排序
        System.out.println("----------排序后-----------");
        Collections.sort(list);
        Iterator li = list.iterator();
        while(li.hasNext()){
            Student s =(Student)li.next();
            System.out.println(s.getNumber());
        }
        //使用Collection类的binarySearch()方法对List集合进行查找
        int index = Collections.binarySearch(list,t1);
        System.out.println("t1的索引是"+index );
    }
}

6.2替换集合元素(fill)

概述:
若有一个需求,需要把List集合中所有的元素都替换为相同的元素,则可以使用Collections类的静态方法fill()来实现。下面通过示例来实现学习。
示例10:使用Collections类的静态方法fill()替换List集合中的所有元素为相同的元素
实现步骤:

  1. 导入相关类
  2. 初始化数据
  3. 使用Collections类的fill()方法替换结合中的元素
  4. 遍历输出替换后的集合

代码呈现

import it.Iter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class Replace {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("张三丰");
        list.add("小龙女");
        list.add("郭靖");
        Collections.fill(list,"东方不败");
        Iterator it =list.iterator();
        while (it.hasNext()){
            String name =(String)it.next();
            System.out.println(name);
        }
    }
}

这样看来Collections类的实现就差不多告一段落。

七、认识泛型

本质:参数化类型即所操作的数据类型被指定为一个参数
好处:安全简单、所有强制转换都是自动和隐式进行的,提高了代码的重用率
定义:将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性。
定义语法格式:类1或者接口<类型实参>对象 = new类2<类型实参>();
例如:ArrayList< String > list = new ArrayList < String >();
解释:创建一个ArrayList集合,但规定该集合中存储的元素类型必须为String类型
泛型在集合中的应用:
有效的解决了取出之前各个接口和类在遍历时必须进行强制类型转换的问题,并且如果把非指定类型的对象放入集合中,会出现编译错误。

  1. List的泛型形式----->List< E >
  2. ArrayList的泛型形式------->ArrayList< E >

== 示例11:使用ArrayList的泛型形式改进示例2==
实现步骤:

  1. 编写同示例2代码
  2. 创建集合对象时,使用ArrayList < NewTitle >
  3. 遍历集合时不需要进行强制转换

代码呈现

package fx;

public class NewTitle {
    private int id;
    private String name;
    private String title;

    public NewTitle(int id, String name, String title) {
        this.id = id;
        this.name = name;
        this.title = title;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
package fx;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        NewTitle car = new NewTitle(1, "管理员", "汽车");
        NewTitle test = new NewTitle(2, "管理员", "高考");
        ArrayList<NewTitle> list = new ArrayList<NewTitle>();
        list.add(car);
        list.add(test);
        for (NewTitle title:list
             ) {
            System.out.println(title.getTitle());
        }
    }
}

同样的,Map和HashMap也有他们的泛型形式。
Map------->Map<k,v>
HashMap---------->HashMap<k,v>
因为他们的每一个元素都包含两个部分,即key和value,所以在应用泛型时,要同时指定key的类型和value的类型。K表示key的类型,V表示value的类型。
示例12:使用HashMap的泛型形式改进示例7
实现步骤:

  1. 实现步骤之前的同示例7
  2. 创建集合对象时,使用的是HashMap<String,Student>
  3. 遍历集合时不需要进行强制转换

代码呈现

package fx;

public class Student {
    private String name;
    private String sex;

    public Student(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}
package fx;

import java.util.HashMap;
import java.util.Map;

public class Test2 {
    public static void main(String[] args) {
        Student t1 = new Student("李四", "男");
        Student t2 = new Student("王五", "男");
        //创建集合存储对象
        Map<String, Student> list = new HashMap<String, Student>();
        //把英文名称与学院对象按照键值对的形式存储在HashMap中
        list.put("jack",t1);
        list.put("rose",t2);
        //输出英文名
        for (String key:list.keySet()
             ) {
            System.out.println("学生的英文名为"+key);
        }
        //输出学生详细信息
        for (Student value:list.values()
             ) {
            System.out.println("学生的姓名为:"+value.getName()+"学生的性别为:"+value.getSex());
        }
    }
}

注意:
在使用put()方法存储数据时,Map集合的key类型必须为String类型而value类型必须为自己创建的类型的数据而在遍历键集的for循环中,key的类型不再是Object而是String;同理value也不是Object而是Student,也不需要进行强制转换。
前面讲到的LinkedList和HashSet也都有自己泛型形式并且与之前的相似,这里留下来自己可以练习一下之前的示例。

八、深入泛型

在学习如何使用泛型前,还需要了解一下两个重要概念。

  1. 参数化类型:参数化类型包含一个类或者接口,以及实际的类型参数列表。
  2. 类型变量:是一种非限定性标识符,用来指定类、接口或者方法的类型。

8.1定义泛型类、泛型接口和泛型方法

什么时候使用泛型定义:对于一些常常处理不同类型数据转换的接口或者类。例如:java中的List接口。
1)泛型类
泛型类简单地说就是具有一个或者多个类型参数的类。
定义泛型类的语法格式如下:

  • 访问修饰符class classname< TypeList >
  • TypeList表示类型参数列表,每个类型变量之间以逗号分隔

创建泛型类示例的语法格式如下:
new classname< TypeList >(argList);

  • TypeList表示定义的类型参数列表,每个类型变量之间以逗号分隔

  • argList表示实际传递的类型参数列表

  • 每个类型变量之间同样以逗号分隔

例如:
new GenericClass< String >(“this is String Object”)
2)泛型接口
泛型接口就是拥有一个或多个类型参数的接口。泛型接口定义的方式与定义泛型类类似。
定义泛型接口的语法格式如下:
访问修饰符 interface interfaceName< TypeList >

  • TypeList表示由逗号分隔的一个或多个类型参数列表

泛型类实现泛型接口的语法格式如下:

  • 访问修饰符 className< TypeList >implements interfaceName< TypeList >

下面我们通过一个接口来看看以上知识:
示例13:定义泛型接口、泛型类,泛型类实现泛型接口,在泛型类中添加相应的泛型方法。
实现步骤:
1)定义泛型接口,添加方法,并设置返回类型
2)定义泛型类,并且实现上述定义接口,声明类型为T的 字段name,添加构造方法
3)使用泛型类实例化定义的泛型
代码呈现

public interface TestInterfance<T> {
    public T getName();//设置的类型由外部决定

}
public class Student<T> implements TestInterfance<T> {
    private T name;

    public Student(T name) {
        this.name = name;
    }

    public void setName(T name) {
        this.name = name;
    }

    @Override
    public T getName() {
        return this.name;//返回类型由外部决定
    }

}
public class GenericesClass {
    public static void main(String[] args) {
    //创建泛型类示例
        TestInterfance<String> student = new Student<String>("张三");
        System.out.println(student.getName());
    }
}

3)泛型方法
当处理的数据类型不确定时,就可以通过泛型方法的方式来定义,达到简化代码、提高代码重用性的目的。
本质上:泛型方法就是带有参数类型的方法。
注意点:定义泛型方法与方法所在的类、或者接口是否是泛型类或者泛型接口没有直接的联系,也就是说无论是泛型类还是非泛型类,如果需要就定义泛型方法。
定义泛型语法格式如下:
访问修饰符<类型参数>返回值 方法名 (类型参数列表)
例如:
public< String >void showName (String s){}
示例14:定义泛型方法并调用
实现步骤:

  1. 定义泛型方法
  2. 调用泛型方法
public class FangFa {
public <Integer> void showSize(Integer o){
    System.out.println(o.getClass().getName());
}

    public static void main(String[] args) {
        FangFa f = new FangFa();
        f.showSize(10);
    }


}
输出结果:
java.lang.Integer

8.2.多个参数的类型

在前面的示例中我们发现,泛型类的类型参数都只有一个,实际上参数类型也是可以有多个。下面介绍如何自定义一个包含多个类型参数的泛型类。
示例15:定义泛型类,并设置两个类型参数
实现步骤:

  • 定义泛型类
  • 实例化泛型类

代码呈现

package ShenRuFX;

public class CanShu<T,V>{
    private T a;
    private V b;

    //构造函数
    public CanShu(T a, V b) {
        this.a = a;
        this.b = b;
    }
    //创建方法输出
    public void showType(){
        System.out.println("a的类型是"+a.getClass().getName());
        System.out.println("b的类型是"+b.getClass().getName());
    }
    //示例化泛型类
    public static void main(String[] args) {
        CanShu<String,Integer> c = new CanShu<>("jack",36);
        c.showType();
    }
}
输出结果:
a的类型是java.lang.String
b的类型是java.lang.Integer

总结:
在示例中,这一类定义了两个类型参数,分别是T和V。定义的时候这两个类型变量的具体类型是不清楚的。注意的是,当在一个泛型中。需要声明多个类型参数时,只需要在每个类型参数之间使用逗号将其隔开即可。在实例化泛型类时,就需要传递两个类型参数,这里分别使用了String和Integer代替了T和V。

8.3从泛型类派生子类

概述:面向对象的特性同样使用与泛型类,所以泛型类也可以继承。不过继承了泛型类的子类也必须是泛型类
继承泛型类的语法格式如下:
class 子类 < T > extends 父类 < T >{ }
示例16:定义泛型父类,同时定义一个泛型子类继承泛型父类
实现步骤:

  • 定义父类,并添加整型字段以及方法
  • 定义子类,重写父类定义的方法

代码呈现

public class Farm<T> {
    protected int plantNum = 0;//整型字段:农作物种植数量

//    public Farm(int plantNum) {
//        this.plantNum = plantNum;
//    }

    //种植农作物的方法
    public void plantCrop(T crop){
        plantNum++;
    }

}
public class FruitFarm<T> extends Farm<T> {

//    public FruitFarm(int plantNum) {
//        super(plantNum);
//    }

    public void plantCrop(List<T>list){
        plantNum+=list.size();

    }
}

结语
好了,就先讲到这里结束,有不足的地方欢迎补充,如果觉得不错,点个赞,点个关注呗,码字不易呜呜呜。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值