来自:

代码大湿

代码大湿

写在前面:

只要认真看过,基本能很熟悉泛型的特性。泛型是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搭建之二:客户端安装

    上一篇文章中已经将OSSEC服务端的安装以及客户端的Key导出操作做了解说,接下来在另一台虚拟机中安装客户端,与安装服务端类似同样需要安装ossec,步骤如下. 一.下载ossec-hids-2.8. ...

  2. (转)MyEclipse +Servlet

    来自:http://www.cnblogs.com/sunada2005/p/3520788.html 在Win7系统下运行自己的第一个Servlet程序,因为有时候配置不当或系统原因可能会运行不成功 ...

  3. Map.putAll方法——追加另一个Map对象到当前Map集合(转)

    该方法用来追加另一个Map对象到当前Map集合对象,它会把另一个Map集合对象中的所有内容添加到当前Map集合对象. 语法  putAll(Map<? extends K,? extends V ...

  4. Eclipse常见设置及快捷键使用总结(更新中)

    Eclipse中常见设置: 1.Eclipse在保存时设置自动去掉多余的import和格式化代码 路径: window --> preferences --> java --> Ed ...

  5. 高难度(3)RenderScript

    RenderScript RenderScript is a framework for running computationally intensive tasks at high perform ...

  6. Windows Tomcat 安装

    JDK的安装可以参考 http://www.cnblogs.com/emanlee/p/3702535.html ,然后安装apache-tomcat step1:http://tomcat.apac ...

  7. shape的属性(二)

    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="r ...

  8. Azure SQL 数据库:新服务级别问答

    ShawnBice   2014 年 5 月 1 日上午 11:10 本月初,我们庆祝了SQL Server 2014 的推出,并宣布正式发布分析平台系统,同时分享了智能系统服务预览版.Quentin ...

  9. Darwin Streaming Server 6.0.3安装、订制、插件或模块

    How to setup Darwin Streaming Server 6.0.3 on 32 or 64 bit Linux platforms, add custom functionality ...

  10. 【Struts】服务器文件的上传和下载

    Java中获得文件的文件后缀 import java.io.*; public class FileTest{ public static void main(String args[]){ File ...