zoukankan      html  css  js  c++  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)意味着编写的代码可以被很多不同类型的对象所重用。

    2.泛型是JDK1.5中一个最重要的特征。通过引入泛型,我们将获得编译时类型的安全和运行时更小的抛出ClassCastException的可能。

      在JDK1.5中,你可以声明一个集合将接收/返回的对象的类型。


      使用泛型时如果不指明参数类型,即泛型类没有参数化,会提示警告,此时类型为Object。

    3.为什么要使用泛型

     使用泛型的典型例子,是在集合中的泛型使用。

      在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型。

      比如:

    List myIntList = new LinkedList(); // 1
    myIntList.add(new Integer(0)); // 2
    Integer x = (Integer) myIntList.iterator().next(); // 3
    

     第三行的这个强制类型转换可能会引起运行时的错误。

      泛型的思想就是由程序员指定类型,这样集合就只能容纳该类型的元素。

      使用泛型:

    List<Integer> myIntList = new LinkedList<Integer>(); // 1'
    myIntList.add(new Integer(0)); // 2'
    Integer x = myIntList.iterator().next(); // 3'
    

     将第三行的强制类型转换变为了第一行的List类型说明,编译器会为我们检查类型的正确性。这样,代码的可读性和健壮性也会增强。

    尖括号中包含的是形式类型参数(formal type parameters),它们就如同一般的类型一样,可以在整个类的声明中被使用。

      当类被使用时,会使用具体的实际类型参数(actual type argument)代替。

      比如前面的例子中的List<Integer>,那么所有的E将会被Integer类型所代替。

      泛型类型参数只能被类或接口类型赋值,不能被原生数据类型赋值,原生数据类型需要使用对应的包装类。

      形式类型参数的命名:尽量使用单个的大写字母(有时候多个泛型类型时会加上数字,比如T1,T2),比如许多容器集合使用E,代表element(元素),Map中用K代表键keys,V代表值。

    具体实现如下:

    public class Generic<T> {
    //T表示一种类型 ,该类具体是什么类型是由调用者来决定的。
    	private T x;
    	private T y;
    	public T getX() {
    		return x;
    	}
    	public void setX(T x) {
    		this.x = x;
    	}
    	public T getY() {
    		return y;
    	}
    	public void setY(T y) {
    		this.y = y;
    	}
    
    public class GenericDemo {
    	public static void main(String[] args) {
    		//情况1:使用String类型
    		Generic<String> c=new Generic<String>();
    		String num=c.getX();
    		//情况2:使用Integer类型
    		Generic<Integer> c1=new Generic<Integer>();
    		Integer num1=c1.getX();
    		//情况3:使用Double类型
    		Generic<Double> c2=new Generic<Double>();
    		Double num2=c2.getX();
    	}
    

     

     

  • 相关阅读:
    深度解读设备的“万能语言”鸿蒙系统的分布式软总线能力
    懂分析、会预测,你见过这样的华为云DAS吗?
    华为云登顶HotpotQA多跳知识推理问答评测
    突破开源Redis的内存限制,存算分离的GaussDB到底有多能“装”?
    六步带你完成博流wifi模组对接华为云流程
    Materialize MySQL引擎:MySQL到Click House的高速公路
    CWE 4.3:强化你的数据自我保护能力
    使用TENSORRT和NVIDIA-DOCKER部署深部神经网络
    用于ONNX的TensorRT后端
    循环IRNNv2Layer实现
  • 原文地址:https://www.cnblogs.com/jiangxifanzhouyudu/p/6696453.html
Copyright © 2011-2022 走看看