首页 > 编程语言 >java泛型和类型擦除

java泛型和类型擦除

时间:2023-02-01 10:05:55浏览次数:40  
标签:lang java list 擦除 Result 泛型 public


java泛型和类型擦除
泛型的本质是参数化类型,这种参数类型可以用在类、接口和方法的创建中。泛型是在JAVA 1.5版本中才引入的,它能和以前的版本兼容的原因是泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,即类型擦除。
根据使用情况可以分为以下三种:
泛型类
泛型方法
泛型接口
下面是一个常用的泛型类:

// 一个泛型类,可以根据需要包装不同结果的返回值
public class Result<T> {

private boolean success;

private String message;

private T data;

// 一个泛型方法
// 返回值类型定义前的<T>是必须的,用来声明一个类型持有者名称,然后就可以把T当作一个类型代表来声明成员、参数和返回值类型。
public static <T> Result<T> success(T data) {
Result<T> r = new Result<>();
r.success = true;
r.data = data;
return r;
}

public static <T> Result<T> error(String message) {
Result<T> r = new Result<>();
r.message = message;
return r;
}

// getter & setter
}

为什么要用T而不是其它字母?事实上是可以任意字符串(如Result< something >),但是为了显得专业,一般约定几个大写字母在不同场景使用。

T 最常用,一般代指任意类,不知道用啥就用它
E 代表Element,一般用在集合的泛型场景
K 代表Key,一般和Value一起出现在键值对场景(如Entry)
V 代表Value,一般和Key一起出现在键值对场景(如Entry)
还有些不太常见的如S,U…
类型擦除

在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

import java.lang.reflect.Field;
import java.util.Date;

public class Main {

public static void main(String[] args) throws NoSuchFieldException {
Result<Date> r1 = Result.success(new Date());
Result<Number> r2 = Result.success(2.333);
dataType(r1);
dataType(r2);
}

private static void dataType(Result<?> result) throws NoSuchFieldException {
Field field = result.getClass().getDeclaredField("data");
System.out.println(field.getType().toString());
}

}

/* 输出:

class java.lang.Object
class java.lang.Object

*/

通过反射我们在运行时得到了data的类型,发现都是Object,证明代码编译后所谓泛型都没了,这就是泛型擦除。
通过反射绕过泛型限制

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;

public class Main {

public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<Integer>();
//正规途径
list.add(1);
//反射大法
Method m = list.getClass().getMethod("add", Object.class);
m.invoke(list, 2);
m.invoke(list, 3.21);
m.invoke(list, "对不起,我是字符串");
m.invoke(list, new Date());
for (Object x : list) {
System.out.println(x.getClass().getName() + ":\t" + x);
}
}
}

/* 输出:

java.lang.Integer: 1
java.lang.Integer: 2
java.lang.Double: 3.21
java.lang.String: 对不起,我是字符串
java.util.Date: Sun Jul 28 23:49:34 CST 2019

*/


标签:lang,java,list,擦除,Result,泛型,public
From: https://blog.51cto.com/u_14389461/6030668

相关文章

  • Java中Set里remove详解
    例如1HashSetset=newHashSet();2Personp1=newPerson(1001,"AA");3Personp2=newPerson(1002,"BB");4set.add(p1);5set.add(p2);6p1.name=......
  • 【Javaweb】什么是Listener监听器?
    1、Listener监听器它是Javaweb的三大组件之一。Javaweb的三大组件分别是:Servelt程序,Filter过滤器,Listener监听器。2、Listener它是JavaEE的规范,就是接口3、监听器的作用......
  • 【Javaweb】jsp | 简单学习
    什么是jsp,它有什么用?jsp的全称是javaserverpages。Java的服务器界面。jsp的主要作用是代替Servlet程序回传html页面的数据因为Servlet程序回传html页面数据是一件非常......
  • 【Javaweb】JavaEE项目的三层架构 | 快速搭建
    逻辑类图  分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。不同的层有不同的包web层com.stguigu.web/servlet/con......
  • 极客时间 Java并发编程实战 笔记
    思考、再思考、总结、再总结01可见性、原子性和有序性举几个例子先。缓存可能导致可见性问题,因为多核CPU上的多个核可能都持有同一数据的不同缓存。两个线程并行地对......
  • JavaScript学习笔记—DOM:事件
    事件(event)事件就是用户和页面之间发生的交互行为比如:点击按钮,鼠标移动,双击按钮,敲击键盘,松开按键...可以通过为事件绑定响应函数(回调函数),来完成和用户之间的交互绑定响......
  • 学习java第四天
    IDEA安装安装完创建src创建newjava.classIDE快捷键:1.psvm=publicstaticvoidmain(String[]args){ }2.sout=System.out.println();IDE:把ide精益求精JAVA语......
  • Java斐波那契数列实例
      在斐波那契数列中,下一个数字是前两个数字的总和,例如:0,1,1,2,3,5,8,13,21,34,55等。斐波那契数列的前两个数字是0和1,第三个数字是前两个数字的和,也就是0+1=1,所以这......
  • Java素数实例
    质数(primenumber)又称素数,有无限个。质数定义是:在大于1的自然数中,除了1和它本身以外不再有其他因数的数称为质数。例如,2,3,5,7,11,13,17….是素数。注意:0和1不是素数。2是......
  • JAVA--你好世界
    publicclassHello{publicstaticvoidmain(String[]args){System.out.print("你好,世界!");}}D:\code>javacHello.java-->生成.class文件D:\co......