一般的我们方法大多都会使用到泛型,那么,我们是否可以取得泛型的实例呢?
答案是可以的。我们可以使用java中的反射技术来实现对方法中泛型对象的实例化。下面,我们来进一步探讨。
1.放射泛型需要使用到的类:
import java.lang.reflect.Field; // 取得对象中的全部属性
import java.lang.reflect.Modifier; // 取得对象中的修饰符(因为返回的是int类型,因此需要使用Modifier.toStirng()方法解析)
import java.lang.reflect.ParameterizedType; //得到泛型中对象的全部信息
import java.lang.reflect.Type; //java语言中所有类型的公共父接口(可用可不用)
二:代码图
①实体类
public class Customer {
// ---------------------->用户资料<----------------------
private String name ;
private String password ;
private int money ;
//---------------------->方法<----------------------
public Customer(String name, String password, int money) { //相当于实体层
super();
this.name = name;
this.password = password;
this.money = money;
}
public Customer() {
}
// toSytring 方法
public String toString() {
return "Customer对象实例化好了";
}
//省略了get和set方法
}
②父类接口类:
public interface BaseCustomer<T> { // DAO公共接口层
String getClassName() ; // 得到类名
String getMassage() ; // 查看类的属性的全部的名字(包括修饰符之类的)
T getInstance() ; // 得到类的实例
}
--------------------------->
③父类实现类:
public class BaseCustomerImpl<T> implements BaseCustomer<T> { //相当于DAO的公共的实现层
// ---------------------->属性<----------------------
private Class<T> clazz ; // 泛型的 class
T t ; // 泛型的实例
// ---------------------->方法<----------------------
// 得到 Class 的类的名字
public String getClassName() {
String name = clazz.getSimpleName() ;
return name;
}
// 在实例化的时候得到泛型的class
public BaseCustomerImpl() { // 相当于DAO的到公共实现层
ParameterizedType pz = (ParameterizedType) this.getClass().getGenericSuperclass() ;//子类必须明确泛型的具体类型
// 由于 ParameterizedType 中的 getActualTypeArguments() 返回的是一个数组
// 因此如果泛型只有一个,就需要指定下标
this.clazz = (Class<T>) pz.getActualTypeArguments()[0] ;
}
// 查看类的属性的全部的名字(包括修饰符之类的)
public String getMassage() {
StringBuffer beffer = new StringBuffer() ;
// 通过反射得到类中的具体信息
// 得到属性名
Field[] fields = clazz.getDeclaredFields() ;
for(int i = 0 ;i < fields.length; i++) {
// 将数组中的东西遍历出来
int mo = fields[i].getModifiers() ; // 得到修饰符的数字
String modifier = Modifier.toString(mo) ; // 还原修饰符
String type = fields[i].getType().getName() ; // 得到数据类型
beffer.append( modifier + " " + type + " " + fields[i].getName() + " ;") ;
if(i != fields.length - 1) {
beffer.append("\n") ;
}
}
return beffer.toString() ;
}
// 得到类的实例
public T getInstance() {
try {
t = clazz.newInstance() ; // 使用泛型来实例化对象
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return t ;
}
}
--------------------------------------------->
④子类实现类:
// 相当于DAO的具体实现层
public class CustomerImpl extends BaseCustomerImpl<Customer> { // 子类明确指定了Customer为泛型的具体类型---------------->重点!!!
// 必须在子类中指定泛型的具体类型,否则会在实例化ParameterizedType中
// 抛出 java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType异常
// 该异常是说将class强制转ParameterizedType错误,因为class<T>中T的类型不明确
}
--------------------------------------------->
⑤测试类:
public class test {
public static void main(String[] args) {
BaseCustomer cm = new CustomerImpl() ;
System.out.println("类的名字-------------->" + cm.getClassName()) ;
System.out.println() ;
System.out.println("类的属性-------------->") ;
System.out.println(cm.getMassage());
System.out.println("类的属性-------------->") ;
System.out.println() ;
System.out.println("类的实例-------------->" + cm.getInstance().toString()) ;
}
}
⑥结果图:
类的名字-------------->Customer
类的属性-------------->
private java.lang.String name ;
private java.lang.String password ;
private int money ;
类的属性-------------->
类的实例-------------->Customer对象实例化好了
三.分析错误及其解决办法:
出现错误:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
原因:在BaseCustomerImpl 中指定了泛型,但是却没有在子类中明确其泛型的具体的类型时,就会报错。
例如 :
①子类在继承类或者是实现接口时没有明确指定泛型的具体类型
public class CustomerImpl extends BaseCustomerImpl<T> {// 子类没有明确指定泛型的具体类型(如果将 T 明确为Customer就不会报错)
// 此时就会抛出 java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType异常
// 该异常是说将class强制转ParameterizedType错误,因为class<T>中T的类型不明确
}
②直接在实例化对象时指定泛型对象(继承时没有明确指定泛型对象类型)
public class test {
public static void main(String[] args) {
BaseCustomer<Customer> cm = newBaseCustomerImpl<Customer>() ;
// 即使是这样使用,还是会抛出java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType异常
//直接在测试类中指定泛型类型,而继承时没有指定,会报错
// 重点----->所以必须有个子类明确其具体的类型,即其必须要有子类来继承 BaseCustomerImpl类 或者是 BaseCustomerImpl类 实现接口时明确泛型的具体类型
}
}
①再写一个子类继承这个类,子类可以没有任何属性和方法,但必须指明泛型类型,然后使用子类创建对象
②写一个含有Class<T>类型的构造方法,在使用该类创建对象时给出具体类型
四.谨记:
一定要在定义类的时候定义泛型的具体的类型,才能获得类的反射(即在 子类继承类 或 实现接口 的时候,明确泛型的类型)
新人初写,不好之处请多多指教和包涵。