当前位置: 首页 > news >正文

Java进阶篇之泛型

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:Java入门
🌠 首发时间:2022年9月13日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生

阅读指南

  • 泛型简介
  • 泛型类
  • 泛型方法
  • 泛型接口
  • 类型通配符
  • 可变参数
  • 可变参数的使用

泛型简介

泛型是 JDK5 中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型,它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

一提到参数,最熟悉的就是定义方法时如果有形参,调用此方法时就要传递实参,那么参数化类型该怎么来理解呢?

顾名思义,参数化类型就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型

这种参数类型可以用在类、方法和接口中,分别被称为泛型类泛型方法泛型接口

泛型的定义格式:

  • <类型>:指定一种类型的格式,这里的类型可以看成是形参
  • <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开,这里的类型可以看成是形参
  • 将来具体调用的时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

以前的写法

import java.util.*;

public class GenericDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();

        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");

        //遍历集合
        Iterator it = c.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            System.out.println(s);
        }
    }
}

学了泛型以后的写法

import java.util.*;

public class GenericDemo {
    public static void main(String[] args) {
        //创建集合对象
        Collection<String> c = new ArrayList<>();

        //添加元素
        c.add("hello");
        c.add("world");
        c.add("java");

        //遍历集合
        Iterator<String> it = c.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
    }
}

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换

泛型类

泛型类的定义格式:

  • 格式:修饰符 class 类名<类型> { }
  • 例子:public class Generic<T> { }
    此处 T 可以随便写为任意标识,常见的如 T、E、K、V 等形式的参数用于表示泛型

我们来定义一个泛型类,如下

public class Generic<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

接着测试一波

public class GenericDemo {
    public static void main(String[] args) {
        Generic<String> g1 = new Generic<>();
        g1.setT("小明");
        System.out.println(g1.getT());

        Generic<Integer> g2 = new Generic<>();
        g2.setT(30);
        System.out.println(g2.getT());

        Generic<Boolean> g3 = new Generic<>();
        g3.setT(true);
        System.out.println(g3.getT());
    }
}

结果如下:
在这里插入图片描述

泛型方法

泛型方法的定义格式:

  • 格式:修饰符<类型> 返回值类型 方法名(类型 变量名) { }
  • 例子:public<T> void show(T t) { }

定义一个泛型方法,如下

public class Generic {
    public <T> void show(T t) {
        System.out.println(t);
    }
}

测试一下

public class GenericDemo {
    public static void main(String[] args) {
        Generic g = new Generic();
        g.show("小明");
        g.show(30);
        g.show(true);
        g.show(12.34);
    }
}

没毛病

在这里插入图片描述

泛型接口

泛型接口的定义格式:

  • 格式:修饰符 interface 接口名<类型> { }
  • 例子:public interface Generic<T> { }

我们来写一个泛型接口

public interface Generic<T> {
    void show(T t);
}

写一个类实现这个接口

public class GenericImpl<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

最后测试这个类

public class GenericDemo {
    public static void main(String[] args) {
        Generic<String> g1 = new GenericImpl<>();
        g1.show("小明");

        Generic<Integer> g2 = new GenericImpl<>();
        g2.show(20);
    }
}

测试成功

在这里插入图片描述

类型通配符

为了表示各种泛型 List 的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的 List,它的元素可以匹配任何的类型
  • 这种带通配符的 List 仅表示它是各种泛型 List 的父类,并不能把元素添加到其中

如果说我们不希望 List<?> 是任何泛型 List 的父类,只希望它代表某一类泛型 List 的父类,可以使用类型通配符的上限

  • 类型通配符上限:<?extends 类型>
  • List<?extends Number>:表示的类型是 Number 或者其子类型

除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限

  • 类型通配符下限:<?super 类型>
  • List<?super Number>:表示的类型是 Number 或者其父类型

如果你不认识 Number 类,那我们这里就简单说一下,Number 是一个抽象类,也是一个超类(即父类)。Number 类属于 java.lang 包,所有的包装类(如 DoubleFloatByteShortInteger 以及 Long)都是抽象类 Number 的子类

import java.util.*;

public class GenericDemo {
    public static void main(String[] args) {
        //类型通配符:<?>
        List<?> l1 = new ArrayList<Object>();
        List<?> l2 = new ArrayList<Number>();
        List<?> l3 = new ArrayList<Integer>();
        System.out.println("---------------------");

        //类型通配符上限:<? extends 类型>
//        List<? extends Number> l4 = new ArrayList<Object>();   //不可以
        List<? extends Number> l5 = new ArrayList<Number>();
        List<? extends Number> l6 = new ArrayList<Integer>();
        System.out.println("---------------------");
        
        //类型通配符下限:<? super 类型>
        List<? super Number> l7 = new ArrayList<Object>();
        List<? super Number> l8 = new ArrayList<Number>();
//        List<? super Number> l9 = new ArrayList<Integer>();   //不可以
    }
}

可变参数

可变参数又称为参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 格式:修饰符 返回值类型 方法名(数据类型... 变量名) { }
  • 例子:public static int sum(int... a) { }

可变参数的注意事项

  • 这里的变量 a 其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,那么可变参数要放在最后
public class ArgsDemo {
    public static void main(String[] args) {
        System.out.println(sum(1, 2, 3));
        System.out.println(sum(1, 2, 3, 4, 5, 6));
        System.out.println(sum(1, 2, 3, 4, 5, 6, 7, 8, 9));
    }

    public static int sum(int... a) {
        int sum = 0;

        for (int i : a) {
            sum += i;
        }

        return sum;
    }
}

在这里插入图片描述

可变参数的使用

Arrays 工具类中有一个静态方法:

  • public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
  • 返回的列表不能做增删操作,可以做修改操作

List 接口中有一个静态方法:

  • public static <E> List<E> of(E... elements):返回一个包含任意数量元素的不可变列表
  • 返回的列表不能做增删改操作

Set 接口中有一个静态方法:

  • public static <E> Set<E> of(E... elements):返回一个包含任意数量元素的不可变集合
  • 返回的集合不能做增删操作,集合没有修改的操作

相关文章:

  • 发送post请求渲染el-table,并实现搜索和分页功能
  • [RK3568 Android11] 时间同步机制
  • 6、Mybatis-Plus wrapper的使用
  • 基于Web的爬虫系统设计与实现
  • Kubernets---配置 Pod 使用投射卷作存储
  • springcloud和分布式微服务学习笔记
  • 【“在路上”疫情信息检测】
  • `算法知识` 模意义下的乘法逆元
  • 微信小程序 | 游戏开发之接宝石箱子游戏
  • 丙烯酰氧乙基三甲基氯化铵(DAC)接枝聚苯乙烯伯胺微球微粒/聚苯乙烯包覆硅胶复合微球
  • 拿下Transformer
  • WPS-系统右键:开启后无法显示
  • C++学习笔记(1)--- 常量、数据类型、运算符
  • AI在工业机器人系统中的应用
  • mybatis一级缓存、二级缓存的意义是什么?
  • Android 控件背景颜色处理
  • JavaScript HTML DOM
  • javascript面向对象之创建对象
  • jquery cookie
  • Js基础知识(四) - js运行原理与机制
  • Laravel核心解读--Facades
  • Material Design
  • Nodejs和JavaWeb协助开发
  • Vue全家桶实现一个Web App
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • Yii源码解读-服务定位器(Service Locator)
  • 从0实现一个tiny react(三)生命周期
  • 对超线程几个不同角度的解释
  • 好的网址,关于.net 4.0 ,vs 2010
  • 将回调地狱按在地上摩擦的Promise
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 前言-如何学习区块链
  • 全栈开发——Linux
  • 使用API自动生成工具优化前端工作流
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 正则表达式
  • puppet连载22:define用法
  • #DBA杂记1
  • #pragma data_seg 共享数据区(转)
  • (13)DroneCAN 适配器节点(一)
  • (14)Hive调优——合并小文件
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (arch)linux 转换文件编码格式
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (五)MySQL的备份及恢复
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (转)visual stdio 书签功能介绍
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .Net Core与存储过程(一)