大白话说Java泛型(一):入门、原理、使用
文章首发于【博客园-陈树义】,点击跳转到原文《大白话说Java泛型(一):入门、原理、使用》
远在 JDK 1.4 版本的时候,那时候是没有泛型的概念的。当时 Java 程序员们写集合类的代码都是类似于下面这样:
List list = new ArrayList();
list.add("www.cnblogs.com");
list.add(23);
String name = (String)list.get(0);
Integer number = (Integer)list.get(1);
在代码中声明一个集合,我们可以往集合中放入各种各样的数据,而在取出来的时候就进行强制类型转换。
但其实这样的代码存在一定隐患,因为可能过了不久我们就会忘记到底我们存放的 list 里面到底第几个是 String,第几个是 Integer 了。这样就会出现下面这样的情况:
List list = new ArrayList();
list.add("www.cnblogs.com");
list.add(23);
String name = (String)list.get(0);
String number = (String)list.get(1); //ClassCastException
上面的代码在运行时会发生强制类型转换异常。这是因为我们在存入的时候,第二个是一个 Integer 类型,但是取出来的时候却将其强制转换为 String 类型了。
泛型的诞生
Sun 公司为了使 Java 语言更加安全,减少运行时异常的发生。于是在 JDK 1.5 之后推出了泛型的概念。
于是在 JDK 1.5 之后,我们如果使用集合来书写代码,可以使用下面这种形式:
List<String> list = new ArrayList();
list.add("www.cnblogs.com");
list.add("www.cnblogs.com/chanshuyi");
String cnBlogs = list.get(0);
String myWebSite = list.get(1);
泛型就是将类型参数化,其在编译时才确定具体的参数。在上面这个例子中,这个具体的类型就是 String。可以看到我们在创建 List 集合的时候指定了 String 类型,这就意味着我们只能往 List 集合中存放 String 类型的数据。而当我们指定泛型之后,我们去取出数据后就不再需要进行强制类型转换了,这样就减少了发生强制类型转换的风险。
上面我们通过两个很简单的例子知道了为什么要有泛型,以及泛型最简单的使用。下面我们通过一个面试中常见的例子来看一下泛型的本质是什么。
泛型的本质
ArrayList<String> a = new ArrayList<String>();
ArrayList<Integer> b = new ArrayList<Integer>();
Class c1 = a.getClass();
Class c2 = b.getClass();
System.out.println(c1 == c2);
在继续往下看之前,先想一想,这道题输出的结果是什么?
是 true 还是 false ?
这道题输出的结果是 true。因为无论对于 ArrayList 还是 ArrayList,它们的 Class 类型都是一直的,都是 ArrayList.class。
那它们声明时指定的 String 和 Integer 到底体现在哪里呢?
答案是体现在类编译的时候。
当 JVM 进行类编译时,会进行泛型检查,如果一个集合被声明为 String 类型,那么它往该集合存取数据的时候就会对数据进行判断,从而避免存入或取出错误的数据。
也就是说:泛型只存在于编译阶段,而不存在于运行阶段。在编译后的 class 文件中,是没有泛型这个概念的。
上面我们只是说了泛型在集合中的使用方式,但其实泛型的应用范围不仅仅只是集合,还包括类、方法、Map 接口等等。
泛型的应用还广泛存在于下面几种情形:泛型类、泛型方法、泛型集合。
泛型类
泛型类一般使用字母 T 作为泛型的标志。
public class GenericClass<T> {
private T object;
public T getObject() {
return object;
}
public void setObject(T object) {
this.object = object;
}
}
使用:
public static void main(String[] args) {
GenericClass<Integer> integerGenericClass = new GenericClass<>(100);
integerGenericClass.showType();
GenericClass<String> stringGenericClass = new GenericClass<>("www.cnblogs.com/chanshuyi");
stringGenericClass.showType();
}
除了使用 T 作为泛型类的标志之外,在需要使用 Map 的类中,通常使用 K V 两个字母表示 Key Value 对应的类型。
public class GenericMap<K, V> {
private K key;
private V value;
public void put(K key, V value) {
this.key = key;
this.value = value;
}
}
使用:
public static void main(String[] args) {
GenericMap<Integer, String> team = new GenericMap<>();
team.put(1, "YaoMin");
team.put(2, "Me");
GenericMap<String, Integer> score = new GenericMap<>();
score.put("YaoMin", 88);
score.put("Me", 80);
}
泛型方法
泛型方法一般使用字母 T 作为泛型的标志。
public class GenericMethod {
public static <T> T getObject(Class<T> clz) throws InstantiationException, IllegalAccessException{
T t = clz.newInstance();
return t;
}
}
使用:
public static void main(String[] args) throws Exception{
GenericMethod genericMethod = getObject(GenericMethod.class);
System.out.println("Class:" + genericMethod.getClass().getName());
}
总结
我们通过一个简单的例子理解了泛型诞生的缘由,之后又通过一个常见的面试题明白了泛型只存在于编译期间的本质,最后介绍了常见的泛型使用场景。
下篇文章,我们将介绍泛型中通配符的使用。
文章首发于【博客园-陈树义】,点击跳转到原文《大白话说Java泛型(一):入门、原理、使用》
大白话说Java泛型(一):入门、原理、使用的更多相关文章
- 大白话说Java泛型:入门、使用、原理
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型:入门.使用.原理> 远在 JDK 1.4 版本的时候,那时候是没有泛型的概念的.当时 Java 程序员们写集合类的代码都 ...
- 大白话说Java反射:入门、使用、原理
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java反射:入门.进阶.原理> 反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释. 一般情况下,我们使用某个类时 ...
- 大白话说Java反射:入门、使用、原理 (转)
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java反射:入门.进阶.原理> 目录 一个简单的例子 反射常用API 获取反射中的Class对象 通过反射创建类对象 通过反射获取类 ...
- 大白话说Java泛型(二):深入理解通配符
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型(二):深入理解通配符> 上篇文章<大白话说Java泛型(一):入门.原理.使用>,我们讲了泛型的产生缘由以及 ...
- java泛型的实现原理
java泛型的实现原理是类型擦除.Java的泛型是伪泛型.在编译期间,所有的泛型信息都会被擦除掉. Java中的泛型基本上都是在编译器这个层次来实现的.在生成的Java字节码中是不包含泛型中的类型 ...
- java泛型 之 入门(interface)
一:泛型简单介绍: (1)所谓泛型,就是变量类型的參数化. 泛型是JDK1.5中一个最重要的特征.通过引入泛型,我们将获得编译时类型的安全和执行时更小的抛出ClassCastException的可能. ...
- java 泛型的内部原理:类型擦除以及类型擦除带来的问题
一.Java泛型的实现方法:类型擦除前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首要前提是理解类型擦出(ty ...
- 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger
1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...
- 初识Java泛型以及桥接方法
泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...
随机推荐
- 【Android Studio快捷键】之导入对应包声明(import packages)
可能import 单个声明的快捷键大家都非常easy找到.Alt+Enter.可是假设我要一次性import文件里全部的声明.这个快捷键是什么呢,找啊找的,就是没找到,曾经在Eclipse是Ctrl+ ...
- ASP.MVC当URL跳转时候参数的安全性
一个页面跳转到另外一个页面直接将参数写在URL上面并不安全比如 http://XXXXXXXXXXX/meeting/shakeGroup?id=5381&uid=o0En_sj1J0bFgI ...
- MQTT 简介
MQTT 全称是 Message Queue Telemetry Transport,是一个轻量级的“发布/订阅”消息传输协议. 官网 http://mqtt.org/ 发布/订阅 MQTT 的基本概 ...
- java 拦截器
一.前言 这是一篇关于 java 拦截器的文章,是我的写 java web 所遇见的问题.当我们写好一个网站,必须要通过登陆页面才可以进入这个系统.那么我们就得写个 java 拦截器,如果是通过登录 ...
- 单点登录,session,jsonp(待更新)
单点登录理解: 单点登录系统设计: ajax跨域:
- restfull软件架构风格
概念:restfull是一种软件架构风格,实现该风格不需导jar包,但要使用@PathVariable注解:特点:没有参数,没有扩展名优势: 1.安全 2.简洁高效 3.容易被搜索引擎所收录 如何利用 ...
- 《计算机程序的构造和解释(第2版)》【PDF】下载
<计算机程序的构造和解释(第2版)>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382255 内容简介 <计算机程序的构造 ...
- 为什么在有的服务器上禅道、蝉知安装会报错? 之理解MySQL的SQL_MODE
最近用蝉知的CMS 建站比较多,感觉蛮顺手的,但在给客户安装的时候却会出现安装报错,其原因也很简单 查看了一下他们的install.sql文件中,有些时间字段的默认值是0000-00-00 00:00 ...
- Scrapy爬虫实例——校花网
学习爬虫有一段时间了,今天使用Scrapy框架将校花网的图片爬取到本地.Scrapy爬虫框架相对于使用requests库进行网页的爬取,拥有更高的性能. Scrapy官方定义:Scrapy是用于抓取网 ...
- iOS 实现UIImageView 的不停的旋转(更新:2017.7.26)
1.先创建一个UIImageView. - (void)createImageView { UIImageView *imageView = [[UIImageView alloc] initWith ...