泛型的内容确实很多,在上一篇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类。