远在 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. 消息推送之百度云推送Android集成与用法

    这两天因为项目须要.研究了一下百度云推送,本来这事没什么多大工作量的,但注冊百度开发人员账户创建应用令我蛋疼菊紧了好一阵,这些东西做了对技术没啥提升,不做又不行,必经之路. 好在我耗费了N多个毫毫秒秒 ...

  2. 一张游览PHP内核迷宫的藏宝图

    PHP内核就像一个迷宫,假设没有一个纵览全局的图,仅仅是面对当中的一个点,就会像进了迷宫一样,走着走着就走到了死胡同.在这个迷宫里转悠了非常久之后,近期得到了一张PHP藏宝图.然后看着这张图去游览PH ...

  3. B1734 [Usaco2005 feb]Aggressive cows 愤怒的牛 二分答案

    水题,20分钟AC,最大值最小,一看就是二分答案... 代码: Description Farmer John has built a <= N <= ,) stalls. The sta ...

  4. Arduino-OLED-四度显示

    double Fahrenheit(double celsius) { ; } //摄氏温度度转化为华氏温度 double Kelvin(double celsius) { return celsiu ...

  5. springmvc-servlet.xml 第二种选择

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  6. docker应用栈实践-nginx处理静态文件

    在我的djangoweb应用在docker搭建好之后,发现一些css静态文件返回没有content-type属性,导致浏览器log一堆警告,强迫症的我受不了这一情况 目前的应用栈结构图: 一共四个容器 ...

  7. (转)Java进阶java int与Integer的区别

    Java进阶java int与Integer的区别 前言 int与Integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而Integer是对象,用一个引 ...

  8. 自定义typecho后台路径

    如何自定义后台路径 Typecho 安装好后,默认的后台路径是 domain.com/admin/,为了提高安全性,我们允许以 domain.com/xxxx/ 的方式访问,其中 xxxx 是你自定义 ...

  9. [OpenWrt]安装mjpg-streamer

    安装mjpg-streamer 远程监控基本上是wifi小车的一个必备功能了.摄像头我用的是奥尼百脑通 D881,这个要100左右. 确认安装了以下软件: kmod-usb2 kmod-video-u ...

  10. Mac使用ssh登录远程linux系统查看jetty日志及同时使用github工具

    转载请注明出处:http://www.houxiurong.com/?post=27 Mac默认是安装了ssh工具软件的. 先用mac的 终端工具生成 id_rsa 和id_rsa.pub 秘钥,生成 ...