首页 > 技术文章 > Java之泛型深解

Cirgo 2018-02-20 21:52 原文

  泛型的内容确实很多,在上一篇Java之泛型浅解讲到了一些常用的泛型,但是还远远不够,上一篇的内容比较容易理解,这一篇我自己觉得更加难理解一些,因此,我还得想办法让它更加接地气更加容易理解,方便我和源宝理解记忆拓展。

泛型方法

  既然之前吹牛逼说这是高级内容,那么我们来思考一个问题------>我们说过,泛型是属于编译阶段的,编译就意味着去泛型化,也就是说编译好的目标程序是不存在所谓的泛型的,总之,记住一句话:编译后的程序一定都是具体类型的。但是我们想想,Java中static(静态)修饰的部分,不能被实例化,在计算机内存中仅仅一份,而泛型呢,类型是变化的,如果允许使用泛型作为静态方法(块)的参数,那么计算机内存绝对不止一份吧,这就矛盾了。因此,Java中规定,如果你定义了一个泛型(类、接口),那么Java规定,你不能在所有的静态方法、静态初块等所有静态内容中使用泛型的类型参数。

1 public class Person<T> {
2     public static void test(T t) {//静态方法使用了泛型T
3     /*编译不通过*/
4     }
5 }

   对于static方法,无法访问泛型类的类型参数。但是也有办法让其具有访问泛型的能力,那就是使static方法变成泛型方法。

  上一篇提到过泛型类,它是在实例化的时候指明具体类型,然而泛型方法呢就是在调用方法的时候,指明具体类型

泛型方法的特点:
  方法的参数中可以使用泛型变量;
  方法的返回值中可以使用泛型变量。

 1 /**
 2  * 泛型方法的基本介绍
 3  * @param tClass 传入的泛型实参
 4  * @return T 返回值为T类型
 5  * 说明:
 6  *     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
 7  *     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
 8  *     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
 9  *     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
10  */
11 public [static] <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
12   IllegalAccessException{
13         T instance = tClass.newInstance();
14         return instance;
15 }

对于泛型方法,推荐博客Java中的泛型方法

<T>与<?>的区别

  <T>:自定义泛型

  <?>:   通配符泛型

   这两者都是不确定类型。自定义泛型<T>在编译之后表示某种确定的类型(如String、int等),因此,在编程时,就可以把它当成某种确定的数据类型进行后续开发工作。对于通配符泛型<?>用得挺多的,Java中泛型引用传递时,类型必须完全匹配,例如:fun<Object>与fun<String>之间就不能传递,务必完全一样才允许传递。

但是,如果对象引用不使用泛型,那么程序可以正常运行,只不过会有警告。

因此,通配符算是派上了用场。

但是需要注意的是,使用<?>意味着能接收一切内容,但是此内容无法使用<?>修饰的泛型对象进行修改。

在修改泛型对象内容时,对象引用的泛型类型必须其指向的泛型引用完全一致,才行。

  综上,我们可以明白<?>只能接收,但是不能修改,一般在集合类用得挺多的。

受限泛型

之前设置泛型类型的时候,实际上都是可以任意设置的,只要是类就可以设置。但是在Java的泛型中可以指定一个泛型的上限和下限。范围的上限使用extends关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。而范围下限使用super进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object类。

设置上限:
  声明对象:类名称<?/T extends 类1 & 类2...>  对象名称
  定义类: [访问权限] 类名称<泛型标示 extends 类>{}
设置下限:
  声明对象:类名称<?/T super 类1 & 类2...> 对象名称
 定义类:[访问权限] 类名称<泛型标示 super 类>{}

 

推荐阅读