Java:泛型基础

泛型

引入泛型

传统编写的限制:

  在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型。如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多!

解决这种限制的三种方法:

1.多态:将方法的参数类型设为基类,那么该方法就可以接收从这个基类导出的任何类作为参数。

class Primary{} //定义基类

class Test()
{
    public void f(Primary p)
    {...}
}

2.方法的参数使用接口:任何实现了该接口的类都可以满足该方法。

interface Primary{} //定义接口

class Test()
{
    public void f(Primary p) //实现了该接口的所有类都可以作为参数
    {...}
}

3.使用泛型。

泛型的说明:

  泛型实现了参数化类型的概念,使代码可以应用于某种不具体的类,而不是具体的一个类或者接口。
简单说就是使代码可以适用于广泛的类型。

泛型表达式的翻译(最后看):

  1.当程序调用泛型方法时,如果擦除了泛型返回类型,编译器插入类型转换。

 Pair<Employee> buddies = ...
 Employee buddy = buddies.getFirst();

    ? 擦除getFirst的返回类型后将返回Object类型,编译器自动插入Employee的强制类型转换。

    ? 也就是说,编译其把这个方法调用翻译为两条虚拟指令:
      ◇ 对原始方法Pair.getFirest的调用。
      ◇ 将返回的Object类型,强制转换为Employee类型。
  2.当存取一个泛型域时也要插入强制类型转换。
    假设 Pair 类的first 域 和 second 域都是 公有的(这不是种好的编程风格, 但在java语法中,这是合法的)。 
    表达式: Employee buddy = buddies.first; 也会在结果字节码中插入强制类型转换;  

简单泛型:

使用泛型预定义参数类型:

  

说明:基本数据类型无法作为类型参数

在使用时具体化类型参数

  

小结

  泛型类最主要的使用是应用在集合中,代码封装了一个ArrayList,这样我们在编写类的时候,就不会受限于具体的类,因为具体使用的类型是在初始化对象的时候才指定的。
我们为什么要这样呢?如果这个实现类不用泛型,如果处理多种类型数据的时候,就要编写多个实现类,来针对处理。

元组:

简单元组实例:

  

通过继承机制来实现长度更长的元组

  

泛型接口

说明:

  泛型也可以应用于接口,类和接口的类型参数应该保持一致,都是T或者其他。

  泛型接口最常用的一个用法是实现Iterable接口,实现迭代方法!

实例:

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Random;

public class RandomList<T> implements Iterable<T> {
    private ArrayList<T> storage = new ArrayList<T>();
    private Random rand = new Random(new Date().getTime());

    public void add(T item) {
        storage.add(item);
    }

    public T select() {
        return storage.get(rand.nextInt(storage.size()));
    }

    /* 实现Iterable接口 */
    public Iterator<T> iterator() {
        return storage.iterator();
    }
}

泛型方法

说明:

  是否拥有泛型方法和其是否是泛型类并无直接关系,也就是说泛型方法可以独立于类而产生变化!

实例:

  

类型说明:

显式的类型说明:

  在泛型方法中,可以显式地指明参数类型,不过很少这样使用!
  

可变参数列表:

   泛型方法和可变参数列表可以很好的共存
  

类型变量的限定

说明:

  1.添加限定来让类型变量具有特定功能。

  

  2.可以有多个限定(接口和类都是可以的),但要注意顺序。

  

为什么关键字不用implements呢?毕竟Comparable是一个接口:

  <T extends BoundingType>

  这句代码表示T应该是绑定类型(BoundingType)的子类型。T和绑定类型可以是类,也可以是接口。
  若T是接口,那么方法调用时传进来的是T的实现类也是可以的。extends更接近于子类的概念,所以选用extends。

神秘的擦除

问题:

  
  我们很可能会认为c1!=c2,结果为false,因为c1不能装入Integer,c2也不能装入String。

说明:

  在泛型代码内部,无法获取任何有关泛型参数类型的信息,也就是你无法获得那个具体的类型是什么,你仅仅可以获知的诸如类型参数标识符和泛型边界这类的信息

Java泛型是使用擦除来实现的:

  这意味者当你在使用泛型的时候,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此问题中c1==c2,为true。这两种形式都被擦除成为它们的“原生”类型,即List.

原始类型与擦除:

      虚拟机没有泛型类型对象,所有对象都属于普通类。无论何时定义了一个泛型类型,都自动提供了一个相应的原始类型,将泛型类型还原成原始类型的过程,称为擦除
  原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定类型的变量默认用Object)。

  

  左图的原始类型变为:public class Test<Object>,所有T都变成Object 右图变为:public class Test<Comparable>,所有T都变成Object。   

说明:

  这样就不难理解,为什么,加上限定边界后,我们就可以调用obj.compareTo()了,因为擦除类型变量后,T都被还原成Comparable,效果就是任何实现了Comparable的子类都可以调用Test对象的compare()方法。如果泛型是在Java 1.0就出现的,那么这个特性将不会使用擦除来实现——它将使用具体化,使类型参数保持为第一类的实体,因此你就能够在类型参数上执行基于类型的语言操作和反射操作。

再一次强调:

Test<Cat> test = new Test<Cat>(); 

  看起来class Test应该知道现在工作于Cat之上,而泛型语法也在强烈暗示,在整个类中的各个地方,类型T都在被替换。但是事实并非如此,无论何时,当你在编写这个类的代码时,必须时刻提醒自己:它仅仅只是一个Object
擦除的补偿。

再谈边界

  1.边界使得你可以在用于泛型的类型参数上设置限制条件。尽管这使得你可以强制规定泛型可以应用的类型,但是其潜在的一个更重要的效果是你可以按照自己的边界类型来调用方法。
  2.因为擦除移除了类型信息,所以,可以用无界泛型参数调用的方法只能是那些可以用Object调用的方法,那么你就可以用这些类型字节来调用方法。

通配符

  说明:

    1.Java泛型是强制类型检测的,泛型类型的子类型互不相关。

    publicclass Test {
        public static void main(String[] args) throws Exception{
            List<Integer> listInteger =new ArrayList<Integer>();
            List<String> listString =new ArrayList<String>();
            printCollection(listInteger);
            printCollection(listString);
        }
        public static void printCollection(Collection<Object> collection){
                   for(Object obj:collection){
                System.out.println(obj);
            }
        }
    }  

//Integer String都是Object的子类型,但是结果会报错,这就说明了泛型不考虑继承关系
The method printCollection(Collection<Object>) in the type GernericTest is not applicable for the arguments (List<Integer>)

  2.我们希望泛型能向普通类那样具有面向对象的一些特征:

    • 向上转型为一个泛型对象。
    • 向下转型为一个泛型对象。

  3.为了使泛型能具有面向对象的一些继承关系,Java引入了通配符的一些概念:无界通配符 ?

  为了使泛型的子类型仍然具有相关性,可以直接使用无界通配符:

  

  使用通配符上界“? extends T”,来指定继承关系

  

  

说明:

  ? extends T 的本质上的实现是泛型的自动向上转型。

  使用通配符下界“?super T”

  使用方法和解释同上。

时间: 2024-12-20 05:21:43

Java:泛型基础的相关文章

一个小栗子聊聊JAVA泛型基础

背景 周五本该是愉快的,可是今天花了一个早上查问题,为什么要花一个早上?我把原因总结为两点: 日志信息严重丢失,茫茫代码毫无头绪. 对泛型的认识不够,导致代码出现了BUG. 第一个原因可以通过以后编码谨慎的打日志来解决,我们今天主要来一起回顾下JAVA泛型基础. 一个小栗子 先看下面一个例子,test1实例化一个List容器的时候没有指定泛型参数,那么我们可以往这个容器里面放入任何类型的对象,这样是不是很爽?但是当我们从容器中取出容器中的对象的时候我们必须小心翼翼,因为容器中的对象具有运行时的类

2.java泛型基础

Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在JDK 5中的新集合类框架中.对于泛型概念的引入,开发社区的观点是褒贬不一.从好的方面来说,泛型的引入可以解决之前的集合类框架在使用过程中通常会出现的运行时刻类型错误,因为编译器可以在编译时刻就发现很多明显的错误.而从不好的地方来说,为了保证与旧有版本的兼容性,Java泛型的实现上存在着一些不够优雅的地

Java基础11:Java泛型详解

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

《Java架构筑基》从Java基础讲起——泛型基础

一.泛型的概述 1.1 泛型由来 我们的集合可以存储多种数据类型的元素,那么在存储的时候没有任何问题,但是在获取元素,并向下转型的时候,可能会存在一个错误,而这个错误就是ClassCastException . 很显然,集合的这种可以存储多种数据类型的元素的这个特点,不怎么友好 , 程序存在一些安全隐患,那么为了出来这种安全隐患,我们应该限定一个集合存储元素的数据类型,我们只让他存储统一中数据类型的元素,那么在做向下转型的是就不会存在这种安全隐患了. 怎么限定集合只能给我存储同一种数据类型的元素

java从基础知识(八)泛型

1.什么是泛型? 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. Java语言引入泛型的好处是安全简单. 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的"任意化","任意化"带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的.对于强制类型转换错

Java基础 Java 泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型.泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.假定我们有这样一个需求:写一个排序方法,能够对整型数组.字符串数组甚至其他任何类型的数组进行排序,该如何实现?答案是可以使用 Java 泛型.使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序.然后,调用该泛型方法来对整型数组.浮点数数组.字符串数组等进行排序. 泛

Java泛型的协变

在上篇<Java泛型的基本使用>这篇文章中遗留下面问题,即将子类型也能加入到父类型的泛型中.要实现这样的功能必须借助于协变. 实验准备 如今在上篇文章展示的Decorator类型的基础上,添加一些代码,如代码清单1所看到的. 代码清单1 /** * * 描 述:Exp2使用br/> * 作 者:jiaan.gja<br/> * 历 史: (版本号) 作者 时间 凝视 <br/> * @param itemList */ public void doDecorate

1月21日 - (转)Java 泛型

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

java泛型的讲解

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M