18、泛型

一、为什么需要泛型?

1、在完成以下需求时

(1)在ArrayList中添加3个Dog对象

(2)Dog对象包含name, age, 并输出name和age

//使用传统方法
ArrayList arrayList = new ArrayList();
arrayList.add(new Dog("旺财", 5));
arrayList.add(new Dog("小白", 7));
arrayList.add(new Dog("小黄", 3));

//问题:如果不小心加入了一只猫
arrayList.add(new Cat("yuan", 18));

//遍历
for (Object o: arrayList) {
    //向下转型
    Dog dog = (Dog) o;
    System.out.println(dog.getName() + '-' + dog.getAge());
}

2、用传统方法解决,可能会遇到如下的问题

(1)不能对加入到集合ArrayList中的数据进行约束(不安全)

(2)遍历的时候需要进行类型转换,如果集合中的数据量较大,对效率有影响

3、使用泛型解决

ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺财", 5));
arrayList.add(new Dog("小白", 7));
arrayList.add(new Dog("小黄", 3));

//存入Cat会报错
//arrayList.add(new Cat("yuan", 18));
for (Dog dog : arrayList) {
    System.out.println(dog.getName() + "-" + dog.getAge());
}

(1)使用泛型后,表示存入该集合中的元素是Dog类型对象

(2)加入其他类型会报错

(3)在遍历的时候可以直接取出Dog类型而不是Object类型

二、什么是泛型?

1、泛型概述

【可以代表一种数据类型,具体类型由程序员指定】

(1)泛型又称为参数类型,是jdk5.0出现的新特性,解决数据类型的安全性问题

(2)在类声明或实例化时只要指定好需要的具体的类型即可

(3)作用:可以在类声明时通过一个标识标识类中某个属性的类型,或者某个方法的返回值类型,或者是参数类型

2、泛型的语法

(1)泛型的声明

interface 接口<T> {
    
}
或
class 类<T> {
    
}

(2)实例化

如:
List<String> strlist = new ArrayList<String> ();
Iyerator<Customer> itertor = customers.iterator();

三、泛型的使用细节

(1)泛型只能是引用类型

(2)给泛型指定具体类型后,可以传入该类型或者其子类类型

(3)不指定类型,泛型默认为Object类

(4)泛型的使用形式

ArrayList<Integer> list1 = new ArrayList<Integer>();

//在实际开发中往往简写,编译器会自动推断
ArrayList<Integer> list1 = new ArrayList<>();

四、自定义泛型

1、泛型类

(1)基本语法

class 类名<T,R,...> {//可以由多个泛型
    成员;
}

(2)注意细节

  • 普通成员可以使用泛型(属性、方法)
  • 使用泛型的数组不能初始化
  • 静态方法不能使用类的泛型
  • 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
  • 如果在创建对象时,没有指定类型,默认为Object

2、泛型接口

(1)基本语法

interface 接口名<T, R,...> {
    
}

(2)注意细节

  • 接口中,静态成员也不能使用泛型——(接口中的属性 ,只能是final,而且是public static final修饰)
  • 泛型接口的类型,在继承接口或者是实现接口时确定
  • 没有指定类型,默认为Object

3、泛型方法

(1)基本语法

修饰符<T, R,...> 返回类型 方法名(参数列表) {
    方法体;
}

(2)注意细节

  • 泛型方法可以定义在普通类中,也可以定义在泛型类中
  • 当泛型方法被调用时,类型会确定
//使用了泛型
public void eat(T t) {}//使用了类中定义的泛型

//泛型方法
public<T> void eat(T t) {}//在方法中定义了泛型,也可以使用类定义的泛型

五、泛型的继承和通配符

(1)泛型不具备继承性

//错误,泛型不具备继承性
List<Object> list = new ArrayList<String> ();

(2)通配符

public class GenericExtends {

    public static void main(String[] args) {

        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<AA> list3 = new ArrayList<>();
        List<BB> list4 = new ArrayList<>();
        List<CC> list5 = new ArrayList<>();

        printCollection1(list1);
        printCollection1(list2);
        printCollection1(list3);
        printCollection1(list4);
        printCollection1(list5);

//        printCollection2(list1);//Object,String都没有继承AA
//        printCollection2(list2);
        printCollection2(list3);
        printCollection2(list4);
        printCollection2(list5);

        printCollection3(list1);
//        printCollection3(list2);//String不是CC的父类
        printCollection3(list3);
        printCollection3(list4);
        printCollection3(list5);
    }

    //接收List类型任何泛型类型的参数
    public static void printCollection1(List<?> c) {
        for (Object o :
                c) {
            System.out.println(o);
        }
    }

    //接收List型中继承了AA泛型类型的数据为参数
    public static void printCollection2(List<? extends AA> c) {
        for (Object o :
                c) {
            System.out.println(o);
        }
    }

    //接收List类型中泛型类型以CC父类的数据为参数,不限于直接父类
    public static void printCollection3(List<? super CC> c) {
        for (Object o :
                c) {
            System.out.println(o);
        }
    }
}

class AA {
}

class BB extends AA {
}

class CC extends BB {
}
posted @ 2022-03-08 23:53  DarkSki  阅读(54)  评论(0编辑  收藏  举报