java反射

java反射这个知识点,是我一直想要掌握的。但是却一直因为其他种种问题没有时间学习,昨晚浅略的学习了一下,现在写篇博文来记录学习的成果。

什么是反射?

在运行的时候(只有在运行的时候.java文件才会被编译成.clss文件),可以知道某个类的所有构造器、public修饰的成员变量、所有方法(有参、无参、继承的、实现的),动态的获取某个类的方法和属性就是反射。

反射能干嘛?

通过获取到反射对象,用这个反射对象去获取被反射类的成员变量、构造器、方法并且使用。

反射有什么用?

反射创建对象啊,当然这是最基本的,最重要的用途就是开发各种通用的框架。
比如Spring框架,由Spring容器创建Bean对象,实际上是我们把类的配置信息给到了Spring容器,Spring容器反射创建Bean

反射的原理?

JAVA语言编译之后会生成一个.class文件,反射就是通过这些个字节码文件找到某一个类、类的构造器、类实现的接口、类中的方法以及属性。
并且还能通过这个字节码文件调用被反射的方法和构造器。

反射常用对象

对象对应关系
Class被反射类对象和被反射对象实现的接口对象
Constructor被反射类的构造器
Field对应的是被反射类的成员变量
Method调用被反射类对象的某个方法

反射的精髓: invoke方法:调用反射类的某个方法。

数据准备

创建一个要被反射的类

public class Person implements PersonService{
    public String name ;
    private  Integer id ;
    public   String password;



    public Person() {
        System.out.println("Person类初始化了");
    }

    static{
        System.out.println("Person类静态代码块");
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(Integer id) {
        this.id = id;
    }

    public Person(Integer id,String name) {
        this.id = id;
        this.name = name;

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Class

获取到某个类的class对象

方式一: 通过被反射类的全限定名

 Class<?> aClass= Class.forName("com.neu.domain.Person");

这个方法传入的参数是被反射类的全限定名,此方 法 会加载 被放射类的静态方法或静态成员变量,因为这个方法是将被反射的类加载到内存并初始化该类。

Class<?>aClass2=Class.forName("com.neu.domain.Person",false,RJava.class.getClassLoader());

这个方法是上一个方法的重载,但是该方法需要多传入两个参数,第二参数时一个布尔类型,默认是true,如果是true是将被反射类加载到内存并初始化,false的话只是将被反射类加载到内存不初始化。第三个参数是当前类的类加载器。

如果同时存在这个两个方法个,只生效第一个方法。(但是谁会无聊用两个办法去创建同一个被反射类的class对象呢)

方式二:通过被反射类的类名

 Class<Person> personClass = Person.class;

这个方法并不会加载被反射类的静态方法和静态成员变量,只是将被反射类加载到内存并不执行初始化操作。

方式三:通过被反射类的对象

Person pp = new Person();
Class<?> ppClass= pp.getClass();
获取到某个类的所实现的接口
Class<?>[] interfaces =  personClass.getInterfaces();

该方法的返回结果是一个数组,如果被反射类没有实现接口,则数组为空

Constructor

获取到某个类的构造器
Constructor<?> constructor = personClass.getConstructor(Integer.class,String.class);

通过传入的类型的简单类名,获取到被反射类的相应类型的构造器,简单类名的书写顺序必须与被反射类的构造器参数类型的顺序一致

就是说,被反射的那个类,有多种构造器,但是那么多种的构造器都是通过重载来实现的,这就根据getConstructor传入的参数类型来获取到对应的构造器

getConstructor方法的参数时可变参数

调用获得的构造器方法:newInstance

Person person = (Person)constructor.newInstance(1,"张三");
System.out.println("id是:"+person.getId()+"名字是:"+person.getName());

Field

获取到某个类指定的成员变量
 Field field = personClass.getField("name");

取到被反射类所有的public修饰的成员变量

 Field[] fields = personClass.getFields();

注意: 严重注意!!!如果反射类的成员变量不是public修饰的,getField方法就不能拿到该指定的成员变量,会报错

Method

获取到某个类的方法

获取到被反射的所有方法,无参方法、有参方法、继承父类的方法,除了构造器方法不能获取

 Method[] methods = personClass.getMethods();

获得被反射类的指定方法

 Method method = personClass.getMethod("setName",String.class);

获取无参方法只需要传入方法名即可
获取有参方法传入方法名,还必须传入参数类型的简单类名

invoke

反射精髓!!!!!
反射调用类的方法

method.invoke(person,"");

invoke方法的第一个参数是一个对象,什么对象呢,就是被反射类的对象

调用这个对象的method方法(调用什么方法还得看需要获取被反射类的什么方法),传入某某参数

这个参数时可变参数,但调用无参方法时,参数就直接不写

我对反射的理解

反射嘛,就是获得到一个类的反射对象,然后通过这个反射对象,获取到被反射类的字段、方法、构造器等,并且通过反射对象去调用被反射类的字段、方法、构造器。但是只是一晚上的学习,并没有太深入的去了解反射的原理和底层,以后还是需要时间去专研反射的源码,看看里面的秘密。

最后附上昨晚学习的源代码:

public class RJava {
    public static void main(String[] args) {

        /**
         * 反射含义:
         * 在运行的时候(只有在运行的时候.java文件才会被编译成.clss文件),可以知道某个类的所有构造器、public修饰的成员变量、所有方法(有参、无参、继承的、实现的)
         * 动态的获取某个类的方法和属性就是反射。
         *
         *
         * 反射原理:
         * JAVA语言编译之后会生成一个.class文件,反射就是通过这些个字节码文件找到某一个类、类的构造器、类实现的接口、类中的方法以及属性。
         * 并且还能通过这个字节码文件调用被反射的方法和构造器
         *
         *
         * 反射的对象:
         *  Class :对应的是被反射类对象和被反射对象实现的接口对象
         *
         *  Constructor:对应的是被反射类的构造器
         *
         *  Field:对应的是被反射类的成员变量
         *
         *  Method:对应的是被反射类的方法
         *
                                                                                                                                                                                                                         *  精髓:invoke方法:调用被反射类对象的某个方法
         *
         *
         *  反射能干什么:
         *  通过获取到反射对象,用这个反射对象去获取被反射类的成员变量、构造器、方法并且使用。
         *
         *
         * 反射有什么用:
         * 反射创建对象啊,当然这是最基本的,最重要的用途就是开发各种通用的框架
         * 比如Spring框架,由Spring容器创建Bean对象,实际上是我们把类的配置信息给到了Spring容器,Spring容器反射创建Bean
         *
         */

        try {

            //获取到某个类的class对象
            //方式一:
            //传入的参数是类的权限定名
            //这个方式会 加载 被反射的类的静态方法或静态成员变量
            //这个方法是把类加载到内存,同时初始化该类,所以调用这个方法会加载类的静态代码块
           Class<?> aClass= Class.forName("com.neu.domain.Person");

            //这个方法传入的后面两个参数:
            //第一个:true -加载类到内存并且初始化类
            //第二个:当前类的类加载器
           Class<?> aClass2= Class.forName("com.neu.domain.Person",false,RJava.class.getClassLoader());

           //当这两个方法 同时存在的时候,以第一个方法优先。(但是谁会无聊用两个办法去创建同一个被反射类的class对象呢)


            //方式二:
            //这个方式并 不加载 被反射的类的静态方法或静态成员变量
            //这个方法是把类加载到内存,但是却不执行初始化操作,只是单纯的返回Class对象,所以这个调用这个方法并没有加载类的静态代码块
            Class<Person> personClass = Person.class;

            //方式三:
            //通过类的对象来获取被反射类的class对象(new一个对象当然必须会调用这个类的构造器)
          /*  Person pp = new Person();
            Class<?> ppClass= pp.getClass();*/

            System.out.println(aClass2);

            System.out.println("************");

            //获取被反射类实现的所有接口
            //如果没有实现接口则获取到空
            Class<?>[] interfaces =  personClass.getInterfaces();
            for (Class i:interfaces) {
                System.out.println("实现的接口"+i);
            }

            System.out.println("************");

            //获取到对应的构造器
            //通过传入的类型的简单类名,获取到被反射类的相应类型的构造器,简单类名的书写顺序必须与被反射类的构造器参数类型的顺序一致
            //就是说,被反射的那个类,有多种构造器,但是那么多种的构造器都是通过重载来实现的,这就根据getConstructor传入的参数类型来获取到对应的构造器
            //getConstructor方法的参数时可变参数
            Constructor<?> constructor =  personClass.getConstructor(Integer.class,String.class);
            System.out.println(constructor);


            //调用获得的构造器方法(由于是调用有参构造器,所以必须先执行无参构造器)
            //newInstance方法传入的参数时根据该构造器需要的参数而确定的
            Person person = (Person)constructor.newInstance(1,"张三");
            System.out.println("id是:"+person.getId()+"名字是:"+person.getName());

            System.out.println("************");


            //获取到被反射类指定的成员变量
            //注意:严重注意!!!如果反射类的成员变量不是public修饰的,getField方法就不能拿到该指定的成员变量,会报错
            Field field = personClass.getField("name");
            System.out.println(field);

            //获取到被反射类所有的public修饰的成员变量
            Field[] fields = personClass.getFields();
            for (Field f:fields) {
                System.out.println(f);
            }

            System.out.println("************");

            //获取到被反射的所有方法,无参方法、有参方法、继承父类的方法,除了构造器方法不能获取
            Method[] methods = personClass.getMethods();
            for (Method m:methods) {
                System.out.println(m);
            }

            System.out.println("************");

            //获得被反射类的指定方法
            //获取无参方法只需要传入方法名即可
            //获取有参方法传入方法名,还必须传入参数类型的简单类名
           Method method = personClass.getMethod("setName",String.class);
            System.out.println(method);

            System.out.println("************");

            Person p = new Person();

            //反射精髓!!!!!invoke
            //invoke方法的第一个参数是一个对象,什么对象呢,就是被反射类的对象,
            // 调用这个对象的method方法(调用什么方法还得看需要获取被反射类的什么方法),传入某某参数
            // 这个参数时可变参数,但调用无参方法时,参数就直接不写
            //因为需要这个被反射类的对象,所以这个被反射的类就被构造出来,调用了无参的构造方法
           method.invoke(person,"");
            System.out.println(person.getName());

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }


    }
}

最后附上一点额外的知识点:

泛型:

 E : Element (指定一般用于集合)
 T : Type(指定Java的某个类)
 K : Key(指定键)
 V : Value(指定值)
 N :Number(指定数值类型)
 ? : 表示不确定的java类型
 Class<?> :表示不确定类型的类
 
 这些泛型的存在是为了约束java类型,也简化了开发
 日后还需要深入去了解这些泛型的奥妙。
         *

初步探索java反射的奥妙,入门小白,还请大家指点一二。欢迎各位留言讨论,一起学习鸭。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值