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

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

泛 型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛 型类、泛型接口和泛型方法。

泛型思想早在C++语言的模板(Templates)中就开始生根发芽,在Java语言处于还没有出现泛型的版本时,只能通过Object是所有类型的父
类和类型强制转换两个特点的配合来实现类型泛化。例如在哈希表的存取中,JDK
1.5之前使用HashMap的get()方法,返回值就是一个Object对象,由于Java语言里面所有的类型都继承于
java.lang.Object,那Object转型为任何对象成都是有可能的。但是也因为有无限的可能性,就只有程序员和运行期的虚拟机才知道这个
Object到底是个什么类型的对象。在编译期间,编译器无法检查这个Object的强制转型是否成功,如果仅仅依赖程序员去保障这项操作的正确性,许多
ClassCastException的风险就会被转嫁到程序运行期之中。

泛型技术在C#和Java之中的使用方式看似相同,但实现上却有着根本性的分歧,C#里面泛型无论在程序源码中、编译后的IL中
(Intermediate
Language,中间语言,这时候泛型是一个占位符)或是运行期的CLR中都是切实存在的,List<int>与
List<String>就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现
的泛型被称为真实泛型。

Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原始类型(Raw
Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList<int>与
ArrayList<String>就是同一个类。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型
擦除,基于这种方法实现的泛型被称为伪泛型。(类型擦除在后面在学习)

使用泛型机制编写的程序代码要比那些杂乱的使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类来说尤其有用。

泛型程序设计(Generic Programming)意味着编写的代码可以被很多不同类型的对象所重用。

实例分析:

在JDK1.5之前,Java泛型程序设计是用继承来实现的。因为Object类是所用类的基类,所以只需要维持一个Object类型的引用即可。就比如ArrayList只维护一个Object引用的数组:

[java] view plaincopy

  1. public class ArrayList//JDK1.5之前的
  2. {
  3. public Object get(int i){......}
  4. public void add(Object o){......}
  5. ......
  6. private Object[] elementData;
  7. }

这样会有两个问题:

1、没有错误检查,可以向数组列表中添加类的对象

2、在取元素的时候,需要进行强制类型转换

这样,很容易发生错误,比如:

[java] view plaincopy

  1. /**jdk1.5之前的写法,容易出问题*/
  2. ArrayList arrayList1=new ArrayList();
  3. arrayList1.add(1);
  4. arrayList1.add(1L);
  5. arrayList1.add("asa");
  6. int i=(Integer) arrayList1.get(1);//因为不知道取出来的值的类型,类型转换的时候容易出错

这里的第一个元素是一个长整型,而你以为是整形,所以在强转的时候发生了错误。

所以。在JDK1.5之后,加入了泛型来解决类似的问题。例如在ArrayList中使用泛型:

[java] view plaincopy

  1. /** jdk1.5之后加入泛型*/
  2. ArrayList<String> arrayList2=new ArrayList<String>();  //限定数组列表中的类型
  3. //      arrayList2.add(1); //因为限定了类型,所以不能添加整形
  4. //      arrayList2.add(1L);//因为限定了类型,所以不能添加整长形
  5. arrayList2.add("asa");//只能添加字符串
  6. String str=arrayList2.get(0);//因为知道取出来的值的类型,所以不需要进行强制类型转换

还要明白的是,泛型特性是向前兼容的。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如
HashMap 和 ArrayList)的现有代码可以继续不加修改地在 JDK 1.5
中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全的好处。

在学习泛型之前,简单介绍下泛型的一些基本术语,以ArrayList<E>和ArrayList<Integer>做简要介绍:

整个成为ArrayList<E>泛型类型

ArrayList<E>中的 E称为类型变量或者类型参数

整个ArrayList<Integer> 称为参数化的类型

ArrayList<Integer>中的integer称为类型参数的实例或者实际类型参数

·ArrayList<Integer>中的<Integer>念为typeof  
Integer

ArrayList称为原始类型

二、泛型的使用

泛型的参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。下面看看具体是如何定义的。

1、泛型类的定义和使用

一个泛型类(generic class)就是具有一个或多个类型变量的类。定义一个泛型类十分简单,只需要在类名后面加上<>,再在里面加上类型参数:

[java] view plaincopy

  1. class Pair<T> {
  2. private T value;
  3. public Pair(T value) {
  4. this.value=value;
  5. }
  6. public T getValue() {
  7. return value;
  8. }
  9. public void setValue(T value) {
  10. this.value = value;
  11. }
  12. }

现在我们就可以使用这个泛型类了:

[java] view plaincopy

  1. public static void main(String[] args) throws ClassNotFoundException {
  2. Pair<String> pair=new Pair<String>("Hello");
  3. String str=pair.getValue();
  4. System.out.println(str);
  5. pair.setValue("World");
  6. str=pair.getValue();
  7. System.out.println(str);
  8. }
  9. 参数:

    [java] view plaincopy

    1. class Pair<T> {
    2. private T value;
    3. public Pair(T value) {
    4. this.value=value;
    5. }
    6. public T getValue() {
    7. return value;
    8. }
    9. public void setValue(T value) {
    10. this.value = value;
    11. }
    12. }

    现在我们就可以使用这个泛型类了:

    [java] view plaincopy

    1. public static void main(String[] args) throws ClassNotFoundException {
    2. Pair<String> pair=new Pair<String>("Hello");
    3. String str=pair.getValue();
    4. System.out.println(str);
    5. pair.setValue("World");
    6. str=pair.getValue();
    7. System.out.println(str);
    8. }

Pair类引入了一个类型变量T,用尖括号<>括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:

public class Pair<T,U>{......}

注意:类型变量使用大写形式,且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。(需要时还可以用临近的字母U和S)表示“任意类型”。

2、泛型接口的定义和使用

定义泛型接口和泛型类差不多,看下面简单的例子:

[java] view plaincopy

  1. interface Show<T,U>{
  2. void show(T t,U u);
  3. }
  4. class ShowTest implements Show<String,Date>{
  5. @Override
  6. public void show(String str,Date date) {
  7. System.out.println(str);
  8. System.out.println(date);
  9. }
  10. }

测试一下:

[java] view plaincopy

  1. public static void main(String[] args) throws ClassNotFoundException {
  2. ShowTest showTest=new ShowTest();
  3. showTest.show("Hello",new Date());
  4. }

3、泛型方法的定义和使用

泛型类在多个方法签名间实施类型约束。在 List<V> 中,类型参数 V 出现在 get()、add()、contains()
等方法的签名中。当创建一个 Map<K, V> 类型的变量时,您就在方法之间宣称一个类型约束。您传递给 add() 的值将与
get() 返回的值的类型相同。

类似地,之所以声明泛型方法,一般是因为您想要在该方法的多个参数之间宣称一个类型约束。

举个简单的例子:

[java] view plaincopy

  1. public static void main(String[] args) throws ClassNotFoundException {
  2. String str=get("Hello", "World");
  3. System.out.println(str);
  4. }
  5. public static <T, U> T get(T t, U u) {
  6. if (u != null)
  7. return t;
  8. else
  9. return null;
  10. }


三、泛型变量的类型限定

在上面,我们简单的学习了泛型类、泛型接口和泛型方法。我们都是直接使用<T>这样的形式来完成泛型类型的声明。

有的时候,类、接口或方法需要对类型变量加以约束。看下面的例子:

有这样一个简单的泛型方法:

[java] view plaincopy

  1. public static <T> T get(T t1,T t2) {
  2. if(t1.compareTo(t2)>=0);//编译错误
  3. return t1;
  4. }

因为,在编译之前,也就是我们还在定义这个泛型方法的时候,我们并不知道这个泛型类型T,到底是什么类型,所以,只能默认T为原始类型Object。所以它只能调用来自于Object的那几个方法,而不能调用compareTo方法。

可我的本意就是要比较t1和t2,怎么办呢?这个时候,就要使用类型限定,对类型变量T设置限定(bound)来做到这一点。

我们知道,所有实现Comparable接口的方法,都会有compareTo方法。所以,可以对<T>做如下限定:

[java] view plaincopy

  1. public static <T extends Comparable> T get(T t1,T t2) { //添加类型限定
  2. if(t1.compareTo(t2)>=0);
  3. return t1;
  4. }

类型限定在泛型类、泛型接口和泛型方法中都可以使用,不过要注意下面几点:

1、不管该限定是类还是接口,统一都使用关键字 extends

2、可以使用&符号给出多个限定,比如

[java] view plaincopy

  1. public static <T extends Comparable&Serializable> T get(T t1,T t2)

3、如果限定既有接口也有类,那么类必须只有一个,并且放在首位置

[java] view plaincopy

    1. public static <T extends Object&Comparable&Serializable> T get(T t1,T t2)

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

时间: 2024-07-30 15:50:29

java泛型(一)、泛型的基本介绍和使用的相关文章

Java中的泛型 (上) - 基本概念和原理

本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以深刻理解容器类.那,泛型到底是什么呢? 什么是泛型? 一个简单泛型类 我们通过一个简单的例子来说明泛型类的基本概念.实现原理和好处. 基本概念 我们直接来看代码: public class Pair<T> { T first; T second; public Pair(T first, T se

java中的泛型的使用与理解

什么是泛型? 泛型是程序设计语言的一种特性.允许程序员在强类型程序设计语言中编写 体验泛型代码时定义一些可变部份,那些部份在使用前必须作出指明.各种程序设计语言和其编译器.运行环境对泛型的支持均不一样.将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型.泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念. 定义: 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型

Java泛型:泛型的定义(类、接口、对象)、使用、继承

地址   http://blog.csdn.net/lirx_tech/article/details/51570138 1. 设计泛型的初衷: 1) 主要是为了解决Java容器无法记忆元素类型的问题: i. 由于Java设计之初并不知道会往容器中存放什么类型的元素,因此元素类型都设定为Object,这样就什么东西都能放了! ii. 但是这样设计有明显的缺点: a. 取出元素的时候必须进行强制类型转换(尽管集合在运行时里面元素的"运行时类型"不变,即元素的getClass返回的还是最初

java基础之泛型的继承

关于泛型的基本介绍和理解请参考以下几篇文章,或查询更多资料: 泛?型?与?泛?型?继?承 泛型(包括泛型抽象类的继承) 泛型的继承测试 本篇以简单的List<>方式来进行说明. ArrayList<Object>继承了List<Object>, ArrayList<String>没有继承List<Object> List<?>等价于List<? extends Object> 请参考以下代码: /** * author D

java中的泛型(一)

在java中我们定义接口其实定义的是这个类的功能,在很多时候我们并不关心这个类的类型而是这个类的能力.泛型的出现让我们的代码和代码所能操作的类型不在绑定在一起,不仅可以复用代码降低耦合还可以提高代码的可读性和安全性. 首先,我们现在看一段代码来介绍一下泛型的基本概念: public class Generic<T>{ T one; T two; public Generic(T one, T two){ this.one = one; this.two = two; } public T ge

Java基础:泛型详解

泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用.什么是泛型?为什么要使用泛型? 泛型,即“参数化类型”.一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参.那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参).泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型).也

夯实Java基础系列13:深入理解Java中的泛型

目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下Star.Fork.Watch三连哈,感谢你的

Java入门(二)——泛型

如果你写过前端,可能会经常写一下关于变量类型的判断,比如:typeof fn === 'function'之类的代码.因为JavaScript作为一门弱类型语言,类型的判断往往需要开发人员自己去检查. Java作为一门强类型语言,它的强就强在类型的约束比较严格,大多都是在编译器(IDEA.eclipse...)里就做了检查,也就是说你刚敲完一个字符,如果有类型错误,下一秒就能提示你哪错了.这也避免了运行时的错误,让你的代码更加的严谨.下面就来了解一下为类型约束做出卓越贡献的人物--泛型. Jav

泛型及java中的泛型

当作笔记整理的~~~ 首先,引出堆对象这个概念. 什么是堆对象,就是程序在运行过程中可以随时建立或者删除的对象,可以用new运算符(或malloc函数)或者delete运算符(或free函数).泛型可以看作是一类堆对象. 泛型是程序设计语言的一种特性.允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明. 各种程序设计语言和其编译器.运行环境对泛型的支持均不一样.将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型. 泛型的定义主要有两种:1.在程序编

Java 中的泛型详解-Java编程思想

Java中的泛型参考了C++的模板,Java的界限是Java泛型的局限. 2.简单泛型 促成泛型出现最引人注目的一个原因就是为了创造容器类. 首先看一个只能持有单个对象的类,这个类可以明确指定其持有的对象的类型 class Holder1 { private Circle a; public Holder1(Circle a) { this.a = a; } Circle get() { return a; } } 上面的类的可重用性不怎么样,无法持有其他类型的任何对象,下面通过持有Object