远在 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 作为泛型的标志。

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());
}

泛型集合

除了使用 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);
}

总结

我们通过一个简单的例子理解了泛型诞生的缘由,之后又通过一个常见的面试题明白了泛型只存在于编译期间的本质,最后介绍了常见的泛型使用场景。

下篇文章,我们将介绍泛型中通配符的使用。

Java泛型(一):入门、原理、使用的更多相关文章

  1. 大白话说Java泛型:入门、使用、原理

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型:入门.使用.原理> 远在 JDK 1.4 版本的时候,那时候是没有泛型的概念的.当时 Java 程序员们写集合类的代码都 ...

  2. java泛型的实现原理

    java泛型的实现原理是类型擦除.Java的泛型是伪泛型.在编译期间,所有的泛型信息都会被擦除掉.   Java中的泛型基本上都是在编译器这个层次来实现的.在生成的Java字节码中是不包含泛型中的类型 ...

  3. java泛型 之 入门(interface)

    一:泛型简单介绍: (1)所谓泛型,就是变量类型的參数化. 泛型是JDK1.5中一个最重要的特征.通过引入泛型,我们将获得编译时类型的安全和执行时更小的抛出ClassCastException的可能. ...

  4. java 泛型的内部原理:类型擦除以及类型擦除带来的问题

    一.Java泛型的实现方法:类型擦除前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首要前提是理解类型擦出(ty ...

  5. 初识Java泛型以及桥接方法

    泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...

  6. Java——泛型

    前言 一般的类和方法,使用的都是具体的类型:基本类型或者自定义的类.如果我们要编写出适用于多种类型的通用代码,那么肯定就不能使用具体的类型.前面我们介绍过多态,多态算是一种泛化机制,但是也会拘泥于继承 ...

  7. Java泛型深入理解(转载)

    原文地址  http://blog.csdn.net/sunxianghuang/article/details/51982979 泛型之前 在面向对象编程语言中,多态算是一种泛化机制.例如,你可以将 ...

  8. JAVA泛型——基本使用

    Java1.5版本推出了泛型,虽然这层语法糖给开发人员带来了代码复用性方面的提升,但是这不过是编译器所做的一层语法糖,在真正生成的字节码中,这类信息却被擦除了.笔者发现很多几年开发经验的程序员,依然不 ...

  9. Java泛型的基本使用

    Java1.5版本推出了泛型,虽然这层语法糖给开发人员带来了代码复用性方面的提升,但是这不过是编译器所做的一层语法糖,在真正生成的字节码中,这类信息却被擦除了.笔者发现很多几年开发经验的程序员,依然不 ...

  10. java泛型梳理

    java泛型梳理 概述 泛型,即参数化类型,是在JDK1.5之后才开始引入的. 所谓参数化类型是指所操作的数据类型在定义时被定义为一个参数,然后在使用时传入具体的类型. 这种参数类型可以用在类,接口, ...

随机推荐

  1. 用BFS解决迷宫问题

    在一个n*n的矩阵里走,从原点(0,0)開始走到终点(n-1,n-1),仅仅能上下左右4个方向走.仅仅能在给定的矩阵里走,求最短步数. n*n是01矩阵,0代表该格子没有障碍.为1表示有障碍物. in ...

  2. CodeForces 651C

    Description Watchmen are in a danger and Doctor Manhattan together with his friend Daniel Dreiberg s ...

  3. sublime中BracketHighlighter 插件使用 (转)

    sublime中BracketHighlighter 插件使用 1.打开package Control,选择install Package 2.输入BracketHighlighter,回车 3.这样 ...

  4. SpringBoot中拦截器和过滤器的使用

    一.拦截器 三种方式 继承WebMvcConfigurerAdapter   spring5.0 以弃用,不推荐 实现WebMvcConfigurer  推荐 继承WebMvcConfiguratio ...

  5. openssl https证书

    今天摸索了下 HTTPS 的证书生成,以及它在 Nginx 上的部署.由于博客托管在 github 上,没办法部署证书,先记录下,后续有需要方便快捷操作.本文的阐述不一定完善,但是可以让一个初学者了解 ...

  6. Python金融量化

    Python股票数据分析 最近在学习基于python的股票数据分析,其中主要用到了tushare和seaborn.tushare是一款财经类数据接口包,国内的股票数据还是比较全的 官网地址:http: ...

  7. POJ 2406 KMP next数组的应用

    题意:让你找最小重复串的个数 加深KMP中对next数组的理解 #include <cstdio> #include <cstring> using namespace std ...

  8. P1629 邮递员送信(未完成)

    题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间.这个邮递员每 ...

  9. WordPress的wordfence插件的设置方法

  10. 【原创】IBM Websphere 报错:JSPG0120E: 为 pageEncoding 属性和匹配 URI 模式的配置元素指定不同的值是非法的。

    websphere中间件,在打开一个jsp页面时报: IBM Websphere 报错:JSPG0120E: 为 pageEncoding 属性和匹配 URI 模式的配置元素指定不同的值是非法的. . ...