集合类库——泛型机制的学习

泛型的概念

  • 集合中是可以存放不同类型的对象,这是因为将所有对象都看做Object类型放入,因此从集合中取出元素时也是Object类型,需要强制类型转换,
    而强制类型转换可能会引发类型转换异常
  • 泛型机制,也就是在集合名称的右侧使用<数据类型>的方式来明确要求该集合中可以存放的元素类型,若放入其它类型的元素则编译报错
  • 泛型只在编译时期有效,在运行时期不区分是什么类型

泛型就是在集合类型的右侧加上<数据类型>,就只能存放选择的数据类型了

编程使用

泛型不需要强制转换了

//1.准备一个支持泛型机制的List集合。明确要求集合中的要求是String类型
        List<String> lt1 = new LinkedList<String>();
        //2.向集合中添加元素并打印
        lt1.add("one");
        System.out.println("lt1="+lt1);//[one]
        //3.获取集合中的元素并打印
        String s = lt1.get(0);
        System.out.println("获取到的元素是:"+s);//one

在这里插入图片描述
注意菱形特性
后面尖括号中的数据类型可以省略

//菱形特性
        List<Double> lt3 = new LinkedList<>();

笔试考点

相互不能复制

//笔试考点
        //试图讲lt1的数值赋值给lt3,也就是覆盖lt3中原来的数值
        lt3 = lt1;//编译报错 集合中支持的类型不同

泛型机制的底层原理

泛型的本质就是参数化类型,让数据类型作为参数传递,其中E相当于形式参数负责占位,而使用集合时<>中的数据类型相当于实际参数,用于给形式参数E进行初始化,从而使得集合中所有的E被实际参数替换

自定义泛型接口和泛型类

  • 泛型接口和普通接口的区别就是后面添加了类型参数列表,可以有多个类型参数,如:<E, T, … >
  • 泛型类和普通类的区别就是类名后面添加了类型参数列表,可以有多个类型参数,如:<E, T, … >等

自定义泛型类Person

其中T相当于形式参数,负责占位,具体数值由实参决定
T看作是名字为T的数据类型即可

public class Person<T> {//这里的T是形式参数,负责在这里占个位置
    private String name;
    private  int age;
    private T gender;//这里表名gender是T类型的,取决于我们一会使用Person或new Person对象时来指定

    public Person() {
    }

    public Person(String name, int age, T gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public T getGender() {
        return gender;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

泛型类的使用

集合中不支持基本数据类型

public class PersonTest {
    public static void main(String[] args) {
        //声明Peron类型的引用指向Person类型对象
        //不指定类型,按Object类型对待
        Person p1 = new Person("zhangfei",30,"male");
        //打印对象特征
        System.out.println(p1);
        System.out.println("--------------------");
        //在创建对象的同时指定数据类型,用于给T进行初始化
        Person<String> p2 = new Person<>();
        p2.setGender("female");
        System.out.println(p2); //null 0 female

        System.out.println("--------------------");
        //使用boolean作为性别类型
        Person<Boolean> p3 = new Person<>();
        p3.setGender(true);
        System.out.println(p3); //null 0 true
    }
}

在这里插入图片描述
实例化泛型类时应该指定具体的数据类型,并且是引用数据类型而不是基本数据类型

泛型类被继承时子类如何处理

  • 擦除:不保留泛型并且没有指定类型,此时Person类中的T默认为Object类型
public class SubPerson extends Person{//不保留泛型并且没有指定类型,此时Person类中的T默认为Object类型
}
  • 不保留泛型但指定了泛型的类型,此时Person类中的T被指定为String类型
public class SubPerson extends Person<String>{//不保留泛型但指定了泛型的类型,此时Person类中的T被指定为String类型

}
  • 保留父类的泛型
public class SubPerson<T> extends Person<T>{//保留父类的泛型 可以在构造对象时指定T的类型
    
}
  • 留父类的泛型 同时在子类中增加新的泛型
public class SubPerson<T, T1> extends Person<T>{//保留父类的泛型 同时在子类中增加新的泛型
    
}

使用:
在这里插入图片描述

子类除了指定或保留父类的泛型,还可以增加自己的泛型

泛型方法

泛型方法就是我们输入参数的时候,输入的是泛型参数,而不是具体的参数。我们在调用这个泛型方法的时需要对泛型参数进行实例化
在静态方法中使用泛型参数的时候,需要我们把静态方法定义为泛型方法

  • 定义泛型方法
//自定义方法实现将参数指定数组中的所有元素打印出来
    public static <T1> void printArray(T1[] arr){//<T1>就是为了告诉java这是个泛型方法
        for(T1 tt:arr){
            System.out.println("tt="+tt);
        }
        
    }
  • 调用泛型方法
System.out.println("--------------------");
        //调用泛型方法进行测试
        Integer[] arr = new Integer[]{11,22,33,44,55};
        Person.printArray(arr);

在这里插入图片描述

泛型在继承上的注意事项

String是Object的子类,但是List并不是List的子类
就如有Dog类继承自Animal类,但若把Dog放进尖括号里面,那么List<Dog>并不是List<Animal>的子类
即:如果B是A的一个子类或子接口,而G是具有泛型声明的类或接口,则G<B>并不是G<A>的子类型

通配符的使用

  • 有时候我们希望传入的类型在一个指定的范围内,此时就可以使用泛型通配符了
  • 如:之前传入的类型要求为Integer类型,但是后来业务需要Integer的父类Number类也可以传入。
  • 泛型中有三种通配符形式:
  1. <?> 无限制通配符:表示我们可以传入任意类型的参数。
  2. <? extends E> 表示类型的上界是E,只能是E或者是E的子类。
  3. <? super E> 表示类型的下界是E,只能是E或者是E的父类

创建Dog类继承Animals类

public class GenericTest {
    public static void main(String[] args) {
        List<Animal> lt1 = new LinkedList<>();
        List<Dog> lt2 = new LinkedList<>();
        //使用通配符作为泛型类型的公共父类
        List<?> lt3 = new LinkedList<>();
        lt3 = lt1;//可以发生List<Animal> 到List<?> 的类型转换
        lt3 = lt1;//可以发生List<Dog> 到List<?> 的类型转换
    }
}

说明其实List<?>是Dog和Animal的公共父类
但实际上lt3中不能存放Animal和Dog类型对象,说明?这个通配符不支持添加操作
但是

Object o = lt3.get(0);

就OK,全当Object类型了,可以直接取

Set集合

java.util.Set集合是Collection集合的子集合,与List集合平级

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值