• 反射应用--取得类的结构


    1,目标:

     通过反射取得类的全部接口,

    取得类所继承的父类

    取得类全部构造方法

    通过反射取得类的全部方法

    通过反射取得一个类的全部属性。

    具体类型

    反射的深入-取得类的结构

    要想通过反射取得类的结构,需要使用接口:java.lang.reflect包中的以下类:

    1,Constructor:表示类的构造方法

    2,Field:表示类中属性。

    3,Method:表示类中的方法。

    这三个类都是AccessibleObject的子类。

    实践:

    一,设置一个类:

    package 类集;
    
    interface China{    // 定义China接口
        public static final String NATIONAL = "China" ;    // 定义全局常量
        public static final String AUTHOR = "小华" ;    // 定义全局常量
        public void sayChina() ;        // 无参的,没有返回值的方法
        public String sayHello(String name,int age) ;    // 定义有两个参数的方法,并返回内容
    }
    public class Person implements China{
        private String name ;
        private int age ;
        public Person(){    // 无参构造
        }
        public Person(String name){
            this.name = name ;    // 设置name属性
        }
        public Person(String name,int age){
            this(name) ;
            this.age = age ;
        }
        public void sayChina(){    // 覆写方法
            System.out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL) ;
        }
        public String sayHello(String name,int age){
            return name + ",你好!我今年:" + age + "岁了!" ;
        }
        public void setName(String name){
            this.name = name ;
        }
        public void setAge(int age){
            this.age = age ;
        }
        public String getName(){
            return this.name ;
        }
        public int getAge(){
            return this.age ;
        }
    };

    1,取得类实现的接口:

    要想取得全部接口:可以使用Class类中的方法:

     Class<?>[] getInterfaces() 
              确定此对象所表示的类或接口实现的接口 

    因为一个类可以同时取得多个接口,所以此处将以一个数组的形式返回实现的全部接口。

    package 类集;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){            //处理异常
                e.printStackTrace() ;
            }
            Class<?> c[] = c1.getInterfaces() ;    // 以数组形式返回实现的全部接口
            for(int i=0;i<c.length;i++){
                System.out.println("实现的接口名称:" + c[i].getName()) ;    // 输出接口名称
            }
        }
    }

    输出结果:

    类集.China

    总结:

    要想取得一个类所实现的全部接口,必须使用Class类中getInterface()方法,

    定义如下:public Class<?> [] getInterface();

    此方法返回一个Class类的对象数组,之后就可以利用Class类中的getName()输出即可。

    取得类所继承的父类

    要想取得父类,使用Class类中的getSupperClass()方法,

    定义如下:

     Class<? super T> getSuperclass() 
              返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。 

    此方法返回的是class实例 ,  和接口一样,通过getName()方法获得。

     一个类继承一个父类,如果没有指明继承哪个类,则肯定继承的是object类

    取得父类。

    package 类集;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1=null;
            try {
                c1=Class.forName("类集.Person");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            Class<?> c2 = c1.getSuperclass() ;    // 取得父类
            System.out.println("父类名称:" + c2.getName()) ;
        }
    }

    输出结果:

    父类名称:java.lang.Object

    取得公共构造方法

     Constructor<T> getConstructor(Class<?>... parameterTypes) 
              返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 

    返回一个对象。注意要处理异常。

    实例:

    package 类集;
    import java.lang.reflect.Constructor;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){
                e.printStackTrace() ;
            }
            Constructor<?> con=null;
            try {
                 con = c1.getConstructor();
            } catch (NoSuchMethodException | SecurityException e) {
                e.printStackTrace();
            }
            
            System.out.println("构造方法:" + con) ;     // 输出构造,直接打印
        }
    }

    输出结果:

    构造方法:public 类集.Person()

    取得全部构造方法:

    通过方法:getConstructors()。

     Constructor<?>[] getConstructors() 
              返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 

    实例:

    package 类集;
    import java.lang.reflect.Constructor;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){
                e.printStackTrace() ;
            }
            Constructor<?> con[] = c1.getConstructors() ;    // 取得一个类中的全部构造
            for(int i=0;i<con.length;i++){
                System.out.println("构造方法:" + con[i]) ;     // 输出构造,直接打印
            }
        }
    }

    输出结果:

    构造方法:public 类集.Person(java.lang.String,int)
    构造方法:public 类集.Person(java.lang.String)
    构造方法:public 类集.Person()

    以上操作确实取得了类中的构造方法,但是此时是通过对象直接打印取得的,输出的时候定会自动调用constructor里面的toString()方法

    如果不想用自带的toString()怎么办?

    constructor类中存在以下方法,

    1)取得修饰符。getModifiers() 

     int getModifiers() 
              以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符。 

    2)取得方法名称:getName();

     String getName() 
              以字符串形式返回此构造方法的名称。 

    3)取得参数的类型。getParameterTypes

     Class<?>[] getParameterTypes() 
              按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。 

    实例:

    package 类集;
    import java.lang.reflect.Constructor;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){
                e.printStackTrace() ;
            }
            Constructor<?> con[] = c1.getConstructors() ;    // 取得一个类中的全部构造
            for(int i=0;i<con.length;i++){
                Class<?> p[] = con[i].getParameterTypes() ;        // 得到某个构造方法中的全部参数
                System.out.print("构造方法:" ) ;     // 输出构造,直接打印
                System.out.print(con[i].getModifiers() + " ") ;    // 得到修饰符
                System.out.print(con[i].getName()) ;    // 取得构造方法的名字
                System.out.print("(") ;
                for(int j=0;j<p.length;j++){          //遍历参数,输出
                    System.out.print(p[j].getName() + " arg" + i) ;
                    if(j<p.length-1){
                        // 判断此是否是最后一个参数
                        System.out.print(",");    // 输出“,”
                    }
                }
                System.out.println("){}") ;
            }
        }
    }

    输出结果:

    构造方法:1 类集.Person(java.lang.String arg0,int arg0){}
    构造方法:1 类集.Person(java.lang.String arg1){}
    构造方法:1 类集.Person(){}

    从之前程序可以发现,取得权限的时候,返回的是一个数字,而不是public,这是因为在java中对于修饰符是使用数字表示出来的, 所以需要还原修饰符出来

    则必须依靠Modifier类完成,定义在reflect包中,直接使用Modify类的以下方法即可将修饰符操作

    static String toString(int mod) 
              返回描述指定修饰符中的访问修饰符标志的字符串。 

    利用以上方法还原修饰符。

    package 类集;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Modifier;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){
                e.printStackTrace() ;
            }
            Constructor<?> con[] = c1.getConstructors() ;    // 取得一个类中的全部构造
            for(int i=0;i<con.length;i++){
                Class<?> p[] = con[i].getParameterTypes() ;        // 得到构造方法中的全部参数
                System.out.print("构造方法:" ) ;     // 输出构造,直接打印
                int mo = con[i].getModifiers() ; // 得到所要的访问权限
                System.out.print(Modifier.toString(mo) + " ") ;    // 得到修饰符
                System.out.print(con[i].getName()) ;    // 取得构造方法的名字
                System.out.print("(") ;
                for(int j=0;j<p.length;j++){
                    System.out.print(p[j].getName() + " arg" + i) ;
                    if(j<p.length-1){
                        // 判断此是否是最后一个参数
                        System.out.print(",");    // 输出“,”
                    }
                }
                System.out.println("){}") ;
            }
        }
    }

    输出结果:

    构造方法:public 类集.Person(java.lang.String arg0,int arg0){}
    构造方法:public 类集.Person(java.lang.String arg1){}
    构造方法:public 类集.Person(){}

    取得全部方法

    可以使用Class类中的getDeclaredMethods,此方法返回一个method类对象数组,如果想要进一步取得方法具体信息,必须依靠Method类。

     Method[] getDeclaredMethods() 
              返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 

    method类有以下方法:

    getReturnType() ; // 取得全部的返回值
    
    getParameterTypes() ; // 取得全部参数
    
    getModifiers():取得修饰符
    
    getName() 获取名称
    
    getExceptionTypes() ; // 取出异常

    实例:

    package 类集;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){
                e.printStackTrace() ;
            }
            Method m[] = c1.getMethods() ;    // 取得全部方法
            for(int i=0;i<m.length;i++){
                Class<?> r = m[i].getReturnType() ;    // 得到返回值类型
                Class<?> p[] = m[i].getParameterTypes() ;    // 取得全部参数的类型
                int xx = m[i].getModifiers() ;    // 类得到修饰符
                System.out.print(Modifier.toString(xx) + " ") ;    //利用Modifier类,输出修饰符
                System.out.print(r + " ") ;
                System.out.print(m[i].getName()) ;
                System.out.print("(") ;
                for(int j=0;j<p.length;j++){
                    System.out.print(p[j].getName() + " " + "arg" + j) ;
                    if(j<p.length-1){
                        System.out.print(",") ;
                    }
                }
                Class<?> ex[] = m[i].getExceptionTypes() ;    // 取出异常
                if(ex.length>0){
                    System.out.print(") throws ") ;
                }else{
                    System.out.print(")") ;
                }
                for(int j=0;j<ex.length;j++){
                    System.out.print(ex[j].getName()) ;
                    if(j<p.length-1){
                        System.out.print(",") ;
                    }
                }
                System.out.println() ;
            }
        }
    }

     输出结果:

    public class java.lang.String getName()
    public void setName(java.lang.String arg0)
    public class java.lang.String sayHello(java.lang.String arg0,int arg1)
    public int getAge()
    public void setAge(int arg0)
    public void sayChina()
    public final void wait() throws java.lang.InterruptedException
    public final void wait(long arg0,int arg1) throws java.lang.InterruptedException,
    public final native void wait(long arg0) throws java.lang.InterruptedException
    public boolean equals(java.lang.Object arg0)
    public class java.lang.String toString()
    public native int hashCode()
    public final native class java.lang.Class getClass()
    public final native void notify()
    public final native void notifyAll()

    实际上,一般开发工具经常看见随笔提示功能,实际上就是利用以上程序实现的。

    取得全部属性

    在反射操作中可以取得全部属性,但是有两种操作:

    1,得到实现的接口,或父类中公共属性:

     Field[] getFields() 
              返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段 

    2,得到本类中全部属性。

     Field[] getDeclaredFields() 
              返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 

    以上返回的欧式Filed的数组,每一个Fild对象表示类中一个属性。

    Field包含的方法:

    getType():得到属性类型。
    
    getModifiers():得到修饰符的数字。

    实例:

    package 类集;
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    public class GetInterfaceDemo {
        public static void main(String[] args) {
            Class<?> c1 = null ;        // 声明Class对象
            try{
                c1 = Class.forName("类集.Person") ;    // 实例化对象
            }catch(ClassNotFoundException e){
                e.printStackTrace() ;
            }
            {    // 本类属性
                Field f[] = c1.getDeclaredFields() ;    // 取得本类中的属性
                for(int i=0;i<f.length;i++){
                    Class<?> r = f[i].getType() ;    // 得到属性类型
                    int mo = f[i].getModifiers() ;    // 得到修饰符的数字
                    String priv = Modifier.toString(mo) ; // 还原修饰符
                    System.out.print("本类属性:") ;
                    System.out.print(priv + " ") ;    
                    System.out.print(r.getName() + " ") ;    // 得到属性类型
                    System.out.print(f[i].getName()) ;    // 输出属性名称
                    System.out.println(" ;") ;
                }
            }
            {    // 公共属性
                Field f[] = c1.getFields() ;    // 取得本类中的公共属性
                for(int i=0;i<f.length;i++){
                    Class<?> r = f[i].getType() ;    // 得到属性类型
                    int mo = f[i].getModifiers() ;    // 得到修饰符的数字
                    String priv = Modifier.toString(mo) ; // 还原修饰符
                    System.out.print("公共属性:") ;
                    System.out.print(priv + " ") ;    
                    System.out.print(r.getName() + " ") ;    // 得到属性类型
                    System.out.print(f[i].getName()) ;    // 输出属性名称
                    System.out.println(" ;") ;
                }
            
            }
        }
    }

    输出结果:

    本类属性:private java.lang.String name ;
    本类属性:private int age ;
    公共属性:public static final java.lang.String NATIONAL ;
    公共属性:public static final java.lang.String AUTHOR ;

    总结:

    1,在开发中,取得类的信息的操作代码用户不会经常开发,

    2,一定要熟悉reflect包作用,反射机制。

    3,取得属性,构造,方法的名称,修饰符等等,了解就可以了。要熟悉

  • 相关阅读:
    【多线程】工具类汇总
    【JVM】GC日志样例解读
    【Docker】
    XXS level5
    XXS level4
    XXS level3
    XXS level2
    SQLI DUMB SERIES-6
    SQLI DUMB SERIES-5
    XXS level1
  • 原文地址:https://www.cnblogs.com/alsf/p/6577347.html
Copyright © 2020-2023  润新知