¶ 泛型方法(利用反射进行传递类型)
定义泛型方法语法格式
调用泛型方法语法格式 ![java-basic-generic-5.png](/uploads/projects/wangyuxiang-wpk45@bzivet/88114dc05f7c8f63f64f9b43169d082d.png)
说明
- 定义泛型方法时,必须在返回值前边加一个
,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。 - Class
的作用就是指明泛型的具体类型,而Class 类型的变量c,可以用来创建泛型类的对象。 - 为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。
- 泛型方法要求的参数是Class
类型,而Class.forName()方法的返回值也是Class ,因此可以用Class.forName()作为参数(直接读取配置文件properties)。其中,forName()方法中的参数是何种类型,返回的Class 就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class 类型的对象,因此调用泛型方法时,变量c的类型就是Class ,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。 当然,泛型方法不是仅仅可以有一个参数Class
,可以根据需要添加其他参数。 ¶ 泛型的上下限
注意:泛型不支持多态
- 先看下如下的代码,很明显是会报错的 ```java class A{} class B extends A {}
// 如下两个方法不会报错
public static void funA(A a) {
// …
}
public static void funB(B b) {
funA(b);
// …
}
// 如下funD方法会报错
public static void funC(List listA) {
// …
}
public static void funD(List listB) {
funC(listB); // Unresolved compilation problem: The method doPrint(List) in the type test is not applicable for the arguments (List)
// …
}
- 为了解决泛型中隐含的转换问题,Java泛型加入了类型参数的上下边界机制。
- <? extends A>表示该类型参数可以是A(上边界)或者A的子类类型。编译时擦除到类型A,即用A类型代替类型参数。
- 这种方法可以解决开始遇到的问题,编译器知道类型参数的范围,如果传入的实例类型B是在这个范围内的话允许转换,这时只要一次类型转换就可以了,运行时会把对象当做A的实例看待。
```java
public static void funC(List<? extends A> listA) {
// ...
}
public static void funD(List<B> listB) {
funC(listB); // OK
// ...
}
泛型上下限的引入
- 在使用泛型的时候,我们可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类。
上限
class Info<T extends Number>{ // 此处泛型只能是数字类型 private T var ; // 定义泛型变量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } } public class demo1{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象 } }
下限
class Info<T>{ private T var ; // 定义泛型变量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } } public class GenericsDemo21{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; // 声明String的泛型对象 Info<Object> i2 = new Info<Object>() ; // 声明Object的泛型对象 i1.setVar("hello") ; i2.setVar(new Object()) ; fun(i1) ; fun(i2) ; } public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型,String类的父类只有Object类 System.out.print(temp + ", ") ; } }
小结
```java <?> 无限制通配符 <? extends E> extends 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类 <? super E> super 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类
// 使用原则《Effictive Java》 // 为了获得最大限度的灵活性,要在表示 生产者或者消费者 的输入参数上使用通配符,使用的规则就是:生产者有上限、消费者有下限
- 如果参数化类型表示一个 T 的生产者,使用 < ? extends T>;
- 如果它表示一个 T 的消费者,就使用 < ? super T>;
- 如果既是生产又是消费,那使用通配符就没什么意义了,因为你需要的是精确的参数类型。
```
¶ 深入理解泛型