`
feng_gladys
  • 浏览: 7898 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java Generic

阅读更多

什么是泛型:

       Generic programming means to write code that can be reused for objects of many different types. 摘自《 Core java  

 

为什么使用泛型

       主要是为了类型转换。如果不使用泛型,那么每次都得显式的就行类型转换。

如:

       不使用泛型:

       List list = …

    String str = (String)list.get(1);  

    使用泛型:

    List<String> list = …

    String str =  list.get(1);  

 

如何定义泛型:

       使用 <Type variable> 中带有类型,该类型可以是具体类型 . 比如 : String.

也可以不是具体类型,比如 <? Extends Number>. 具体类型 (reifiable type) 和非具体类型 (unreifiable type)

       (非)具体化类型后面再介绍

       < Type variable > 即表明声明了泛型,可以在类、方法、字段等处定义泛型。

 

什么是类型参数( type parameter   参数化类型( parameterized type

       比如,类 List<String> ,称 String 为类型参数。 List<String> 为参数化类型,因为 List String 参数化了。  

 

 

子类型( subtypes )及替换原则  

    Integer Number 的子类,能放置 Number 的地方都能放置 Integer ,这便是 Java 中的替换原则。

    Substitution Principle: a variable of a given type may be assigned a value of any subtype of that type, and a method with a parameter of a given type may be invoked with an argument of any subtype of that type -- 摘自 Java Generics & Collections  

    数组 Integer[] Number[] 的子类,那是不是 List<Integer> 也是 List<Number> 的子类?其实不是,他们其实是同一类型。可以通过以下代码判断。

List<Number> numList = …

List<Integer> intList = …

System.out.println(numList.getClass() == intList.getClass())  

       如果我们需要在泛型中拥有类似于数组的该特性( Integer[] Number[] 的子类),我们就得使用通配符 (wildcard).  
 

通配符 (wildcard) 访问原则

       上述说过,数组 Integer[] Number[] 的子类, List<Integer> 确不是 List<Number> 的子类。要实现类似于数组的该特性,就需要通配符来实现 : List< ? extends Number> .

       表示通配符,表示任意类型(继承 Object 的任意类型)。

       ? extends T 表示继承或实现 T 的类型。即 T 的任意子类型 , 比如 ? extends Number 表示继承自 Number 的任意类型,可以是 Integer, Double …

       ? super T 表示 T 的任意父类型( super type ),比如: ? Super ArrayList 表示 ArrayList 的任意父类型,可以是 List, AbstractList…

       表示 ? extends Object  
 

       通过通配符,我们可以实现类似于数组的功能:

       List<Integer>  intList = …;

       List<Number> numList=…;

       List<? Extends Number> list1 = intList;

       List<? Extends Number> list2 = numList;

       List<? Super Number> list3 = numList;  

       这样我们可以向数组一样进行类型转换。但却不能像数组一样进行以下方式的赋值:

       Number[] nums = …

       Nums[0] = Integer.valueOf(2)..  

       如果编写以下代码:

       List<? Extends Number> list =  … ;

       List.add(Integer.valueOf(2)) // 编译器报错。

       List.add(Double.valueOf(2)) // 编译器报错  

    为什么呢? <? Extends Number> 不是表示 Number 的任意子类型么? 使用替换原则不是应该正确的么?

       该问题的源头就是因为 <? Extends Number> 表示 Number 的子类型。但是我们却不知道到底是哪个具体的类型。因此 List< ? extends Number> 可以指向其任意的子类型。比如, List<Integer>, List<Number>,List<Double>. 如果是 list 是指向 ArrayList<Double>, list.add(Integer.valueOf(2)) 合法的话,那么 list 中就存在 Double Integer Number 子类型的对象, ArrayList<Double> 中的元素类型就不一样。那么 list.get(..) 就有可能返回 Integer 类,就可能出现问题,由于泛型有个基本原则:

    Cast-iron guarantee:

    the implicit casts added by the compilation of generics never fail.

  •  
    •  
      •  
        •  

                -- 摘自 Java Generics & Collections  

所以编译器在编译级别就将可能导致类型转化的错误屏蔽掉。

    当然我们可以调用 list.add(null), 因为 null 是任意类型的子类型,可以安全的使用,但很多时候没有用处。 

       如果使用 list.get(..) 就不会有问题,因为 list 存的就是 Number 子类对象,任何子类都能转为其基类( Number )。  

       同样的道理,以下代码无法编译:

       List<? Super Integer> list = …

       Integer in =  list.get(0); // 编译过不去

       因为 List 存的是 Integer 的基类型,但是我们并不知道具体是哪个基类。所以就无法进行转化 , 当然我们可以调用 Object obj = list.get(0)

       如果使用 list.add(Integer.valueOf(2)) 却不会有问题,因为 list 存的是 Integer 的父类,那么必然可以存 Integer 类型。  

       因此利用 < ? extend …> <? Super …> 时,一般使用一个原则:

The Get and Put Principle: use an extends wildcard when you only get values out of a structure, use a super wildcard when you only put values into a structure, and don't use a wildcard when you both get and put.

  •  
    •  
      •  
        •  

                -- 摘自 Java Generics & Collections

类型参数 VS 通配符

       比如我们需要将一个list的数据拷贝到另一个list中。

假设方法在类Collections中定义:

public static <T> void copy(List<? super T> dst, List<? extends T> src)  

List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");

List<Integer> ints = Arrays.asList(5, 6);  

List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");

List<Integer> ints = Arrays.asList(5, 6);

Collections.copy(objs, ints);

assert objs.toString().equals("[5, 6, four]");  

由以下方法调用, <Object> 表示 T Object

Collections.copy(objs, ints);

Collections.<Object>copy(objs, ints);

Collections.<Number>copy(objs, ints);

Collections.<Integer>copy(objs, ints);  

比较以下几种方法签名:

1:public static <T> void copy(List<T> dst, List<T> src)

2:public static <T> void copy(List<T> dst, List<? extends T> src)

3:public static <T> void copy(List<? super T> dst, List<T> src)

4:public static <T> void copy(List<? super T> dst, List<? extends T> src)  

比较:

1 :限制最大,必须要求 dst src 是同一类型,比如同是 List<Integer>.

       该方法不能用于 上述的例子 collectioins.copy(objs,ints)  

2: 仅仅使用于T为Object时。即Collections.<Object>copy(objs, ints)方式  

3:仅仅使用于T为Integer时,Collections.<Integer>copy(objs, ints);  

4 :可应用于 T Object Number Integer 时。  

以上例子摘自 – Java Generic & Collections  

简单的总结一下:

       泛型方法签名尽可能的使用 wildcard ,其可用范围更广。如果需要严格限制为同一类型时,就可以使用 type parameter  

 

 

Wildcard capture

       译为 捕捉通配符??? 何为 wildcard capture. 顾名思义 : 就是捕捉通配符的类型。 看以下例子:

       Pair<T>有first 和second两个变量。分别有对应的set, get 方法。  

       public static void swap(Pair<?> p){

             ? t = p.getFirst(); // ERROR

             p.setFirst(p.getSecond());

             p.setSecond(t);  

       }

       但是用T确实没有问题:

public static <T> void swapHelper(Pair<T> p)

{

   T t = p.getFirst();

   p.setFirst(p.getSecond());

   p.setSecond(t);

}  

因此我们经常使用swapHelper(Pair<T> p)来实现swapHelper(Pair<?> p):

public static void swap(Pair<?> p) { swapHelper(p); }  

这种情况,我们叫T 捕捉了 通配符(T captures the wildcard).我们并不知道wildcard表示什么类型,但是我们知道其必然是一个明确的类型。因此可以用T去捕捉它。(这里有点绕,知道T可以捕捉?即可)。  

       注意的是:要用T捕捉?,那么要保证wildcard必须是表示同一、明确的类型(尽管我们不知道这是什么类型)。

       比如 ArrayList<List<T>>就不能用来捕捉ArrayList<List<?>>,因为ArrayList可能包含两个或以上List<?>,每个List<?>拥有不同的类型。  

以上例子摘自—Core Java  
 

擦除( erasure  

泛型定义:  

泛型方法:  

Bridge Method  

具体化类型 (reifiable type)  

泛型对象创建  

消除 Unchecked warning  

反射与泛型  

Effective generic

评论

相关推荐

    Java Generic 介绍 (pdf)

    标题中的“Java Generic 介绍”涵盖了泛型的基本概念、使用方式以及其背后的原理。以下是对这一主题的详细阐述: 1. **泛型的基本概念**:泛型是Java中的一种模板类或接口,它允许开发者在定义类、接口和方法时使用...

    Java - Generic

    在Java编程语言中,泛型(Generic)是一个强大的特性,它允许我们在编译时检查类型安全,并且可以消除运行时的类型转换。泛型引入的主要目的是提高代码的重用性、安全性和效率,同时减少类型转换的繁琐工作。这篇...

    android 浅复制和深复制-Java Generic Deep Copy 篇

    本文将深入探讨Java中的浅复制和深复制,并以Android为背景,结合具体的实例讲解如何实现Java泛型深拷贝。 首先,我们要理解浅复制和深复制的概念。浅复制(Shallow Copy)是指创建一个新的对象,然后将原对象引用...

    java-generic.rar_泛型

    在《java-generic.rar》压缩包中包含的《java generic.pdf》文件,很可能是详细阐述了以下几个关于Java泛型的核心知识点: 1. **类型参数化**:泛型的核心在于类型参数化,这使得我们可以在定义类、接口和方法时...

    Japag - Java generic command line GUI-开源

    【Japag - Java generic command line GUI 开源项目详解】 Japag,全称为 Java Application for Providing a Generic GUI,是一个开源项目,专为那些希望通过图形用户界面(GUI)而非命令行来运行各种命令行应用...

    Java高手真经(编程基础卷)光盘全部源码

    看到很多人都分卷打包的,下载很是不方便,还浪费积分,我就整合压缩打包到一个包里面,里面包含全部...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性

    java高手真经 光盘源码

    java高手真经 全光盘源代码 打包rar 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例Hello...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性

    Java高手真经(编程基础卷)光盘全部源码 免积分

    看到那些要积分的很不酸,发布免费版本。 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例...javageneric.zip 27.Java泛型编程 javaannotation.zip 28.Java注释符编程 javafeature.zip 29.Java5.0语言新特性

    Java泛型编程指南.pdf

    ### Java泛型编程指南知识点详解 #### 一、绪论:理解Java泛型的重要性与背景 **1.1 泛型的基本概念** 泛型是一种在编程语言中支持编写类型安全的通用函数或类的能力。在Java中引入泛型的主要目的是为了提供更...

    java 泛型接口示例

    Java 泛型是Java SE 5.0引入的一项重要特性,极大地增强了代码的类型安全性和重用性。泛型接口是泛型在接口中的应用,它允许我们在接口中定义带有类型参数的方法,使得实现该接口的类可以使用不同的数据类型。下面...

    Generic_MT4_java_generic_mt4_

    标题中的"Generic_MT4_java_generic_mt4_"暗示了一个与MetaTrader 4 (MT4)交易平台相关的编程项目,可能是一个自定义的智能交易系统(Expert Advisor,EA)或指标,使用了Java语言,并且具有通用性。这个“Generic_...

    Java中的泛型方法演示代码

    Java中的泛型是Java SE 5.0引入的一项重要特性,极大地增强了代码的类型安全性和重用性。泛型方法是泛型概念的一个关键部分,它允许我们在方法签名中使用类型参数,从而使方法能够处理不同类型的参数。在这个“Java...

    Java1.5泛型指南中文版(Java1.5 Generic Tutorial)

    Java1.5泛型指南中文版(Java1.5 GenericTutorial)

    java 开发技术大全10

    ### Java开发技术大全10:深入理解泛型 #### 10.1 泛型的本质 泛型在Java中是一项重要的特性,它被引入到JDK 1.5中,目的是为了提高代码的复用性和类型安全性。泛型的本质是类型参数化,即允许开发者在声明类或...

    java collection framework

    此外,还介绍了一种名为 JGL (Java Generic Library) 的第三方库,该库在 Java Collection Framework 出现之前就已经存在,并且提供了一些额外的功能。 #### 八、总结 《Java Collection Framework》这本书不仅是...

    java 泛型的使用 详细讲解

    ### Java泛型的使用详细讲解 #### 一、引言 在Java开发中,泛型是一种重要的语言特性,它能够帮助开发者在不增加代码量的情况下处理多种数据类型,同时还能保持代码的清晰度和可读性。本文将详细介绍Java泛型的...

Global site tag (gtag.js) - Google Analytics