来自:

代码大湿

代码大湿

写在前面:

只要认真看过,基本能很熟悉泛型的特性。泛型是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. Ossec常用命令

    启动并查看httpd服务 systemctl start httpd systemctl status httpd.service 启动并查看mysql服务 systemctl start maria ...

  2. 4、处理方法中获取请求参数、请求头、Cookie及原生的servlet API等

    1.请求参数和请求头 使用@RequestParam绑定请求参数,在处理方法的入参处使用该注解可以把请求参数传递给请求方法 —— value :参数名 —— required : 是否必须,默认为tr ...

  3. hadoop拾遗(三)---- 多种输入

    虽然一个MapReduce作业的输入可能包含多个输入文件(由文件glob.过滤器和路径组成),但所有文件都由同一个InputFormat和同一个Mapper来解释.然而,数据格式往往会随时间而演变,所 ...

  4. 《Linux/Unix系统编程手册》读书笔记2

    <Linux/Unix系统编程手册>读书笔记 目录 第5章: 主要介绍了文件I/O更深入的一些内容. 原子操作,将一个系统调用所要完成的所有动作作为一个不可中断的操作,一次性执行:这样可以 ...

  5. WebService只能在本地使用,无法通过网络访问的解决办法

    问题描述:WebService只能在本地使用,无法通过网络访问. 解决方案:在web.config的<system.web></system.web>中间加入如下配置节内容: ...

  6. asp.net清除页面缓存防止同时登录

    //清除页面缓存,防止页面回退重复提交数据 在页面里做以下设置就可以使页面的缓存失效,每次都需要获取新页面. Response.Cache.SetCacheability(System.Web.Htt ...

  7. 50个python库

    50个很棒的Python模块,包含几乎所有的需要:比如Databases,GUIs,Images, Sound, OS interaction, Web,以及其他.推荐收藏. Graphical in ...

  8. UVA 10735 Euler Circuit 混合图的欧拉回路(最大流,fluery算法)

    题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径. 分析:欧拉回路的定义是,从某个点出发,每条边经过一次之后恰好回到出发点. 无向边同样只能走一次,只是不限制 ...

  9. VirtualBox的工作原理&参考网上文章

    事先申明,我这里有好多东西都是看网上的,文末给出参考博客链接. 1.在设置里面为什么要选择桥接网络?baidu之后,了解到是虚拟机工作原理的不同,也就是说有好几种工作模式. bridged(桥接模式) ...

  10. Delphi DecodeDate和EncodeDate 拆分和聚合时间函数的用法

    SysUtilsprocedure DecodeData(Date: TDateTime; var Year, Month, Day: Word);DecodeDate打断TdateTime成为年月日 ...