zoukankan      html  css  js  c++  java
  • 二十六、Java--------反射

     

    反射

        正常情况下,我们必须知道一个类的完整路径后才可以实例化对象,但是在Java也可以通过一个对象来找到其所在类的信息,这其实就是Class的功能。

    可以看到此时的所有操作都是反着来,这就是反射。

    package reflect;

    class X{

        

    }

    public class GetClassDemo01 {

        public static void main(String[] args) {

            X x=new X();

            System.out.println(x.getClass().getName());

        }

    }

      

    Class

        Class本身表示一个类的本身,通过Class可以完整的得到一个类的完整结构,包括此类中的方法定义、属性定义等。

      

            此类在jdk中文档中没有发现任何构造方法,所以此类的构造方法是被私有化了。

    实例化Class 类对象的三种方式

        第一种:通过forName()方法

            ♥ 第二种: 通过类class

            ♥ 第三种:通过对象.getClass()

    package reflect;

    class X{

        

    }

    public class GetClassDemo01 {

        public static void main(String[] args) {

            Class <?> c1=null;

            Class <?> c2=null;

            Class <?> c3=null;

            try {

                //通过第一种方式实例化Class对象,这种方法也是最常用的一种形式

                c1=Class.forName("reflect.X");

                //通过Object类中的放过实例化Class对象

                c2=new X().getClass();

                //通过类.cass实例化Class

                c3=X.class;

                System.out.println("类名称:" + c1.getName() );

                System.out.println("类名称:" + c2.getName() );

                System.out.println("类名称:" + c3.getName() );

            } catch (ClassNotFoundException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

    }

         一旦可以实例化Class对象之后就可以进行反射的进一步操作了。

    Class的使用

        Class主要是反射的源头,不光可以取得对象所在类的信息,也可以直接通过Class类的方法进行对象的实例化对象操作,使用关键字new为对象实例化,如果现在已经实例化好Class对象,则可以通过Class类提供的newInstance()方法实例化对象。

    package reflect;

    class Person{

        private String name;

        private int age;

        @Override

        public String toString(){//为了操作方便,复写toString放过

            return "姓名:"+this.name+",年龄"+this.age;

            

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public int getAge() {

            return age;

        }

        public void setAge(int age) {

            this.age = age;

        }

        

    }

    public class InstanceDemo01 {

        public static void main(String[] args) {

            Class<?> c=null;

            try {

                c=Class.forName("reflect.Person");

                Person per=null;

                per=(Person) c.newInstance();//实例化对象

                per.setName("月芽之上");

                per.setAge(24);

                System.out.println(per.toString());

                

                

            } catch (ClassNotFoundException e) {

                e.printStackTrace();

            } catch (InstantiationException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            } catch (IllegalAccessException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            

        }

    }

       通过以上的代码可以发现,即使不适用 new关键字对象也可以进行实例化操作,这也就是反射的作用。但是我们也发现在使用以上操作的时候有一点需要注意,就是所操作的类中必须有午餐构造函数,否则无法进行实例化!

    为了解决这一问题,我们需要明确的指明要调用的方法,并传递参数,(实际开发中一般会有午无参构造)。步骤如下:

      ❤ 1、通过Class类中的getConstructors()取得本类中的全部构造方法。

        ❤ 2、向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数

        ❤ 3、之后通过Constructor实例化对象

            Construction类中存在一个方法:

            public T newInstance(Object... initargs)

                            throws InstantiationException,

                            IllegalAccessException,

                            IllegalArgumentException,

                            InvocationTargetException

            传递参数初始化,以进行对象的实例化操作。

    Constru中常用方法:

    调用带参数的构造方法示例

    package reflect;

      

    import java.lang.reflect.Constructor;

    import java.lang.reflect.InvocationTargetException;

      

    class Person{

        private String name;

        private int age;

        public Person(String name,int age){//定义一个有两个参数的构造函数,此时当前类不再存在无参构造

            this.name=name;

            this.age=age;

        }

        @Override

        public String toString(){//为了操作方便,复写toString放过

            return "姓名:"+this.name+",年龄"+this.age;

            

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public int getAge() {

            return age;

        }

        public void setAge(int age) {

            this.age = age;

        }

        

    }

    public class InstanceDemo01 {

        public static void main(String[] args) {

            Class<?> c=null;

            try {

                c=Class.forName("reflect.Person");

                Constructor<?> cons[]=null;

                cons=c.getConstructors();

                

                Person per=null;

                

                per=(Person) cons[0].newInstance("月芽之上",24);//实例化对象

                

                System.out.println(per.toString());

            } catch (ClassNotFoundException e) {

                e.printStackTrace();

            } catch (InstantiationException e) {

                e.printStackTrace();

            } catch (IllegalAccessException e) {

                e.printStackTrace();

            } catch (IllegalArgumentException e) {

                e.printStackTrace();

            } catch (InvocationTargetException e) {

                e.printStackTrace();

            }

            

        }

    }

    通过反射获取类的结构

        在实际开发中,上面介绍的程序就是反射用的最多的情况,当然反射机制所提供的功能远不止这些,还可以通过反射获取一个类的完整结构,那么这是就要使用到java.lang.reflect保重的一些几个类。

        ❤ 1Constructor :表示类中的构造方法

            ❤ 2Filed :表示类中的属性

            ❤ 3Method :表示类中的方法

    这三个类都是AccessibleObject的子类

      

    package reflect.construction;

    interface China{

        String NATIONAL="China";//定义全局变量

        String AUTHOR="月芽之上";//定义全局变量

        void sayChina();

        String sayHello(String name,int age);

    }

    public class Person implements China {

        private String name;

        private int age;

        Person(){//参构造

        }

        Person(String name){//设置name

        this.name=name;

        }

        Person(String name,int age){//设置name

            this.name=name;

            this.age=age;

            }

        @Override

        public void sayChina() {

            System.out.println("作者:"+AUTHOR+",国籍"+NATIONAL);

        }

        @Override

        public String sayHello(String name, int age) {

            return name+",你好,我今年"+ age+"岁了!";

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public int getAge() {

            return age;

        }

        public void setAge(int age) {

            this.age = age;

        }

    }

    取得类所实现的全部接口

        要取得一个类所实现的接口,则必须使用Class类中的getInterfaces()方法。此方法定义如下:

    public Class<?>[] getInterfaces()

    方法的返回值是一个class类的对象数组,之后就可以直接利用Class类中的getName()方法输出即可、

    public class GetInterfaceDemo {

        public static void main(String[] args) {

            Class<?> c1=null;

            try {

                c1=Class.forName("reflect.construction.Person");

                Class<?> c[]=c1.getInterfaces();

                for(int i=0;i<c.length;i++){

                    System.out.println(c[i].getName());

                }

            

            } catch (ClassNotFoundException e) {

                e.printStackTrace();

            }

            

        }

    }

    取得该类所继承的父类

        一个类可与有多个实现,但是却只能有一个直接父类,所以想要取得一个类的父类,可以使用Class类中的getSuperclass()方法。

    public Class<? super T> getSuperclass()

    此方法返回的是Class实例,和之前取得接口一样,可以通过getName(0方法取得名次

    public class GetSuperClassDemo {

        public static void main(String[] args) {

            Class<?> c1 = null;

            try {

                c1 = Class.forName("reflect.construction.Person");

                Class<?> c = c1.getSuperclass();

                System.out.println(c.getName());

      

            } catch (ClassNotFoundException e) {

                e.printStackTrace();

            }

        }

    }

    取得全部构造函数

    import java.lang.reflect.Constructor;

    public class GetConstructorDemo {

        public static void main(String[] args) {

            Class<?> c1=null;

            try {

                c1=Class.forName("reflect.construction.Person");//实例化Class对象

                Constructor<?>[] cons=c1.getConstructors();//得到全部构造方法

                for(int i=0;i<cons.length;i++){

                    System.out.println(cons[i]);//打印所以构造方法

                }

            } catch (ClassNotFoundException e) {

                e.printStackTrace();

            }

            

        }

    }

    取得类中的方法

        要取出一个类中的全部方法,可以使用Class类中的getDeclaredMethods()方法,此方法返回的是一个Method类的对象数组。而想取得方法的具体信息例如:方法参数、抛出的异常等等,就必须依靠Mehod类。

    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)                    取出本类的全部方法

                    throws NoSuchMethodException,SecurityException

    public Method[] getMethods()                                                                  取得全部方法

                     throws SecurityException

      

    public class GetMethodDemo {

        public static void main(String[] args) throws ClassNotFoundException {

            Class<?> c1=null;

            c1=Class.forName("reflect.construction.Person");

            Method m[]=c1.getMethods();

            for(int i=0;i<m.length;i++){

                System.out.println(m[i]);

            }

        }

    }

    取出类中的属性:

    依赖的方法:

    public Field[] getFields()  throws SecurityException

    public Field[] getDeclaredFields()  throws SecurityException

    public class GetFiledDemo {

        public static void main(String[] args) throws ClassNotFoundException {

            Class<?> c1=null;

            c1=Class.forName("reflect.construction.Person");

            Field f[]=c1.getFields();

            for(int i=0;i<f.length;i++)

            {

                System.out.println(f[i]);

            }

        }

    }

    通过反射调用类中的方法

        在正常情况下一个类对象产生后就可以直接调用类中的方法了.如果要调用的话肯定必须清楚的指定调用的方法名是什么,之后通过Class 中的getMethod()方法。

    public Method getMethod(String name, Class<?>... parameterTypes)

                       throws NoSuchMethodException, SecurityException

    该方法得到的Method对象,之后通过此Method对象来执行方法,但是在调用的时候因为会涉及到参数的问题,所以通过getMehod()取得的时候需要要设置好对应的参数类型。

    比如调用Person中sayChina()方法,因为该方法中没有任何参数,所以只需要调用Method 中invoke()方法。

    public Object invoke(Object obj,Object... args)
                    throws IllegalAccessException,IllegalArgumentException,InvocationTargetException

    执行的时候需要还需要传递参数进去, 而且需要实例化对象。

    public class InvokeSayChinaDemo {

        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

            Class<?> c1=null;

            c1=Class.forName("reflect.construction.Person");//实例化Class对象

            Method met=c1.getMethod("sayChina");//找到sayChina()方法

            met.invoke(c1.newInstance());//调用方法

        }

    }

    调用有参数的方法

    public class InvokeSayChinaDemo {

        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {

            Class<?> c1=null;

            c1=Class.forName("reflect.construction.Person");//实例化Class对象

            Method met=c1.getMethod("sayHello",String.class,int.class);//找到sayHello()方法

            String returnValue=(String) met.invoke(c1.newInstance(),"李占祥",24);//调用方法

            System.out.println(returnValue);

        }

  • 相关阅读:
    编写 ES6 的 7 个实用技巧
    [docker] 常用命令
    ansible 的第一次亲密接触
    [bug] JS sort 函数在 ios 中无效
    这几天bug多,自我检讨一下
    【面试】——随手收集面试问题
    Linux的五个查找命令:find,locate,whereis,which,type
    Linux下php安装Redis扩展
    mysql in 子查询 效率慢 优化(转)
    mysql group by 用法解析(详细)
  • 原文地址:https://www.cnblogs.com/yueyazhishang/p/4064191.html
Copyright © 2011-2022 走看看