Java学习笔记 13、泛型

简介: Java学习笔记 13、泛型

一、认识泛型


首先提出一个问题:为什么有泛型?


设计背景:集合容器在设计阶段/声明阶段不能确定该容器实际存的是什么类型的对象,所以在JDK1.5之前统一将容器中的元素设计为Object,在JDK1.5之后使用泛型来解决。

将元素的类型设计成一个参数,这个参数就叫做泛型。例如:interface Collection<E> extends Iterable<E>其中的E就是泛型,根据传入类型来定。

泛型:就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时确定(例如继承实现某某接口,声明变量,创建对象)。


一个类继承了父类,那么就能通过它的父类找到对应的子类,但是不能通过其他类来找到具体要找的和这个类。

好处:使用泛型能够规范集合中的元素,避免了强转出现异常的情况,没有实现泛型前是类型不安全的。


重要点:JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持。若是不指定类型也可以默认是Object。



JDK1.7新特性:类型推断


//当我们创建实例时,new后面不需要设置指定类型了(前面一定要有)
Map<String,Integer> map = new HashMap<>();



二、自定义泛型结构


自定义泛型举例


class MyGeneric<T>{
    private String name;
    private T Order;
    public void setOrder(T order) {
        Order = order;
    }
    public T getOrder() {
        return Order;
    }
}


这里T作为泛型,等待创建实例传入指定的类型参数,并且该类属性也能够使用该泛型。


继承泛型类两种方式

方式一:不属于泛型类,直接确定类型


//当子类不使用泛型时,其继承的类需要明确类型
class Type1 extends MyGeneric<String>{//这里使用的上面自定义例子的类
}


方式二:属于泛型类,根据传过来的类型决定


//可以通过创建Type2实例时将类型也传递给MyGeneric
class Type2<T> extends MyGeneric<T>{
}



自定义泛型注意点

1、泛型类可以有多个参数,多个参数要一起放在<>中,例如<T,E,K>。


2、泛型类的构造器不需要使用<E>,和往常一样即可。


3、使用泛型类若是不指定类型,对应类型默认为Object。


4、若泛型类是一个接口或抽象类,不能创建泛型类的对象。


5、泛型指定只能使用引用数据类型,若是想要表示基本数据类型可用包装类代替。


6、异常类不能指定泛型。



三、泛型不同使用情境


泛型表示接口
interface MyGeneric<E>{
    E get();
}


一般泛型接口常用于生成器,即对象工厂,一种专门用来创建类的工厂对象。



泛型方法

泛型方法:在方法中出现泛型的结构,泛型参与类的泛型参数没有任何关系。


情况一:使用类中的泛型


class MyGeneric<T>{
    private String name;
    private T Order;
    //这里的T与创建实例时传入的类型一致
    public List<T> getList(List<T> arr){
        return arr;
    }
}


情况二:若是单独在方法中使用泛型,则需要在返回参数之前加上类似于<E>标记


class MyGeneric<T>{
    private String name;
    private T Order;
    //为了让E不表示一个类而是一个参数则需要在返回参数前加<E>
    public <E> List<E> copy(List<E> arr){
        return arr;
    }
}


不加标记会将E识别为一个类,从而找不到该类出现编译错误:




四、泛型继承上的体现


①类A是类B的超类,G<A> 和 G<B> 二者不具备子父类关系,二者是并列关系



②类A是类B的父类,A<G> 是 B<G> 的父类



总结:对于具有子父类关系的泛型类,其泛型应该一致,否则不具备子父类关系。



五、通配符使用


通配符为:?


通过使用?通配符能够解决之前G<A> 和 G<B>的问题,这两者共同的父类为G<?>



运用到方法中:


import java.util.*;
public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        traversal(list);
        traversal(list2);
    }
    //可遍历任意list<A> List<B>
    public static void traversal(List<?> list){
        Iterator<?> iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //或者
//        for (Object o : list) {
//            System.out.println(o);
//        }
    }
}



注意点:例如上面List使用?不能进行add()的添加操作,获取值也只能获取到Object类型。


@Test


public void test(){
    List<String> list1 = new ArrayList<>();
    //给list1添加两个String字符串
    list1.add("AA");
    list1.add("BB");
    List<?> list2 = null;
    list2 = list1;
    //添加(写入):对于List<?> 就不能向其内部添加数据
    //除了添加null之外
    //        list2.add("AA");
    //        list2.add('?');//两个都会进行报错
    list2.add(null);//添加null值是允许的
    //获取读取:允许读取数据,读取的数据类型为Object
    Object o = list2.get(0);
    System.out.println(o);//AA
}



有限制条件的通配符使用


<? extends Number>:只允许泛型为Number及Number子列的引用调用。


<? super Number>:只允许泛型为Number及Number父类的引用调用。


extends:使用时只能使用对应类及其子类。

super:使用时只能使用对应类及其父类。

例子如下:


public static void main(String[] args) {
    List<? extends Person> list = new ArrayList<>();
    List<? super Person> list2 = new ArrayList<>();
    List<Person> list3 = new ArrayList<>();
    List<Student> list4 = new ArrayList<>();
    List<Object> list5 = new ArrayList<>();
    //赋值操作
    list = list3;
    list = list4;
    list = list5;//无法赋值,Object是Person父类
    list2 = list3;
    list2 = list4;//无法赋值,Student是Person子类
    list2 = list5;
    //获取对应值
    Person person = list.get(0);//由于泛型范围为Person及其子类,所以返回一个最大父类Person
    Object object = list2.get(0);//由于泛型范围为Person及其父类,所以返回一个最大父为Object
}



注意其中引用赋值范围以及获取对应泛型参数值的范围!!!


六、泛型中E、T、K等含义


其实可以使用任何合法的Java标识字符串,习惯用法是单一的字母表示,为了好辨识某些泛型的含义,特使用如下几个字母:


E:可表示Element,一般在集合中使用,集合中存放元素。

T:可表示Type,Java类。

K:可表示Key,作为键,Map中使用到。

V:可表示Value,作为值,Map中使用到。

N:Number,数值类型。

?:表示不确定的java类型。


相关文章
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
617 5
|
存储 Java
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
303 13
|
9月前
|
安全 Java
Java之泛型使用教程
Java之泛型使用教程
476 10
|
9月前
|
小程序 Java 知识图谱
Java 学习笔记 —— BMI & BMR 计算器
这是一个使用 Java 编写的 BMI 与 BMR 计算器小程序,可输入年龄、性别、身高和体重,计算身体质量指数(BMI)和基础代谢率(BMR),并输出健康评估结果。通过该项目,掌握了 Java 的输入处理、数据验证、条件判断、数学运算及格式化输出等基础知识,是 Java 初学者的理想练习项目。
|
9月前
|
Java
Java 数组学习笔记
本文整理Java数组常用操作:遍历、求和、查找、最值及二维数组行求和等典型练习,涵盖静态初始化、元素翻倍、去极值求平均等实例,帮助掌握数组基础与应用。
|
11月前
|
安全 Java API
在Java中识别泛型信息
以上步骤和示例代码展示了怎样在Java中获取泛型类、泛型方法和泛型字段的类型参数信息。这些方法利用Java的反射API来绕过类型擦除的限制并访问运行时的类型信息。这对于在运行时进行类型安全的操作是很有帮助的,比如在创建类型安全的集合或者其他复杂数据结构时处理泛型。注意,过度使用反射可能会导致代码难以理解和维护,因此应该在确有必要时才使用反射来获取泛型信息。
345 11
|
开发框架 Java 开发工具
【Java全栈学习笔记-U1-day01】Java介绍
本笔记整理了Java学习的基础内容,涵盖程序理解、Java语言特性、JDK安装与配置、Java程序开发工具及编写步骤。重点介绍了Java程序的基本结构、编译和运行过程,以及输出语句的使用。通过实例演示了IDEA创建Java程序的方法,并强调了编码规范和注意事项。适合初学者复习和交流学习。 主要内容: 1. 理解程序:计算机组成、程序定义。 2. 简介:Java语言特点、技术平台、JDK作用。 3. 编写Java程序:编写、编译、运行步骤,基本结构。 4. 输出语句 5. DEA使用:新建工程、保存位置、文件介绍、新建类。 6. 扩展:注释、代码规范、大小写敏感、缩进等。
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
239 5
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
266 1
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
171 1