JAVA--reflect(反射)

java编程之ReFlect(反射)


  • Class类的反射
  • 方法的反射
  • 成员变量的反射
  • 构造函数的反射
  • java类加载机制


    Class类的反射

  • Class类

    在面向对象的世界里,万事万物都是对象。
    java语言中,静态的成员,普通的数据类型也是对象,类的实例就是类的对象。
    那么类是谁的对象呢?
    类是对象,类是java.lang.Class类的实力对象。
    There is a class named Class

package com.imooc.ReFlectTest;
/**
*这段代码介绍了关于Class类的实例的三种创建方法
*/
public class ClassDemo1 {

    public static void main(String[] args) {
        //创建一个Dog类的实例对象
        Dog dog = new Dog();
        //Dog类也是实例对象,Dog类是Class类的实例对象
        //Class类只有private权限的构造函数,只允许jvm调用!
        //我Class类的实例对象,一共有3种表示方式

        //第一种每个类都有一个隐含的static(静态)的成员class,可以直接调用
        Class c1 = Dog.class;

        //第二种,已知一个类的实例对象,可以调用getClass()方法
        Class c2 = dog.getClass();

        /**
         * 官方上给的解释,此处的c1,c2是Dog类的(class type(类类型))
         */

        //结果是true,说明c1,c2都代表了Dog类的类类型,也说明了一个类只有一个Class类的一个实例对象
        System.out.println(c1 == c2);

        //第三种方式,调用Class类的forName方法,会有异常
        Class c3 = null;
        try {
            //方法中写入类的全称
            c3 = Class.forName("com.imooc.ReFlectTest.Dog");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //此处依然是true,还是那句话一个类只有一个Class类的实例对象
        System.out.println(c2 == c3);

        /**
         * 我们也可以通过类的类类型来创建该类的实例
         * 即我们可以用c1 or c2 or c3 来创建一个Dog类的对象
         */
        try {
            //类类型创建的类的实例是Object类型的,此处因为没有用泛型,所以我们需要进行强制类型转换
            //前提是该类要有无参数的构造方法
            Dog dog1 = (Dog)c1.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}


class Dog{}

Class.forName(“类的全称”)

  • 不仅表示类的类类型,还表示了动态加载类
  • 区分编译和运行
  • 编译时加载的类是静态加载类,运行时加载的类是动态加载类

使用反射访问类的所有信息

代码中的注释已经详细解释了他们的作用

package com.imooc.ReFlectTest;

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

public class Classutil {

    /**
     * 打印类的信息,包括类的成员函数的信息
     * obj 即类的对象,此处没用泛型,所以用多态来实现
     */
    public static void printClassMassage(Object obj) {
        //获取实际传递的obj的类类型
        Class c = obj.getClass();//存在多态,实际调用时,调用的是传递的类的方法
        //获取类的名字
        System.out.println(c.getName());
        /**
         * Method方法,用来获取类的方法名
         * 一个方法就是一个Method对象
         * getMethods()方法获取的是所有的public的函数,包括从父类继承来的
         * getDeclaredMethods()方法获取类自己声明的所有方法,不问访问权限
         */
        Method[] methods =  c.getMethods();//c.getDeclaredMethods();

        for(int i=0; i<methods.length; i++) {
            //输出方法的名字
            System.out.print(methods[i].getName() + "(");
            //通过方法,获取方法的参数列表
            //getParameterType()方法,获取参数列表的类型的类类型
            Class[] parameterType = methods[i].getParameterTypes();
            //依次打印方法的参数列表
            for (Class class1 : parameterType) {
                System.out.print(class1.getName() + ",");
            }
            System.out.println(")");


        }

    }

    public static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        /**
         * 获取类的成员变量的信息
         * 用java.lang.reflect.Field
         * Field封装了关于类的成员变量的所有操作
         * getFileds()方法获取所有权限为public的成员变量的信息
         * getDeclaredFileds()方法获取的是该类自己声明的变量的信息
         */

        Field[] fileds = c.getDeclaredFields();

        for (Field field : fileds) {
            //得到成员变量的类型的类类型
            Class fieldType = field.getType();
            //typeName,成员变量的名字,即变量名
            String typeName = fieldType.getName();
            //fieldName,变量的类类型的名字,即变量的类型名(例:int,String)
            String fieldName = field.getName();

            System.out.println("typeName = " + typeName + " " +"fieldName = "+ fieldName);
        }
    }

    public static void printConMessage(Object obj) {
        Class c = obj.getClass();
        //获取所有的public的构造方法
        //Constructor[] cs = c.getConstructors();
        //获取当前类内的所有的构造方法Constructor
        Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            System.out.print(constructor.getName() + "(");
            Class[] parameter = constructor.getParameterTypes();
            for (Class class1 : parameter) {
                System.out.print(class1.getName() + ",");
            }
            System.out.println(")");
        }
    }
}

通过上述代码的方法,我们可以访问任意一个类的名称以及它的所有方法的名称,参数列表以及返回值,包括构造函数!
当然除了上述的三种访问以外,reflect中还封装了很多很好的方法,我们可以在需要的时候,去查阅java.lang,Class的API


通过获取的类信息,可以做反射操作

我们通过获取的类的信息,可以方法调用对象

package com.imooc.ReFlectTest;

import java.lang.reflect.Method;

public class ClassDemo5 {

    public static void main(String[] args) {

        A a1 = new A();
        //获取方法的信息的前提是获取类的信息,获取类的信息要先获取类的类类型
        Class c = a1.getClass();

        try {
            /**
             * 获取方法,由名称和参数列表来决定
             * getMethod()获取public的方法
             * getDeclaredMethod()获取自己声明的方法
             */
            Method m = c.getMethod("print", int.class, int.class);
            //方法的反射调用,利用m对象进行方法的调用invoke()方法,和a1.print()的效果完全相同
            //invoke(obj, new Object[])
            //方法无返回值,则返回null,否则返回方法的返回值 
            Object o = m.invoke(a1, new Object[]{10,20});
//          Object o = m.invoke(a1, 10,20);
            System.out.println("================================");
            Method m1 = c.getMethod("printStr", String.class, String.class);
            //用方法进行反射操作
//          a1.printStr("Hello", "World");
            m1.invoke(a1, "hello", "World");
            System.out.println("=================================");
            //方法没有参数
            //方法1 ,传一个空的类类型数组
//          Method m2 = c.getMethod("print", new Class[]{});
            //方法2,不穿参数也可以
            Method m2 = c.getMethod("print");
//          m2.invoke(a1, new Object[]{});
            m2.invoke(a1);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class A {
    public void print(int a, int b) {
        System.out.println(a + b);
    }

    public void printStr(String a, String b) {
        System.out.println(a.toUpperCase() + "," + b.toUpperCase());
    }
}

通过反射我们可以理解集合泛型的本质

泛型的目的是为了防止输入错误,但只在编译时有效。

package com.imooc.ReFlectTest;

import java.awt.event.FocusEvent;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ClassDemo6 {

    public static void main(String[] args) {
        List l1 = new ArrayList();
        List<String> l2 = new ArrayList<String>();

        Class c1 = l1.getClass();
        Class c2 = l2.getClass();
        //结果为true
        System.out.println(c1 == c2);


        l2.add("hello");
        //String类型的List不能添加int型的数,编译时无法通过
//      l2.add(20);

        /**
         * 反射的操作都是编译之后的操作
         * c1 == c2 返回值为true说明编译之后的集合是“去泛型化”的
         * java集合中的泛型,是防止错误输入的,只在编译阶段有效
         * 当我们绕过编译时,泛型就无效了
         * 验证:通过方法的反射操作,绕过编译
         */

        try {
            Method m = c2.getMethod("add", Object.class);
            m.invoke(l2, 20);
            System.out.println(l2.size());
            System.out.println(l2);

            /*
             * 不能使用foreach循环,会出异常
             * for (String string : l2) {
             *      System.out.println(string);
             * }
             */

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值