利用反射取得泛型的类名和属性名

来源:互联网 发布:免费手机qq群发软件 编辑:程序博客网 时间:2024/05/20 09:10

一般的我们方法大多都会使用到泛型,那么,我们是否可以取得泛型的实例呢?

答案是可以的。我们可以使用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 CustomerImplextends 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>类型的构造方法,在使用该类创建对象时给出具体类型

四.谨记:

一定要在定义类的时候定义泛型的具体的类型,才能获得类的反射(即在子类继承类实现接口 的时候,明确泛型的类型


新人初写,不好之处请多多指教和包涵。

阅读全文
0 0
原创粉丝点击