Java泛型T,E,K,V,N,?与Object区别和含义
作者:不想起床的小张 发布时间:2022-02-23 07:25:30
通常我们在看一些源码时,发现全是T、?,晕乎乎的:sob:。于是,把泛型掌握好十分重要!
什么是泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
泛型有什么好处?写个例子一目了然:
我们要封装一个消息响应类:
public class Result implements Serializable {
// 响应码
Integer code;
// 是否成功
Boolean success;
// 返回体数据
User user;
public Result(Integer code, Boolean success, User user) {
this.code = code;
this.success = success;
this.user = user;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", success=" + success +
", user=" + user +
'}';
}
public static void main(String[] args) {
User user = new User(1, "Tony");
Result result = new Result(200, true, user);
System.out.println(result);
}
}
class User implements Serializable {
Integer id;
String name;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Result{code=200, success=true, user=User{id=1, name='Tony'}}
进程已结束,退出代码0
呼~这样这个反应体就可以返回请求状态和用户信息了。可现在需求又需要返回关于手机的信息,那我们又得封装一个能返回手机信息的响应类了...到后面还有衣服、鞋子...那不得累死?这时候泛型登场了:
public class Result<T> implements Serializable {
// 响应码
Integer code;
// 是否成功
Boolean success;
// 返回体数据
T data;
public Result(Integer code, Boolean success, T data) {
this.code = code;
this.success = success;
this.data = data;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", success=" + success +
", data=" + data +
'}';
}
public static void main(String[] args) {
User user = new User(1, "Tony");
Result<User> resultUser = new Result<>(200, true, user);
System.out.println(resultUser);
Phone phone = new Phone(999.99, "Yellow");
Result<Phone> resultPhone = new Result<>(200, true, phone);
System.out.println(resultPhone);
}
}
class User implements Serializable {
Integer id;
String name;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
class Phone implements Serializable {
Double price;
String color;
@Override
public String toString() {
return "Phone{" +
"price=" + price +
", color='" + color + '\'' +
'}';
}
public Phone(Double price, String color) {
this.price = price;
this.color = color;
}
}
Result{code=200, success=true, data=User{id=1, name='Tony'}}
Result{code=200, success=true, data=Phone{price=999.99, color='Yellow'}}
进程已结束,退出代码0
可见,利用泛型,可以统一标识需要返回的实体类。不管你来什么类,我都可以给你塞进去!
第一次接触可能看不太明白,下面就详细讲解
泛型方法
你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
语法规则
所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前
比如说这是一个用来打印数组的泛型方法:
private static <E> void printArray(E[] inputArray)
每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
比如这个方法
private static <E,T> void printArray(E[] inputArray, T data)
类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(int double char等)
泛型标记符
E Element 集合元素
T Type Java类
K Key 键
V Value 值
N Number 数值类型
? 表示不确定的Java类型
这些标记并不是限定只有对应的类型才能使用,即使你统一使用A-Z英文字母的其中一个,编译器也不会报错。之所以又不同的标记符,这是一种**约定。**在开发中很多规则都是一种约定,它能提高我们代码的可读性,方便团队见的合作开发
写个完整的例子:
public class TFunction {
public static void main(String[] args) {
// 创建各种类型的数组
Integer[] intArray = {1, 2, 3, 4, 5};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
System.out.println("整型数组元素为:");
printArray(intArray); // 传递一个整型数组
System.out.println("\n双精度型数组元素为:");
printArray(doubleArray); // 传递一个双精度型数组
System.out.println("\n字符型数组元素为:");
printArray(charArray); // 传递一个字符型数组
}
// 泛型方法
private static <E> void printArray(E[] inputArray) {
// 遍历打印数组
Arrays.stream(inputArray).forEach(e -> {
System.out.printf("%s ", e);
});
System.out.println();
}
}
泛型类
泛型类的声明与非泛型类几乎相同,唯一的不同在于类名的后面添加了参数声明部分
这边就不举例子了,因为开篇的例子就是封装了一个泛型类,当时不太理解的可以再回去看一下
类型通配符
?
我们一般可以使用?来承接所有的引用类型,搬运一个菜鸟上的例子:
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
getData(name);
getData(age);
getData(number);
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
}
data :icon
data :18
data :314
?extends T
这是**泛型上边界:**只有T对象的子类可以被传入
如果是? extends C,那么只有D和E允许被传入,否则会编译报错
? super T
这是**泛型下边界:**只有T对象的父类可以被传入
如果是? super D,那么只有C和A允许被传入,否则会编译报错
T 和 ?
不知道看到这里,有没有疑惑。T和?好像作用差不多啊,有什么区别?
这里解释一下,T一般作为泛型参数,而?是更多是用来一个不确定的引用类型,意会一下吧~~~
T 和 Object
重头戏!!
知道的Object的同志都了解其是Java的超类(所有对象的父类),不了解的可以去看看我的博客,有做详细的解释。
那么问题就来了,Object好像可以代替泛型的功能啊!所有能用到泛型的地方Object都可以!
其实,在JDK5之前,都是用的Object,但其存在很多的问题,JDK5之后便引入了泛型
Object是所有类的父类,在编码过程中就难免出现类型转化问题,且在编译阶段不会报错,到了运行阶段才暴露问题,大大降低了程序的安全性和健壮性!
举例之前说一些转型的分类:
向上转型 用父类声明一个子类对象 例如:Animal是Cat的父类,在声明时我们这么写:
Animal cat = new Cat();
向下转型
将父类对象强转为其子类实例:
Animal cat = new Cat();
Cat anotherCat = (Cat) cat;
所以当我们使用Object作为泛型来使用时,不仅写起来麻烦,还要不停的进行类型转化,还很容易出现问题,很逊的诶~
举个例子看看:
利用Object定义了一个数字变量,我们常识将其向下转型为Integer和String。将一个数字转型为字符串是一件荒唐的事情,可编译器并不能察觉这件事,直到程序运行了起来...
类型转换异常!!!
来源:https://juejin.cn/post/7072703705811779620


猜你喜欢
- 本文实例讲述了C#数字图像处理之图像二值化(彩色变黑白)的方法。分享给大家供大家参考。具体如下://定义图像二值化函数private sta
- 本文实例为大家分享了java动态模拟时钟的具体代码,供大家参考,具体内容如下应用名称:java动态模拟时钟用到的知识:javaGUI,jav
- springboot项目启动,访问报404错误今天在做一个springboot项目的时候,是接着别人的项目写的,写完之后想做一下测试,于是就
- 先记下来,以备后用! /// <summary> /// 金额转为大写金额 //
- 最近在做项目时需要对异常进行全局统一处理,主要是一些分类入库以及记录日志等,因为项目是基于Springboot的,所以去网络上找了一些博客文
- 1、前言在日常的Spring Boot项目开发中,我们都会建立几个固有的包,分别是Controller、entity(pojo)、dao、s
- 阿里云accessID和secret请自行进入阿里云申请sms.template.code请进入阿里云,进行短信服务进行魔板添加开源代码地址
- 概要:流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性
- —学习并使用mybatis-plus的一些高级功能的用法例如: AR模式、 乐观锁 、逻辑删除 、自动填充、数据保护等功能为了方便演示,咱们
- PS:用了一下个推.感觉实现第三方应用的推送功能还是比较简单的.官方文档写的也非常的明确.学习内容:1.使用个推实现第三方应用的推送.所有的
- 今天为大家介绍一下语音动弹界面的实现,新版本的客户端大家应该都看过了,这里我就只简单的介绍一下控件布局了。你可以在这里看到本控件的完整源码:
- 开发设计搞了一个带圆形进度的进度条,在GitHub上逛了一圈,发现没有,自己撸吧。先看界面效果:主要思路是写一个继承ProgressBar的
- pom文件如果你的springboot项目要用到druid,那么这三个依赖必不可少:<dependency> &n
- 日常使用中spring的 @Cacheable 大家一定不陌生,基于aop机制的缓存实现,并且可以选择cacheManager具体提供缓存的
- 概述LruCache的核心原理就是对LinkedHashMap的有效利用,它的内部存在一个LinkedHashMap成员变量,值得注意的4个
- 一、导入JAR包二、配置applicationContext.xml的spring核心配置三、 public static void mai
- 前言Android Studio是Google开发的一款面向Android开发者的IDE,支持Windows、Mac、Linux等操作系统,
- JVM 的主要作用是什么?JVM 就是 Java Virtual Machine(Java虚拟机)的缩写,JVM 屏蔽了与具体操作系统平台相
- 在安卓开发中,会碰到选开始日期和结束日期的问题。特别是在使用Pad时,如果弹出一个Dialog,能够同时选择开始日期和结束日期,那将是极好的
- 最近在做项目的时候,一直用一个叫做API的东西,controller注解我会写,这个东西我也会用,但是我确实不知道这个东西是个什么,有点神奇