为跳槽面试作准备,今天开始进入 Java 基础的复习。但愿基础很差的同窗看完这篇文章,能掌握泛型,而基础好的同窗权当复习,但愿看完这篇文章可以起一点你的青涩记忆。html
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,而后调用此方法时传递实参。那么参数化类型怎么理解呢?前端
顾名思义,就是将类型由原来的具体的类型参数化(动词),相似于方法中的变量参数,此时类型也定义成参数形式(能够称之为类型形参),java
而后在使用/调用时传入具体的类型(类型实参)。python
泛型的本质是为了参数化类型(在不建立新的类型的状况下,经过泛型指定的不一样类型来控制形参具体限制的类型)。也就是说在泛型使用过程当中。linux
操做的数据类型被指定为一个参数,这种参数类型能够用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。c++
参考:www.cnblogs.com/coprince/p/…git
E:元素(Element),多用于 java 集合框架 K:关键字(Key) N:数字(Number) T:类型(Type) V:值(Value)github
回答这个问题前,首先举两个栗子,我想打印字符串到控制台,以下代码:面试
package com.nasus.generic;
import java.util.ArrayList;
import java.util.List;
/** * Project Name:review_java <br/> * Package Name:com.nasus.generic <br/> * Date:2019/12/28 20:58 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class Show {
public static void main(String[] args) {
List list=new ArrayList();
list.add("一个优秀的废人");
list.add("java 工程师");
list.add(666);
for (int i = 0; i < list.size(); i++) {
String value= (String) list.get(i);
System.out.println(value);
}
}
}
复制代码
自己个人 list 是打算装载 String 去打印的,可是你们发现没有?我传入 int 型时(编译期),Java 是没有任何提醒的(顶可能是 IDEA 警告)。直到我循环调用(运行期)打印方法,打印 int 型时,Java 才报错:算法
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
一个优秀的废人
at com.nasus.generic.Show.main(Show.java:23)
java 工程师
复制代码
第二栗子,我想实现一个能够操做各类类型的加法,以下代码:
package com.nasus.generic.why;
/** * Project Name:review_java <br/> * Package Name:com.nasus.generic <br/> * Date:2019/12/28 21:18 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class Add {
private static int add(int a, int b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
private static float add(float a, float b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
private static double add(double a, double b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}
// 一个泛型方法
private static <T extends Number> double add(T a, T b) {
System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
return a.doubleValue() + b.doubleValue();
}
public static void main(String[] args) {
Add.add(1, 2);
Add.add(1f, 2f);
Add.add(1d, 2d);
System.out.println("--------------------------");
// 如下三个都是调用泛型方法
Add.add(Integer.valueOf(1), Integer.valueOf(2));
Add.add(Float.valueOf(1), Float.valueOf(2));
Add.add(Double.valueOf(1), Double.valueOf(2));
}
}
复制代码
这个加法能够操做 int、float、double 类型,但相应的也必须重写对应的加法,而此时我其实能够就用一个泛型方法就实现了上面三个重载方法的功能。
1+2=3
1.0+2.0=3.0
1.0+2.0=3.0
--------------------------
1+2=3.0
1.0+2.0=3.0
1.0+2.0=3.0
复制代码
因此使用泛型缘由有三个:
参考:www.jianshu.com/p/986f732ed…
由咱们指定想要传入泛型类中的类型,把泛型定义在类上,用户使用该类的时候,才把类型明确下来,好比:定义一个万能的实体数据暂存工具类。
注意:泛型类在初始化时就把类型肯定了
package com.nasus.generic.how;
/** * Project Name:review_java <br/> * Package Name:com.nasus.generic.how <br/> * Date:2019/12/28 21:35 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class EntityTool<T> {
private T entity;
public T getEntity() {
return entity;
}
public void setEntity(T entity) {
this.entity = entity;
}
public static void main(String[] args) {
// 建立对象并指定元素类型
EntityTool<String> stringTool = new EntityTool<>();
stringTool.setEntity("一个优秀的废人");
String s = stringTool.getEntity();
System.out.println(s);
// 建立对象并指定元素类型
EntityTool<Integer> integerTool = new EntityTool<>();
// 此时,若是这里传入的仍是 String 类型,那就会在编译期报错
integerTool.setEntity(10);
int i = integerTool.getEntity();
System.out.println(i);
}
}
复制代码
有时候咱们只想在方法中使用泛型,能够这么定义:
值得注意的是:
package com.nasus.generic.how;
/** * Project Name:review_java <br/> * Package Name:com.nasus.generic.how <br/> * Date:2019/12/28 21:46 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class Show {
public static <T> T show(T t) {
System.out.println(t);
return t;
}
public static void main(String[] args) {
// 返回值不用强转,传进去是什么,返回就是什么
String s = show("一个优秀的废人");
int num1 = show(666);
double num2 = show(666.666);
System.out.println("------------------------");
System.out.println(s);
System.out.println(num1);
System.out.println(num2);
}
}
复制代码
泛型接口分两种实现方法:
一是实现类不明确泛型接口的类型参数变量,这时实现类也必须定义类型参数变量(好比下面 Showimpl)
接口:
public interface Show<T> {
void show(T t);
}
复制代码
public class ShowImpl<T> implements Show<T>{
@Override
public void show(T t) {
System.out.println(t);
}
public static void main(String[] args) {
ShowImpl<String> stringShow = new ShowImpl<>();
stringShow.show("一个优秀的废人");
}
}
复制代码
二是明确泛型接口的类型参数变量
public class ShowImpl2 implements Show<String>{
@Override
public void show(String s) {
System.out.println("一个优秀的废人");
}
}
复制代码
其实就是至关于指定了泛型类的父类 声明类:类名<泛型标识 extends 类>{}
在类中使用:
// 用在类上
public class Show<T extends Number> {
private T show(T t){
System.out.println(t);
return t;
}
public static void main(String[] args) {
// 初始化时指定类型
Show<Integer> show = new Show<>();
show.show(6666666);
// 报错,该类只接受继承于 Number 的泛型参数
// Show<String> stringShow = new Show<>();
}
}
复制代码
方法中使用:
定义对象:类名<泛型标识 extends 类> 对象名称
public class Info<T> {
// 定义泛型变量
private T var;
public void setVar(T var) {
this.var = var;
}
public T getVar() {
return this.var;
}
public String toString() {
return this.var.toString();
}
}
复制代码
public class ShowInfo {
// 用在方法上,只能接收 Number 及其子类
public static void showInfo(Info<? extends Number> t) {
System.out.print(t);
}
public static void main(String args[]) {
Info<Integer> i1 = new Info<>();
Info<Float> i2 = new Info<>();
i1.setVar(666666666);
i2.setVar(666666.66f);
showInfo(i1);
showInfo(i2);
}
}
复制代码
定义对象:类名<泛型标识 extends 类> 对象名称
与指定上限相反,指定下限定很简单,就是至关于指定了泛型类的子类,再也不赘述。
public class ShowInfo {
// 只接受 String 的父类
public static void showInfo(Info<? super String> t) {
System.out.println(t);
}
public static void main(String args[]) {
Info<String> stringInfo = new Info<>();
Info<Object> objectInfo = new Info<>();
stringInfo.setVar("一个优秀的废人");
objectInfo.setVar(new Object());
showInfo(stringInfo);
showInfo(objectInfo);
}
}
复制代码
泛型是提供给 javac 编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的 java 程序后,生成的 class 文件中将再也不带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为 “擦除”。
一、不能实例化泛型类 二、静态变量或方法不能引用泛型类型变量,可是静态泛型方法是能够的 三、基本类型没法做为泛型类型 四、没法使用 instanceof 关键字或 == 判断泛型类的类型 五、泛型类的原生类型与所传递的泛型无关,不管传递什么类型,原生类是同样的 六、泛型数组能够声明但没法实例化 七、泛型类不能继承 Exception 或者 Throwable 八、不能捕获泛型类型限定的异常但能够将泛型限定的异常抛出
若是看到这里,喜欢这篇文章的话,帮忙 " 转发 "或者点个" 在看 ",行吗?祝大家 2020 暴富。微信搜索「一个优秀的废人」,欢迎关注。
回复「1024」送你一套完整的 java、python、c++、go、前端、linux、算法、大数据、人工智能、小程序以及英语教程。
回复「电子书」送你 50+ 本 java 电子书。