前言:

https://www.cnblogs.com/LoveBB/p/17277662.html

什么是范型

JDK 1.5开始引入Java泛型(generics)这个特性,该特性提供了编译时类型安全检测机制,允许程序员在编译时检测到非法的类型。停,废话就不多说了,这些术语,自己去百度看看吧,反正不管你看不看得懂,我就要把你教懂,所以,这里不是重点。


泛型的作用

泛型有四个作用:类型安全、自动转换、性能提升、可复用性。即在编译的时候检查类型安全,将所有的强制转换都自动和隐式进行,同时提高代码的可复用性。着实是废话,但是不说又不行,生怕你们把路走弯了。


泛型的使用

  • 我们写代码,不也是这几样嘛:类、接口、方法。

泛型类

  • 来个3简单的类,为了让我们看清楚,类的结构
正经类
public class Student {

}
public class Teacher {

}
public class Room {

}

这谁不会啊,嘿嘿,别着急,这一般就是我们修炼的名门正派功法,这是很标准的"正派"写法。接下来,使用魔教功法进行魔改。


范型类结构
public class 类名 <泛型类型1,...> {
// todo
}

范型类
  • 一个范型

简简单单

public class Student<T> {

}
  • 两个范型

我好像在骂人,但是你没哟证据

public class Student<S,B> {
}
  • 三个范型

这里注意,范型里面的 S, B, Q 都是自定义的,一般用大些字母表示,个数不限

public class Student<S, B, Q> {
}
  • N 个范型

嘿嘿,个数不限,那就来个不限的吧

public class Student<S, B, Q, V, N, F, D, A, U, I, O, P, L, H, J, K, G> {
}

  • 关于字母

有人说,字母就26个啊,你写重复的话,那不是一样了嘛。对,你是对的,但是魔教功法就在于,他不讲道理,谁说一定要使用大写字母了,下面来个逼死强迫症写法,什么叫无限火力

public class Student<Sq, VIP, diss, QR, LKl, WOrd, Hao, Da, VPP, Ji, Ni, Tai, Mei, N, WoCao, D, CPDD, U, I, Love, Dog, OPHJKG, JiuK, HangZhou, WO, LAi, CoffEr, VCS> {

}

怎么样,好好的一个类,经过魔教功法的改造,是不是看起来不一样了。


  • 一般规定

虽然我们可以乱写,但是魔教功法还是很讲武德的,一般关于大些字母的定义如下

T:任意类型 type
E:集合中元素的类型 element
K:key-value形式 key
V: key-value形式 value
N: Number(数值类型)
?: 表示不确定的java类型

对比
  • 为了加深记忆,我们前后在对比一下
// 改造前
public class Student { } // 改造后
public class Student<T> { }
实例化
  • 那我们范型类应该怎么样实例化呢,请看下面正派写法
// 正经写法
Student student = new Student();
// 范型写法
Student<T> student = new Student<>(); // 案例1
Student<String> student = new Student<>();
// 案例2
Student<Integer> student = new Student<>();
// 案例3
Student<Teacher> student = new Student<>();
// 案例4:前面都没意思,来试试套娃吧,哈哈,走火入魔了没有,魔功就是魔功,这里自己动手,这样才清晰
Student<Student<Student<Student<Student<String, Student<String, Long>>, Boolean>, Integer>, String>, Student<String, Integer>> student = new Student<>();
// 案例5:那个最长的,我实在懒得写了,后面全部用String代替了
Student<
String,
BigDecimal,
Integer,
Boolean,
Long,
Double,
Room,
Teacher,
String,
String,
String,
String,
String,
String,
String,
String,
String
> student = new Student<>();

咱就是说,用了魔教功法之后,我们 new 出来的对象,想传什么就传什么,有多少个范型参数,就传多少个对象进去。总之就一句话,很强,运用好了,绝对是秒天秒地秒空气。


泛型接口

看过范型类了,那接下来就是接口。说实在的,接口的使用率比类高很多很多

正经接口
public interface Student {
// todo
}

范型接口结构
public interface 接口名<T> {
// todo
}
范型接口
  • 两个参数
public interface Student<T> {
// todo
}
  • 两个参数
public interface Student<S, B> {
// todo
}
  • 三个参数

停,就到这里吧,再写下去就不礼貌了,参数是和类一样的,可以N个,英文字母不限大小。


对比
// 改造前
public interface Student {
// todo
} // 改造后
public interface Student<T> {
// todo
}

  • 实例化

中所周知,接口只能用实现的方式类实例化,java8之后还能用函数式编程,这次就不展开来说了

// 正经实现
public class GoodStudent implements Student{ } // 范型实现
public class GoodStudent<T> implements Student<T>{ } // 这里不用T可不可以呢,可以的,只要子类和父类的范型一样就行
public class GoodStudent<B> implements Student<B>{ } // 实战1
public class GoodStudent<String> implements Student<String>{ } // 实战2
public class GoodStudent<Integer> implements Student<Integer>{ } // 实战N,别忘记了我们还能套娃,还能无限火力N,这里就不演示了

  • 那子类和父类的范型不一样呢,那就编译器报错呗

![image-20230331231845229](/Users/zhangch/Library/Application Support/typora-user-images/image-20230331231845229.png)


使用方式

那说了那么多,这个范型有什么用呢,答案是:接口、类声明中定义的类型形参则可以在整个接口、类中使用。

可以作为参数类型,入参,返回值使用

  • 范型使用
public class GoodStudent<T> implements Student<T>{
// 范型作为参数类型
private T personality;
// 范型接口1,作为入参
public void evaluation(T t){ }
// 范型接口2,作为入参和返回值
public T evaluation2(T t){
return t;
}
}
  • 案例参考(比较容易看懂)
// 实例化后很简单的,一看就懂,这就是我们正常的写法
public class GoodStudent<String> implements Student<String>{
// 范型参数
private String personality; public void evaluation(String t){ } public String evaluation2(String t){
return t;
} } // 案例2
public class GoodStudent<Integer> implements Student<Integer>{
// 范型参数
private Integer personality; public void evaluation(Integer t){ } public Integer evaluation2(Integer t){
return t;
} }
  • 实例化
    public static void main(String[] args) {
// String 类型
GoodStudent<String> goodStudent = new GoodStudent<>();
String personality = "";
goodStudent.evaluation(personality);
String result = goodStudent.evaluation2(personality); // Integer 类型
GoodStudent<Integer> goodStudent = new GoodStudent<>();
Integer personality = "";
goodStudent.evaluation(personality);
Integer result = goodStudent.evaluation2(personality); // 套娃类型,这里我就套一层,不然容易走火入魔
GoodStudent<GoodStudent<String>> goodStudent = new GoodStudent<>();
GoodStudent<String> personality = new GoodStudent<>();
// 内层
String resultString = personality.evaluation2(""); goodStudent.evaluation(personality);
// 外层
GoodStudent<String> result = goodStudent.evaluation2(personality);
}

泛型方法

  • 介绍范型方法之前,我们先看看普通方法,我们经常写的方法就是这样
正经方法
// 无返回值,无入参
public void test(){ }
// 无返回值,有入参
public void test(String s){ }
// 有返回值,无入参
public String test(){
return "";
}
// 有返回值,有入参
public String test(String s){
return s;
}

范型方法结构
// 范型方法就是加上一个范型声明
public <泛型类型> 返回类型 方法名(泛型类型 变量名) {
// todo
}

范型演示(注意和之前正常的对比)
// 无返回值,无入参(无意义)
public <T> void test(){ }
// 无返回值,有入参(不常用)
public <T> void test(T s){ }
// 有返回值,无入参(不太常用)
public <T> T test(){
retrn null;
}
// 有返回值,有入参(经常用)
public <T> T test(T s){
return s;
}

案例
  • 正经案例
public class GoodStudent implements Student {
// 无返回值,无入参
public void test() { } // 无返回值,有入参
public void test2(String s) { } // 有返回值,无入参
public String test3() {
return "";
} // 有返回值,有入参
public String test4(String s) {
return s;
} }
  • 正经调用
public static void main(String[] args) {
GoodStudent goodStudent = new GoodStudent();
goodStudent.test();
String s = "";
goodStudent.test2(s);
String s1 = goodStudent.test3();
String s2 = goodStudent.test4(s);
}
  • 范型案例
public class GoodStudent implements Student {
// 无返回值,无入参(无意义)
public <T> void test(){ }
// 无返回值,有入参(不常用)
public <T> void test2(T s){ }
// 有返回值,无入参(不太常用)
public <T> T test3(){
return null;
}
// 有返回值,有入参(经常用)
public <T> T test4(T s){
return s;
}
}
  • 范型调用
public static void main(String[] args) {
// String 范型
GoodStudent goodStudent = new GoodStudent();
goodStudent.test();
String s = "";
goodStudent.test2(s);
String s1 = goodStudent.test3();
String s2 = goodStudent.test4(s); // Integer 范型
GoodStudent goodStudent = new GoodStudent();
goodStudent.test();
Integer s = "";
goodStudent.test2(s);
Integer s1 = goodStudent.test3();
Integer s2 = goodStudent.test4(s); // Student<String> 范型
GoodStudent goodStudent = new GoodStudent<>();
goodStudent.test();
Student<String> s = new GoodStudent<>();
goodStudent.test2(s);
Student<String> s1 = goodStudent.test3();
Student<String> s2 = goodStudent.test4(s); }

范型方法是传什么参数,就是什么返回值


泛型通配符(上下界)

你以为这就完了?要放大招了。

Java泛型的通配符是用于解决泛型之间引用传递问题的特殊语法, 主要有以下三类:

  • 无边界的通配符,使用精确的参数类型
  • 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类
  • 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类

无边界更多是服务于上届和下届的

// 表示类型参数可以是任何类型
public class B<?> {
} // 上界:表示类型参数必须是A或者是A的子类
public class B<T extends A> {
} // 下界:表示类型参数必须是A或者是A的超类型
public class B<T supers A> {
}
正常类
public class GoodStudent implements Student{
// String参数
private String personality;
// String 作为入参
public void evaluation(String t){ }
// String作为入参和返回值
public String evaluation2(String t){
return t;
}
}
  • 范型类
public class GoodStudent<T> implements Student<T>{
// 范型参数
private T personality;
// 范型接口1,作为入参
public void evaluation(T t){ }
// 范型接口2,作为入参和返回值
public T evaluation2(T t){
return t;
}
}
  • 下界范型
public class GoodStudent<T extends String> implements Student<T> {
// 范型参数
private T personality;
// 范型接口1,作为入参
public void evaluation(T t){ }
// 范型接口2,作为入参和返回值
public T evaluation2(T t){
return t;
}
}

到这里,我已经走火入魔了,后续的后面在写了,从这里我们也能看出,一个“正派”的类,经过”魔教“功法范型的改造之后,已经具备一定的复杂性了。这就是 魔功-范型 带来的威力。

// 改造前
public class GoodStudent implements Student{
// String参数
private String personality;
// String 作为入参
public void evaluation(String t){ }
// String作为入参和返回值
public String evaluation2(String t){
return t;
}
} // 改造后
public class GoodStudent<T extends String> implements Student<T> {
// 范型参数
private T personality;
// 范型接口1,作为入参
public void evaluation(T t){ }
// 范型接口2,作为入参和返回值
public T evaluation2(T t){
return t;
}
}

java魔功心法-范型篇的更多相关文章

  1. Java数组协变与范型不变性

    变性是OOP语言不变的大坑,Java的数组协变就是其中的一口老坑.因为最近踩到了,便做一个记录.顺便也提一下范型的变性. 解释数组协变之前,先明确三个相关的概念,协变.不变和逆变. 一.协变.不变.逆 ...

  2. 为什么Java不允许创建范型数组

    问题示例 List<Integer>[] intListArr = new ArrayList<Integer>[8]; // 编译时报错 能看到这么看似没啥问题的一个简单语句 ...

  3. Java数据结构与算法分析-第一章(引论)-Java中的范型<T,E>构件

    一.为什么需要使用范型? 官方的说法是:Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质 ...

  4. Java范型随笔

    最近在帝都好无聊啊, 排遣寂寞就只有让自己不要停下来,不断的思考了 QWQ; 最近做ndk, java有点忘了,突然看到了一些java范型方面的问题, 踌躇了一会, 想着想着,决定还是写个随笔记录下来 ...

  5. Java Comparator的范型类型推导问题

    问题 在项目中,有一处地方需要对日期区间进行排序 我需要以日期区间的开始日为第一优先级,结束日为第二优先级进行排序 代码 我当时写的代码如下: List<Pair<LocalDate, L ...

  6. Java范型

    泛型不用考虑对象的具体类型.优点在于,因为不用考虑对象的具体类型所以可以对一类对象执行一定的相同操作:缺点在于,因为没有考虑对象的具体类型所以就不能使用对象自带的接口函数.泛型的最佳用同是实现容器类. ...

  7. Java范型学习笔记

    对于范型的使用或者说印象只有集合,其他地方即使使用过也不知道,反正就是只停留在List<E> Map<K, V>,最近刚好闲来无事,就找找资料学习一下:下列为个人学习总结,欢迎 ...

  8. java范型集合中的成员排序

    范型集合中的类是JsonObject,不是自定义类,如果是自定义类就直接取要比较的字段值. ArrayList<JSONObject> TList = new ArrayList<J ...

  9. 关于java范型

    1 范型只在编译阶段有效 编译器在编译阶段检查范型结果之后,就会将范型信息删除.范型信息不会进入运行时阶段. 泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型. 2 不能对确定的范型 ...

  10. 【转】Java魔法堂:String.format详解

    Java魔法堂:String.format详解     目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六. ...

随机推荐

  1. 添加新模块 import

    import getpass username = input("username") password = input("password") #passwo ...

  2. Debug --> CICFlowMeter的java版本安装及使用

    一. 首先,给出一个很详细的配置链接!使用IDEA进行配置~ https://blog.csdn.net/BananaMan45/article/details/105473151?utm_mediu ...

  3. python代码抛出异常

    from traceback import format_exc except Exception: print(format_exc())

  4. 第一个程序,Hello,World!

    Hello World 创建一个文件夹,存放代码 新建一个java文件 后缀名为.java 编写代码 public class Hello{    public static void main(st ...

  5. Layui分页与springboots

    service.java public List<Menu> listAllMenuPage(PageData pd) throws Exception{ List<Menu> ...

  6. windows IIS http 自动转https

    1.安装url重写组件 https://www.iis.net/downloads/microsoft/url-rewrite#additionalDownloads 2.刷新IIS 3.添加规则

  7. 12.6linux学习第十三天

    今天老刘开始讲第9第章使用ssh服务管理远程主机.第10章开了个小头. 9.1 配置网卡服务 9.1.1 配置网卡参数 截至目前,大家已经完全可以利用当前所学的知识来管理Linux系统了.当然,大家的 ...

  8. 8css 盒子模型

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 归纳了一下AD的快捷键

    1:shift+s 键 切换单层显示 2:q     英寸和毫米 尺寸切换3:D+R进入布线规则设置.其中 Clearance 是设置最小安全线间距,覆铜时候间距的.比较常用4:CTRL+鼠标单击某个 ...

  10. jmeter-脚本制作

    HTTP请求 默认端口号 HTTP默认端口号:80 HTTPS默认端口:443 数据来源 通过网络抓包软件(Fiddler.Charles等).接口文档数据 脚本制作+结果 录制脚本 badbod 录 ...