Java基础(二十):泛型

news2024/11/13 14:45:46

Java基础系列文章

Java基础(一):语言概述

Java基础(二):原码、反码、补码及进制之间的运算

Java基础(三):数据类型与进制

Java基础(四):逻辑运算符和位运算符

Java基础(五):流程控制语句

Java基础(六):数组

Java基础(七):面向对象编程

Java基础(八):封装、继承、多态性

Java基础(九):Object 类的使用

Java基础(十):关键字static、代码块、关键字final

Java基础(十一):抽象类、接口、内部类

Java基础(十二):枚举类

Java基础(十三):注解(Annotation)

Java基础(十四):包装类

Java基础(十五):异常处理

Java基础(十六):String的常用API

Java基础(十七):日期时间API

Java基础(十八):java比较器、系统相关类、数学相关类

Java基础(十九):集合框架

Java基础(二十):泛型


目录

  • 一、泛型概述
    • 1、集合中使用泛型
  • 二、自定义泛型结构
    • 1、泛型的基础说明
    • 2、自定义泛型类或泛型接口
      • 2.1、说明
      • 2.2、注意
    • 3、自定义泛型方法
      • 3.1、说明
  • 三、泛型在继承上的体现
  • 四、通配符的使用
    • 1、通配符的读与写
    • 2、使用注意点
    • 3、有限制的通配符


一、泛型概述

  • 在JDK5.0之前只能把元素类型设计为Object
  • JDK5.0时Java引入了“参数化类型(Parameterized type)”的概念,允许我们在创建集合时指定集合元素的类型
  • 所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值或参数的类型

1、集合中使用泛型

  • 集合中没有使用泛型时

在这里插入图片描述

  • 集合中使用泛型时

在这里插入图片描述
举例:

//泛型在List中的使用
@Test
public void test1(){
    //举例:将学生成绩保存在ArrayList中
    //标准写法:
    //ArrayList<Integer> list = new ArrayList<Integer>();
    //jdk7的新特性:类型推断
    ArrayList<Integer> list = new ArrayList<>();

    list.add(56); //自动装箱
    list.add(76);
    list.add(88);
    list.add(89);
    //当添加非Integer类型数据时,编译不通过
    //list.add("Tom");//编译报错

    Iterator<Integer> iterator = list.iterator();
    while(iterator.hasNext()){
        //不需要强转,直接可以获取添加时的元素的数据类型
        Integer score = iterator.next();
        System.out.println(score);
    }
}

二、自定义泛型结构

1、泛型的基础说明

  • <类型>这种语法形式就叫泛型
  • <类型>的形式我们称为类型参数,这里的"类型"习惯上使用T表示,是Type的缩写。即:<T>
  • <T>:代表未知的数据类型,我们可以指定为<String>,<Integer>,<Circle>等
  • 类比方法的参数的概念,我们把<T>,称为类型形参,将<Circle>称为类型实参,有助于我们理解泛型
  • 这里的T,可以替换成K,V等任意字母
  • 声明类或接口时,在类名或接口名后面声明泛型类型,我们把这样的类或接口称为泛型类泛型接口
【修饰符】 class 类名<类型变量列表>extends 父类】 【implements 接口们】{
    
}
【修饰符】 interface 接口名<类型变量列表>implements 接口们】{
    
}

//例如:
public class ArrayList<E>    
public interface Map<K,V>{
    ....
} 
  • 声明方法时,在【修饰符】与【返回值类型】之间声明类型变量,我们把声明了类型变量的方法,称为泛型方法
[修饰符] <类型变量列表> 返回值类型 方法名([形参列表])[throws 异常列表]{
    //...
}

//例如:java.util.Arrays类中的
public static <T> List<T> asList(T... a){
    ....
}

2、自定义泛型类或泛型接口

  • 当我们在类或接口中定义某个成员时,该成员的相关类型是不确定的
  • 而这个类型需要在使用这个类或接口时才可以确定,那么我们可以使用泛型类、泛型接口

2.1、说明

  • 我们在声明完自定义泛型类以后,可以在类的内部(比如:属性、方法、构造器中)使用类的泛型
  • 我们在创建自定义泛型类的对象时,可以指明泛型参数类型
    • 一旦指明,内部凡是使用类的泛型参数的位置,都具体化为指定的类的泛型类型
  • 如果在创建自定义泛型类的对象时,没有指明泛型参数类型
    • 那么泛型将被擦除,泛型对应的类型均按照Object处理,但不等价于Object
    • 经验:泛型要使用一路都用。要不用,一路都不要用
  • 泛型的指定中必须使用引用数据类型。不能使用基本数据类型,此时只能使用包装类替换
  • 除创建泛型类对象外,子类继承泛型类时、实现类实现泛型接口时,也可以确定泛型结构中的泛型参数
    • 如果我们在给泛型类提供子类时,子类也不确定泛型的类型,则可以继续使用泛型参数
    • 我们还可以在现有的父类的泛型参数的基础上,新增泛型参数

2.2、注意

  • 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
  • JDK7.0 开始,泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>()
  • 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]
    • 参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组
  • 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,但不可以在静态方法中使用类的泛型
    • 静态方法需要在类加载初始化默认值,类泛型在创建对象时候才能确定类型,所以自洽
  • 异常类不能是带泛型的

举例1:

class Person<T> {
    // 使用T类型定义变量
    private T info;
    // 使用T类型定义一般方法
    public T getInfo() {
        return info;
    }
    public void setInfo(T info) {
        this.info = info;
    }
    // 使用T类型定义构造器
    public Person() {
    }
    public Person(T info) {
        this.info = info;
    }
    // static的方法中不能声明泛型
    //public static void show(T t) {
    //
    //}
    // 不能在try-catch中使用泛型定义
    //public void test() {
        //try {
        //
        //} catch (MyException<T> ex) {
        //
        //}
    //}
}

举例2:

class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son1 extends Father {// 等价于class Son extends Father<Object,Object>{
}
// 2)具体类型
class Son2 extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2> extends Father<Integer, T2> {
}

3、自定义泛型方法

  • 如果我们定义类、接口时没有使用<泛型参数>
  • 但是某个方法形参类型不确定时,这个方法可以单独定义<泛型参数>

3.1、说明

  • 泛型方法的格式:
[访问权限]  <泛型>  返回值类型  方法名([泛型标识 参数名称])  [抛出的异常]{
    
}
  • 方法,也可以被泛型化,与其所在的类是否是泛型类没有关系
  • 泛型方法中的泛型参数在方法被调用时确定
  • 泛型方法可以根据需要,声明为static

举例1:

public class DAO {
    public <E> E get(int id, E e) {
        E result = null;
        return result;
    }
}

举例2:

public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
        c.add(o);
    }
}

public static void main(String[] args) {
    Object[] ao = new Object[100];
    Collection<Object> co = new ArrayList<Object>();
    fromArrayToCollection(ao, co);

    String[] sa = new String[20];
    Collection<String> cs = new ArrayList<>();
    fromArrayToCollection(sa, cs);
}

三、泛型在继承上的体现

  • 如果B是A的一个子类型(子类或者子接口)
    • 而G是具有泛型声明的类或接口
    • G<B>并不是G<A>的子类型!
  • 比如:String是Object的子类,但是List<String>并不是List<Object>的子类

在这里插入图片描述

public void testGenericAndSubClass() {
    Person[] persons = null;
    Man[] mans = null;
    //Person[] 是 Man[] 的父类
    persons = mans;

    Person p = mans[0];

    // 在泛型的集合上
    List<Person> personList = null;
    List<Man> manList = null;
    //personList = manList;(报错)
}

四、通配符的使用

  • ? 为泛型非限定通配符,表示类型未知,不用声明,可以匹配任意的类
  • 比如:List<?>Map<?,?>
    • List<?>List<String>List<Object>等各种泛型List的父类

1、通配符的读与写

写操作

  • 将任意元素加入到其中不是类型安全的
Collection<?> c = new ArrayList<String>();

c.add(new Object()); // 编译时错误
  • 因为我们不知道c的元素类型,我们不能向其中添加对象
  • 唯一可以插入的元素是null,因为它是所有引用类型的默认值

读操作

  • 读取List<?>的对象list中的元素时,永远是安全的
  • 因为不管 list 的真实类型是什么,它包含的都是Object

举例1:

public class TestWildcard {
    public static void m4(Collection<?> coll){
        for (Object o : coll) {
            System.out.println(o);
        }
    }
}

举例2:

public static void main(String[] args) {
    List<?> list = null;
    list = new ArrayList<String>();
    list = new ArrayList<Double>();
    // list.add(3);//编译不通过
    list.add(null);

    List<String> l1 = new ArrayList<String>();
    List<Integer> l2 = new ArrayList<Integer>();
    l1.add("尚硅谷");
    l2.add(15);
    read(l1);
    read(l2);
}

public static void read(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
}

2、使用注意点

  • 注意点1:编译错误:不能用在泛型方法声明上,返回值类型前面<>不能使用?
public static <?> void test(ArrayList<?> list){
}
  • 注意点2:编译错误:不能用在泛型类的声明上
class GenericTypeClass<?>{
}
  • 注意点3:编译错误:不能用在创建对象上,右边属于创建集合对象
ArrayList<?> list2 = new ArrayList<?>();

3、有限制的通配符

  • <?>:允许所有泛型的引用调用
  • 通配符指定上限:<? extends 类/接口 >:使用时指定的类型必须是继承某个类,或者实现某个接口,即(子类)<=
  • 通配符指定下限:<? super 类/接口 >:使用时指定的类型必须是操作的类或接口,或者是操作的类的父类或接口的父接口,即(父类)>=
  • 说明:
<? extends Number>     //(无穷小 , Number]
//只允许泛型为Number及Number子类的引用调用

<? super Number>      //[Number , 无穷大)
//只允许泛型为Number及Number父类的引用调用

<? extends Comparable>
//只允许泛型为实现Comparable接口的实现类的引用调用

举例1

class Creature{}
class Person extends Creature{}
class Man extends Person{}

class PersonTest {
    public static <T extends Person> void test(T t){
        System.out.println(t);
    }

    public static void main(String[] args) {
        test(new Person());
        test(new Man());
        test(new Creature());// 编译报错
    }
}

举例2:

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement1(list1);
    getElement1(list2);//报错
    getElement1(list3);
    getElement1(list4);//报错
  
    getElement2(list1);//报错
    getElement2(list2);//报错
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}

举例3:

@Test
public void test1(){
    //List<Object> list1 = null;
    List<Person> list2 = new ArrayList<Person>();
    //List<Student> list3 = null;

    List<? extends Person> list4 = null;

    list2.add(new Person());
    list4 = list2;

    //读取:可以读
    Person p1 = list4.get(0);

    //写入:除了null之外,不能写入
    list4.add(null);
    //        list4.add(new Person());
    //        list4.add(new Student());

}

@Test
public void test2(){
    //List<Object> list1 = null;
    List<Person> list2 = new ArrayList<Person>();
    //List<Student> list3 = null;

    List<? super Person> list5 = null;
    list2.add(new Person());

    list5 = list2;

    //读取:可以实现
    Object obj = list5.get(0);

    //写入:可以写入Person及Person子类的对象
    list5.add(new Person());
    list5.add(new Student());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/465874.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SWAT水文模型】SWAT水文模型建立及应用第四期: 气象数据的准备(待更新)

SWAT水文模型建立及应用&#xff1a; 气象数据的准备 1 简介2 气象数据的准备&#xff08;传统气象站&#xff09;2.1 天气发生器各参数的计算2.2 降水及气温输入数据的准备 3 气象数据的准备&#xff08;中国区域高精度同化气象站CMADS&#xff09;参考 本博客主要介绍气象数据…

Git命令与在IDEA中配置Git

目录 Git常用命令 全局设置 1.设置用户信息 2.查看配置信息 3.获取Git仓库 工作区, 暂存区, 版本库的概念 本地仓库操作 远程仓库操作 分支操作 标签操作 IDEA配置Git 本地仓库操作 远程仓库操作 分支操作 Git常用命令 全局设置 1.设置用户信息 git config --g…

ESP32设备驱动-VEML7700光照度传感器驱动

VEML7700光照度传感器驱动 1、VEML7700介绍 文章目录 VEML7700光照度传感器驱动1、VEML7700介绍2、硬件准备3、软件准备4、驱动实现VEML7700 是一款高精度环境光数字 16 位分辨率传感器。 它包括一个高灵敏度光电二极管、一个低噪声放大器、一个 16 位 A/D 转换器,并支持一个…

Coursera—Andrew Ng机器学习—课程笔记 Lecture 1_Introduction and Basic Concepts 介绍和基本概念

1. 1欢迎 1.2 机器学习是什么 参考视频: 1 - 2 - What is Machine Learning_ (7 min).mkv 1.2.1 机器学习定义 • Arthur Samuel (1959). Machine Learning: Field of study that gives computers the ability to learn without being explicitly programmed. 机器学习…

基于COM组件实现C#调用C++类对象过程中的注意事项

目录 一、基于COM的调用原理二、注意事项如何在C ATL中有效添加方法与属性如何让C#调用C中的属性&#xff08;.idl中声明属性&#xff09;如何对变量类型进行转换C#如何获取C类中的参数变量 一、基于COM的调用原理 调用原理&#xff1a;首先基于C ATL模板类&#xff0c;实现需…

29次-CCF-第一题-田地丈量

1 题目链接 进去后点&#xff0c;模拟考试就可以看到题目了 AC证明&#xff1a; 2 分析 前言&#xff1a; 离谱&#xff0c;这个题考试的时候做了30min才写出来&#xff0c;但是代码还贼简单。 你说它难吧&#xff0c;代码这么简单&#xff0c;你说不难吧&#xff0c;我在这…

CSS布局之圣杯布局/双飞翼布局

&#x1f4dd;个人主页&#xff1a;爱吃炫迈 &#x1f48c;系列专栏&#xff1a;HTMLCSS &#x1f9d1;‍&#x1f4bb;座右铭&#xff1a;道阻且长&#xff0c;行则将至&#x1f497; 文章目录 圣杯布局HTML代码步骤CSS代码 双飞翼布局HTML代码步骤CSS代码 小结 圣杯布局 HTM…

延长无线传感器网络网络寿命的异构节点智能部署策略(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 无线传感器网络是通过大量分布的传感器节点作为终端来协同感知和自主地监测外部世界,以多跳、自组织或协作的方式进行通信和信息…

Android系统架构

Application层&#xff0c;也就是应用层&#xff0c;不仅包括通话短信联系人这种系统级的应用&#xff0c;还包括用户自己安装的一些第三方应用Framework层&#xff0c;这一层大部分用Java写的&#xff0c;包括系统服务和四大组件Library层&#xff0c;这一层大部分都是C/C写的…

C++调用matlab编译动态库方法及相关问题解决

目录 参考链接&#xff1a;1、C调用matlab代码的方法1.1、Library Compiler 方法1.1.1、功能1.1.2、参考链接 1.2、mex -setup方法1.2.1、功能参考链接&#xff1a; 1.3、coder 方法功能 1.4、Matlab engine 2、C 使用matlab编译动态库的传参方法3、matlab运行时 参考链接&…

《AI嵌入式系统技术与实践-基于树莓派RP2040和MicroPython》书籍介绍

图书封面及出版信息 该书由本博主编著&#xff0c;全书总字数约50万字&#xff0c;本书于2023年4月出版。 内容简介 本书基于以RP2040 MCU芯片为核心的树莓派Pico开发板硬件扩展接口&#xff0c;利用Pico硬件扩展接口和面包板设计典型硬件电路&#xff0c;并结合当今流行的微…

网络编程(TCP与UDP协议)

文章目录 1. 网络编程1.1 软件架构1.2 网络基础 2. 网络通信要素2.1 如何实现网络中的主机互相通信2.2 通信要素一&#xff1a;IP地址和域名2.2.1 IP地址2.2.2 域名 2.3 通信要素二&#xff1a;端口号2.4 通信要素三&#xff1a;网络通信协议 3. 传输层协议&#xff1a;TCP与UD…

如何快速查询Git的config配置文件的本地路径

如何快速查询Git的config配置文件的本地路径 命令作用git config --local --list --show-origin查看仓库级别 git 配置信息&#xff0c;并打印配置文件本地路径最高优先级&#xff08;仓库下&#xff09;git config --global --list --show-origin查看全局级别 git 配置信息&a…

2022年全国职业院校技能大赛网络系统管理赛项模块B:Windows部署(样题1)

2022年全国职业院校技能大赛 网络系统管理赛项 模块B&#xff1a;Windows部署 &#xff08;样题1&#xff09; 目录 一、 初始化环境 &#xff08;一&#xff09;默认账号及默认密码 二、项目任务描述 &#xff08;一&#xff09;基本配置 &#xff08;二&#xff09;拓…

C语言控制语句

文章目录 前言一、分支语句1.if语句2.if else else if3.switch语句 二、循环语句1.for循环2.while循环3.do-while循环 三、跳转语句1.break语句2.continue语句3.goto语句 四、嵌套语句1.if语句嵌套2.for语句嵌套3.while语句嵌套 总结 前言 C语言中的控制语句是非常重要的一个知…

JVM入门必备

1、JVM 的位置 2、JVM 的体系结构 JVM&#xff08;Java虚拟机&#xff09;是Java程序的运行环境&#xff0c;它对于Java平台的运行和跨平台特性的实现有着重要的作用。JVM的体系结构有以下几个部分&#xff1a; 类加载器&#xff08;ClassLoader&#xff09;&#xff1a;负责将…

day4 IP地址与端口号

IP地址及其表示方式 IP地址表示方法&#xff1a; 分类的IP地址&#xff1a; 多归属主机&#xff1a; 当一个主机通过两个网卡同时连接到两网络时&#xff0c;也就是该主机同时拥有两个IP地址&#xff0c;该主机被称为多归属主机&#xff1b; 一个路由器至少连接到两个不同的网…

C++语法(21)---- 模拟map和set

(1条消息) C语法&#xff08;20&#xff09;---- 模拟红黑树_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130296772?spm1001.2014.3001.5501 目录 1.stl中的设计思想 2.模拟set和map 1.set和map的类 2.BRTree的仿函数实现 3.红黑树的迭…

C语言力扣简单题-两数之和

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 两数之和 题目&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和…

从数据处理到人工智能(常用库的介绍)

Python库之数据分析 ​​​​​​​​​​​​ 可以这么理解pandas通过扩展了对一维数据和二维数据的一种表示&#xff0c;因而能够形成更高层对数据的操作&#xff0c;简化数据分析的运行 Python库之数据可视化 Matplotlib — Visualization with Python seaborn: statistic…