零基础入门学反射

1.首先我们来认识一下什么叫做动态语言:我们知道,程序一旦运行起来,他的结构就是固定的,很难对他的结构做出修改,对于有些语言这是一件不可能完成的事情,比如C/C++,能够完成这一操作的语言叫做动态语言:其中代表有JavaScript,Python等,就可以完成这一操作,即使在程序运行的时候依然可以改变程序的结构。java是向这种语言的过度语言,不能说他是动态语言,但是Java确实可以支持这种机制,所以他可以叫做准动态语言。java通过反射机制来支持这一操作,反射有利有弊。反射虽然可以方便我们使用,但是会拖慢程序的运行速度。我们来看看java的反射

2.考虑一个问题:有没有这样一种东西,可以根据我们指定的东西来创建对象/调用函数/操作函数的属性。当然了,你可能认为这有何难,不就是动态的创建对象吗?很简单啊。但是请你先保留这一观点继续看下去。

3.首先我们来看一下什么叫做java的反射。JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。知道了这些,我们首先来反射一下,看看可不可以实现相应的操作.

package Reflection;

import static java.lang.Class.forName;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class demo01 {
 static private String path="test.user";/*首先我们把需要反射的类的路径写成一个成员变量,我们这里只是演示,所以你可以简单的写一个静态的路径,但是在实际的应用中这条路径完全可以从外界获取,然而这里面的操作依然是成立的,所以这就体现了反射的动态性。*/
public static void main(String[] args)
{
    //调用Class方法中的Forname方法产生一个Class的对象,这个对象是统配的
   //这个类就像一面镜子一样可以反射出原来类的所有信息。
    try
    {
        Class c=Class.forName(path);
        //通过反射获取类的名字.这个是带有包名的
        System.out.println(c.getName());
        //这个不带有包名
        System.out.println(c.getSimpleName());
        //获取相关的属性,方法,构造器
        //1.获取相关的属性。注意,这里有两个方法
        /*
         * 这个方法只能返回public属性
         */
        Field[]field=c.getFields();
        System.out.println(field.length);
        //如果返回所有的属性就要使用这个:
        Field [] l=c.getDeclaredFields();
        for(Field temp:l)
        {
            System.out.println(temp);
        }
        /*
         * 获取相关的方法信息:其实都是一样,只需要将Field换成:Method即可
         * 由于user里面的方法都是public所以getMethod()都可以获取到。
         * 如果获取所有的方法,那么就是:getDeclaredMethods
         * 还可以通过方法名直接获取相关的方法
         */
        Method []m=c.getMethods();
        for(int i=0;i<m.length;i++)
        {
            System.out.println(m[i]);
        }
        Method []m1=c.getDeclaredMethods();
        /*
         * 获取相关的构造器的信息
         * 方法和上边的一样
         * 如果想要获取指定参数类型的构造器,只需要给方法传递对应的参数信息就好
         */
        Constructor []constructor=c.getDeclaredConstructors();
        
        
    } catch (ClassNotFoundException e)
    {
        // TODO Auto-generated catch block
        System.out.println("the path is wrong");
    }

    }

}

4.上边的操作我们只是简单的获取了一被反射的类的一些属性,方法。其实我们可以感受到,反射,就像他的名字一样,类似于一面镜子,通过这面镜子,被反射的类的所有信息都可以被获取。同样,通过这面镜子,我们作于这个类的所有操作都会起作用。下面我们来看一下。如何通过反射来动态的加载类,创建对象,调用方法,操作属性。

package Reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import test.user;
public class Demo02 {
private static String path="test.user";
    /*
     * 通过反射得到的对象动态的操作对象的构造器,方法,属性
     */
    public static void main(String[] args) throws Exception
    {

        //首先通过反射动态的构造对象
        @SuppressWarnings("unchecked")
        Class<user> c=(Class<user>)Class.forName(path);
        try {
            user u=(user)c.newInstance();
            System.out.println(u);
            Constructor<user>u1=c.getDeclaredConstructor(int.class,int.class,String.class);
            u1.newInstance(1,1,"yg");
            System.out.println(u1.getName());
            /*
             * 接下来使用反射API来调用函数
             */
            @SuppressWarnings("unused")
            user u2=c.newInstance();
            //直接使用对象调用方法来设置函数
            u2.setName("yg");
            
            //但是既然有了反射机制,我们采用反射来调用该方法
            //获取到该方法
            Method m=c.getMethod("setName", String.class);
            //激活该方法
            m.invoke(u2, "yg");//这个方法默认是两个参数,第一个是对象,表示当前激活的到底是那个
                                //对象,第二个草书就是被激活的方法需要传递的参数。
            //好处:从上边的动态调用我们可以看出来:由于getMethod中间有一个参数是setName()
            //也就是方法的名字,这个参数决定了到底调用哪一个方法,所以会根据传来的信息的不同而调用
            //不同的函数,这就是动态语言的影子。这也就是反射的好处
            /*
             * 以上是动态的加载方法,动态的调用构造器,下面我们来看动态的操作属性
             */
            //首先我们要深刻的理解反射,并且充分的用到这一原理
            user u3=c.newInstance();
            //首先通过反射获取到该属性
            Field f=c.getField("name");
            //调用set方法来设置属性的值。首先需要注意的是set方法的两个参数:对象,,属性的值
            f.set(u3, "yg");
            //其实这里面和调用函数的方式如出一辙,首先是通过反射API函数动态的获取到方法/属性,之后
            //再调用这个方法的值来操作对应的东西,都是一个动态的思想,其中反射就像一面镜子,通过这面
            //镜子我们可以看到原来的类中的所有的东西。我们的操作也可以具有反射的效果,作用到相关的
            //对象上去。
            /*
             * 反射机制对于私有方法的处理:在面向对象中,我们知道对象的私有方法只是自己的成员内部使用
             * 外部不能访问,私有的函数也是只有自己内部可以调用,外部无法调用,但是反射机制对于这个问题2
             * 给出了处理。以上题为例:虽然我们通过set()方法给u3的属性设置了对应的值,但是依然无法访问
             * 这个如果我们希望访问到这一元素,那么可以采用反射机制提供的一些手段来打破封装
             *             
             * */
            user u4=c.newInstance();
            //首先通过反射获取到该属性
            Field f1=c.getField("name");
            //调用set方法来设置属性的值。首先需要注意的是set方法的两个参数:对象,,属性的值
            f1.setAccessible(true);//跳过安全检查的阶段。这个方法对于私有方法,私有构造器都适用
            f1.set(u4, "yg");
            u4.getName();
            f1.get(u4);
        } catch (InstantiationException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_41863129/article/details/81380921
今日推荐