来自:

代码大湿

代码大湿

写在前面:

只要认真看过,基本能很熟悉泛型的特性。泛型是JDK1.5之后出现的,比如JDK1.5之前的ArrayList,会出现2个问题

1:向ArrayList当中添加对象,添加String和Date都可以,但我们的本意是添加String,编译器不会检查错误,会导致不可预知的错误。

2:get()方法得到一个元素的时候要进行强制类型转换。

所以泛型的引入很好的解决了这2个问题。


1,泛型类

一个泛型类如下;


class Pair<T,E>{
private T first;
private E second;
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public E getSecond() {
return second;
}
public void setSecond(E second) {
this.second = second;
} }

尖括号中的T,E称为类型变量。


  1. 泛型方法

一个泛型方法的签名:

public static T getV(T t)

类型变量在方法修饰符的后面,返回值的前面。


3.类型擦除

JVM中是不存在泛型这一说法的,即编译器在编译的时候,将类型变量擦除掉了,换成了Bounding Type。上面的Pair类在编译后,Pair变成这样了:

class Pair{
private Object first;
private Object second;
public Object getFirst() {
return first;
}
public void setFirst(Object first) {
this.first = first;
}
public Object getSecond() {
return second;
}
public void setSecond(Object second) {
this.second = second;
} }

将类型变量替代成了Object。更多的类型替代请继续往下阅读;

类型擦除带来的问题:

定义一个Pair的子类

class extendsPair extends Pair<Date,Date>{
public void setSecond(Date d){
super.setSecond(d);
System.out.println("我是字类的方法");
}
}

Pair pair=new extendsPair();
pair.setSecond(new Date());

执行结果是:

我是父类的方法

我是字类的方法

为什么会是这样呢?

因为子类自己定义了一个public void setSecond(Date d)

但是从父类继承了一个方法是public void setSecond(Object d),这是2个不同的方法。当用父类的引用指向子类的实例,然后调用词方法,对于编译器只会寻找父类的那个方法即public void setSecond(Object d)。而程序员的意图是调用子类的方法public void setSecond(Date d),所以此种情况,编译器会为我们生成一个桥方法

public void setSecond(Object d){
setSecond((Date)d);
}

所以正如结果中那样,先调用父类的setSecond方法,然后在此方法中调用子类的setSecond方法。


4.类型限定符

1.类型限定符,用关键字extends表示子类型限定

对于下面方法

public People getName(Pair<People,People> p){
return p.getFirst();
}

这个方法,我们无法传入Pair<Student,Studnet>类型的参数,此时我们就要用到子类型限定,将此方法改为:

public People getName(Pair<? extends People,? extends People> p){
return p.getFirst();
}

用关键字super表示超类型限定,<?>表示无类型限定。比如一个方法getPairs()我们要返回Pair<>[]。其中的元素有Pair<Student>,还有Pair<Scientist>Student和Scientist不存在继承关系。这是就只能用<?>

2:类型限定注意事项:

看下面代码

public People getName(Pair<? extends People,? extends People> p){
Student student=new Student();
p.setFirst(student);
return p.getFirst();
}

p.setFirst(student)会报错,因为Pair<? extends People,? extends People>的setFirst方法是

public void setFirst(<? extends People first) {
this.first = first;
}

形参是People的某子类,但是编译器不能确定Student是不是这个子类的子类。但是对于get方法,总能将返回类型转型成People类。相应的使用超类型限定,get()方法会报错。


5:泛型的注意事项:

1:不能在泛型类的静态上下文中定义含有类型变量的静态成员,如:
class Pair<T,E>{
private static T name;
....

只是对于泛型类来说,如上面普通类中可以存在静态方法。这个原因很简单,比如Pair<String,String>和Pair<Date,Date>这2个对象,那么这两个对象要共享name,那么变量name是什么类型呢?存在冲突。


2:泛型类不能继承异常类,也不能被抛出

因为泛型类不能继承Throwable,但是类型变量可以被抛出,如:

public static <T extends Throwable> T get(T t) throws T{
return t;
}

3:泛型数组是不合法的

不能创建这样的数组:

Pair<String,String>[] pairs=new Pair<String,String>[10];

因为实际上paris是Pair[]类型的,所以我们添加Date类型的元素,编译器是不会发现的。这会产生难以定位的错误。但是我们可以用下面的方式来定义泛型数组。

Pair<String,String>[] pairs=(Pair<String, String>[])(new Pair[10]);

4:不能实例化类型变量

不能出现 new T(),new T[]这样的src。因为经过类型擦除后,T均变为BoundingType。这样的操作没有意义。

5:类型变量不能是raw类型。

关注更多好文:

代码大湿

代码大湿

Java——泛型(最易懂的方式讲解泛型)的更多相关文章

  1. java泛型操作复习,以及讲解在android中使用的场景

    android使用泛型的地方很多,比如集成自BaseAdapter实现封装的Adapter,对常用操作进行封装,但是需要对传进来的数据进行处理,此时就使用到泛型,示例如下: public abstra ...

  2. Java中泛型的详细解析,深入分析泛型的使用方式

    泛型的基本概念 泛型: 参数化类型 参数: 定义方法时有形参 调用方法时传递实参 参数化类型: 将类型由原来的具体的类型参数化,类似方法中的变量参数 类型定义成参数形式, 可以称为类型形参 在使用或者 ...

  3. java 编程基础 反射方式获取泛型的类型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()

    引言 自从JDK5以后,Java Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是 Class 如果 Class 对应的类暂时未知,则使 C ...

  4. JAVA之旅(二十一)——泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符

    JAVA之旅(二十一)--泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符 不知不觉JAVA之旅已经写到21篇了,不得不感叹当初自己坚持要重学一遍JAVA的信念,中途也算 ...

  5. java 泛型详解(普通泛型、 通配符、 泛型接口,泛型数组,泛型方法,泛型嵌套)

    JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型.  1.Java泛型  其实Java ...

  6. java基础(7)集合与泛型

    第一部分:Collection集合 1 collection集合概述 集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection和双列集合java.util.Map. C ...

  7. java为什么要用类型擦除实现泛型?--c++,java,c# 的泛型是如何实现的

    所以总结一下c++,java,c#的泛型.c++的泛型在编译时完全展开,类型精度高,共享代码差.java的泛型使用类型擦出,仅在编译时做类型检查,在运行时擦出,共享代码好,但是类型精度不行.c#的泛型 ...

  8. java 泛型实例详解(普通泛型、 通配符、 泛型接口)

    java 泛型详解(普通泛型. 通配符. 泛型接口) 2013-02-04 19:49:49| 分类: JAVA | 标签:java |举报|字号 订阅 下载LOFTER客户端 JDK1.5 令我们期 ...

  9. java语言进阶(二)_Collection_泛型

    主要内容 Collection集合 迭代器 增强for 泛型 第一章 Collection集合 1.1 集合概述 在前面基础班我们已经学习过并使用过集合ArrayList ,那么集合到底是什么呢? 集 ...

随机推荐

  1. 机器学习 —— 概率图模型(学习:CRF与MRF)

    在概率图模型中,有一类很重要的模型称为条件随机场.这种模型广泛的应用于标签—样本(特征)对应问题.与MRF不同,CRF计算的是“条件概率”.故其表达式与MRF在分母上是不一样的. 如图所示,CRF只对 ...

  2. qtp与selenium2的区别

    QTP:  我觉得qtp适合的人: 对编程不是很熟悉的 厌烦了手动的功能测试,想快速进入自动化行业的 公司想快速自动化项目,并且对价格或者对盗版无所谓的 vbs脚本语言易于上手,可以培训你对代码的兴趣 ...

  3. 【原创】MySql 数据库导入导出(备份)

    啥不说了,两周前刚刚做过mysql导入导出的结果现在又忘了.. 更可悲的是竟然同样的三篇blog,现在看起来还是如当初一样费劲,里面的内容..所以自己写个记录一下 环境:*nix 权限:有相关表的写读 ...

  4. Struts知识问答 分类: 面试 2015-07-10 22:01 4人阅读 评论(0) 收藏

    1. 简述Struts框架的初始化流程. 答案: 对于采用Struts框架的Web应用,在Web应用启动时就会加载并初始化控制器ActionServlet ActionServlet从struts-c ...

  5. Android开发之定义app在手机的安装位置

    定义app在手机的安装位置,可以通过在清单文件中添加属性 android:installLocation="" 该属性有三个值:auto(自动),preferExternal(外部 ...

  6. 如何在Ubuntu上安装最新版本的Node.js

    apt-get update apt-get install -y python-software-properties software-properties-common add-apt-repo ...

  7. 深入理解Java虚拟机

    1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://nibnait.com/6f8dd084-about-Java-Virtual-Machine/ 2. JVM性能调优 ...

  8. 面试题_66_to_75_Java IO 和 NIO 的面试题

    IO 是 Java 面试中一个非常重要的点.你应该很好掌握 Java IO,NIO,NIO2 以及与操作系统,磁盘 IO 相关的基础知识.下面是 Java IO 中经常问的问题. 66)在我 Java ...

  9. inline-block在ie6中的经典bug

    众所周知,给元素设置 inline-block ,可以让ie下的元素出发layout:1. 但是,当给元素设置 inline-block 后,在另外一个class 样式(非设置inline-block ...

  10. UVa 10288 (期望) Coupons

    题意: 每张彩票上印有一张图案,要集齐n个不同的图案才能获奖.输入n,求要获奖购买彩票张数的期望(假设获得每个图案的概率相同). 分析: 假设现在已经有k种图案,令s = k/n,得到一个新图案需要t ...