为什么要使用泛型?

  在Java中增加泛型之前,泛型程序设计是用继承来实现的,例如ArrayList,只维护Object引用的数组:

 public class ArrayList{
private Object[] elementData; public Object get(int i){...}
public void add(Object o){...}
}

  在这里有一个问题,就是每次使用的时候,都必须进行一次强制类型转换

 ArrayList list = new ArrayList();
...
String name = (String)list.get(0);

  可以发现还没有错误检查,如果是其他类型会检测不到,当添加的时候,可以是任何类的对象

  每次都转换一次很麻烦,用什么解决呢,类型参数!

ArrayList<String> list = new ArrayList<String>();
//在JAVASE 7以后的版本中,可以直接使用一下方法来声明了
ArrayList<String> list = new ArrayList<>();

简单泛型类

public class Pair<T>{
private T first;
private T second; public Pair(){first = null; second = null;}
public Pair(T first, T second){this.first = first; this.second = second} //get set
...
}

  现在,我们可以像现在这样定义了

Pair<String> test1 = new Pair<>();
Pair<Integer> test2 = new Pair<>();

泛型方法

public class test{
public static <T> T first(T...a){
//...
}
}

  但是需要注意的是,下面这几种,并不是泛型方法,不要混淆

 public class test<T>{
private T t; //这个不是,只是一个普通的成员的方法
public test(T t){
this.t = t;
}
//这个也不是,只是泛型类是形参
public void add(test<T> object){...}
}

通配符

  通配符是什么,为什么要使用通配符?试想一下,如果我们在一个方法中要传入的参数可能是一个类的子类,这该怎么办呢?

 public void test(Persion<Number> p){...}

 x.test(Intger); //错误
x.test(Double);

  不妨自己在编译器上试一试,这里是识别不了的,泛型中这两个没有关联关系,so,可以使用通配符

 public void test(List<? extends T>){...}

  这样子类和父类就联系起来了,?是类型实参,不是类型形参

  如果像上面这样使用,我们可以add元素进去吗?反着思考一下,一个父类派生出很多个子类,我们在实例化的时候,很可能new出来的不是一个东西,这可不行呀,要存就得存一种,哪有Int,float都存进去的道理,如果还不明白可以看看代码

 List<? extends Person> = new ArrayList<Student>();
List<? extends Person> = new ArrayList<Teacher>();

  这样的话我们只能Get,并不能add,想要add那我们现在可以这样

 public void test(List<? superT>){...}

  如此之后,只能add,不能get,又是为什么呢,还是反着思考,既然我们能够add元素进去,但是每一个元素的实际类型不相同

 List<? super Student> = new ArrayList<Student>();
List<? super Student> = new ArrayList<Person>();

  当我们想get到Student的时候,可能是一个Person类型,这个Person可能是个Teacher

说了这么多,终于到了类型擦除

类型擦除

  在JVM中不存在什么泛型,只有基本的类,当我们定义了一个泛型类的时候

 public class Node<T> {
private T data;
private Node<T> next; public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
} // ...
}

  在做完类型检查后,会变成这样

 public class Node{
private Object data;
private Node next; public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
// ...
}

  惊不惊喜意不意外!如果我们不想变成Object怎么办,可以自己设置

 public class Node<T extneds Comparable<T>> {
private T data;
private Node<T> next; public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
// ...
} public class Node {
private Comparable data;
private Node next; public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
// ...
}

  看似其实就是这样嘛!但是这样的话会引起一些问题

  1、不允许创建泛型数组

    因为数组中的元素必须统一类型,如若使用了泛型数组,类型都被擦除成Object后,我们不会知道插入的数据是否都是同一个类型的,出错很难排查,可以运行一下下面的代码

Class c1 = new ArrayList<Integer>().getClass();
Class c2 = new ArrayList<Double>().getClass();
System.out.println(c1 == c2);

    最终会得到true的结果,这里可以联想到,泛型无法使用instanceof

  2、桥方法的合成用来保持多态  

 public class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}

    类型擦除后

 public class Node {
public Object data;
public Node(Object data) { this.data = data; }
public void setData(Object data) {
System.out.println("Node.setData");
this.data = data;
}
}
public class MyNode extends Node {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
 MyNode mn = new MyNode(5);
Node n = mn;
n.setData("Hello");

    实际上不是这样的,这会抛出ClassCastExeption,在哪里?

 class MyNode extends Node {
// 桥方法
public void setData(Object data) {
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
// ...
}

    setData方法里面有一个强制类型转换,String没办法转换成Integer,记住一句话,桥方法被合成用来保持多态

  3、反射和泛型

    反射允许你在运行时分析任意的对象,如果对象是泛型类的实例,关于泛型类型参数则得不到太多信息,因为它们会被擦除

 

  

Java泛型的基本介绍与使用的更多相关文章

  1. java泛型探索——介绍篇

    1. 泛型出现前后代码对比 先来看看泛型出现前,代码是这么写的: List words = new ArrayList(); words.add("Hello "); words. ...

  2. java泛型(一)、泛型的基本介绍和使用

    现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 泛 型的定义:泛型是JDK 1.5的一 ...

  3. Java泛型一:基本介绍和使用

    原文地址http://blog.csdn.net/lonelyroamer/article/details/7864531 现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就 ...

  4. java泛型 7 泛型的基本介绍和使用

    现在开始深入学习Java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 一.泛型的基本概念 泛型的定义:泛型是 ...

  5. Java泛型介绍!!!

    Java总结篇系列:Java泛型  转自:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下 ...

  6. Java 泛型 介绍

    为什么需要泛型? public class GenericTest { public static void main(String[] args) { List list = new ArrayLi ...

  7. java泛型介绍

    一.泛型初衷 Java集合不会知道我们需要用它来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要就具有很好的通用性.但这样做也带来两个问题: –集合对元素类型没有任何限制,这样可能引 ...

  8. Java泛型的历史

    为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...

  9. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

随机推荐

  1. [USACO15OPEN]haybales Trappe…

    嘟嘟嘟 刚开始我以为如果这头牛撞开一个干草堆的话,获得的冲刺距离只有新增的部分,但实际上是加上原来的部分的. 暴力很好写,区间排完序后一次判断每一个区间是否能逃脱,复杂度O(n2). 优化想起来也不难 ...

  2. lucene&solr学习——分词器

    下图是语汇单元的生成过程: 从一个Reader字符流开始,创建基于Reader的Tokenizer分词器,经过三个TokenFilter生成语汇单元Tokens. 要看分词器的分析效果,只需要看Tok ...

  3. LeetCode2.两数相加 JavaScript

    给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -& ...

  4. js动画之requestAnimationFrame

    1.setTimeout和setInterval 在讲setTimeout和setInterval之前,先讲一下异步执行的运行机制.(同步执行也是如此,因为它可以被视为没有异步任务的异步执行.) (1 ...

  5. SpringBoot非官方教程 | 第十四篇:在springboot中用redis实现消息队列

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springboot/2017/07/11/springboot14-redis-mq/ 本文出自方志朋的博客 这 ...

  6. eclipse内存溢出解决

    1 查看内存: workspace/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs,在里面加上SH ...

  7. ABAP术语-Business Object Type

    Business Object Type 原文:http://www.cnblogs.com/qiangsheng/archive/2008/01/10/1033480.html Generic de ...

  8. NFS网络文件系统详解

    第1章 NFS基本概述 1.1 什么是nfs NFS是Network File System的缩写及网络文件系统. 主要功能是通过局域网络让不同的主机系统之间可以共享文件或目录. NFS系统和Wind ...

  9. JAVAOOP多线程

    进程每个独立运行的任务对应一个进程,每个进程可以产生多个线程 特点:1,进程是系统运行程序的基本单位 2,每一个进程都有自己独立的一块内存空间,一组系统资源 3,每一个进程的内部数据和状态都是完全独立 ...

  10. python pandas库——pivot使用心得

    python pandas库——pivot使用心得 2017年12月14日 17:07:06 阅读数:364 最近在做基于python的数据分析工作,引用第三方数据分析库——pandas(versio ...