反射原理详解

一、通过反射获取对象,并操作属性

public class Person {

    public int age;

     public String name;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/*
    反射第一步:获取Class类的对象
 */
public class ReflectionTest {

    @Test
    public void test1() {
        Person person = new Person();
        person.setName("aa");
        person.setAge(11);
        System.out.println(person);
    }


//  有了反射,可通过反射创建一个类的对象,并且可以调用其中的方法和属性
    @Test                    //  此为类找不到异常
    public void test() throws Exception{

        //正常获取对象方法
        Person person = new Person();
        System.out.println(person);
        
        
        //通过反射获取对象方法!!!
        //1、获取的是Class类的对象,而不是Person类的对象(Class是类类,不是类)
        Class<?> personClass = Class.forName("com.gr.Person");
        //2、通过反射创建出Person类的对象(如果不转换,他是一个Object对象)
        Person o = (Person) personClass.newInstance();
        System.out.println(personClass);


        //3、通过反射调用运行时类的属性
        Field name = personClass.getField("name");   //只能获取public修饰的属性
        //为o这个对象的name属性赋值
        name.set(o,"姓名");
        //getDeclaredField是可以获取一个类的所有字段.
        //getField只能获取类的public 字段.
        Field age = personClass.getDeclaredField("age");
        //    在Java中可以通过反射进行获取实体类中的字段值,当未设置Field的setAccessible方法为true时,会在调用的时候进行访问安全检查,会抛出异常.
        //将此对象的accessible标志设置为指示的布尔值。true的值表表示反射对象应该在使用时抑制Java访问检查。false表示反映的对象应该强制执行Java访问
        //检查
        age.setAccessible(true);
        age.set(o,23);



    }
}

 

二、通过反射获取并调用方法

public class Person {

    public int age;

     public String name;

     public void show(){
         System.out.println("this is show method");
     }


    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/*
    反射第一步:获取Class类的对象
 */
public class ReflectionTest {

    @Test
    public void test1() {
        Person person = new Person();
        person.setName("aa");
        person.setAge(11);
        System.out.println(person);
    }


//  有了反射,可通过反射创建一个类的对象,并且可以调用其中的方法和属性
    @Test                    //  此为类找不到异常
    public void test() throws Exception{

        //正常获取对象方法
        Person person = new Person();
        System.out.println(person);


        //通过反射获取对象方法!!!
        //1、获取的是Class类的对象,而不是Person类的对象(Class是类类,不是类)
        Class<?> personClass = Class.forName("com.gr.Person");
        //2、通过反射创建出Person类的对象(如果不转换,他是一个Object对象)
        Person o = (Person) personClass.newInstance();


        //通过反射获取并调用方法
        //  如果方法有参数,就在“show”后面加,参数
        Method showmethod = personClass.getMethod("show");
        //如果有参数就在o后面加,参数
        showmethod.invoke(o);


    }
}

 

三、通过反射获取并调用有参方法

public class Person {

    public int age;

     public String name;

     public void run(int a,String str){
         System.out.println("a="+a+"and string"+str);
     }

     //     用于反射调用方法时候使用
     public void show(){
         System.out.println("this is show method");
     }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
/*
    反射第一步:获取Class类的对象
 */
public class ReflectionTest {

    @Test
    public void test1() {
        Person person = new Person();
        person.setName("aa");
        person.setAge(11);
        System.out.println(person);
    }


//  有了反射,可通过反射创建一个类的对象,并且可以调用其中的方法和属性
    @Test                    //  此为类找不到异常
    public void test() throws Exception{

        //正常获取对象方法
        Person person = new Person();
        System.out.println(person);


        //通过反射获取对象方法!!!
        //1、获取的是Class类的对象,而不是Person类的对象(Class是类类,不是类)
        Class<?> personClass = Class.forName("com.gr.Person");
        //2、通过反射创建出Person类的对象(如果不转换,他是一个Object对象)
        Person o = (Person) personClass.newInstance();

        //反射调用有参方法
        Method showmethod1 = personClass.getMethod("run",Integer.class,String.class);
        showmethod1.invoke(o,123,"string类型");



    }
}

 

提出问题:为什么要通过3方法来这么麻烦的进行属性赋值,而不是简单的o.setAge(12);???(看楼下=====处代码)

//  有了反射,可通过反射创建一个类的对象,并且可以调用其中的方法和属性
    @Test                    //  此为类找不到异常
    public void test() throws Exception{

        //正常获取对象方法
        Person person = new Person();
        System.out.println(person);
        
        
        //通过反射获取对象方法!!!
        //1、获取的是Class类的对象,而不是Person类的对象(Class是类类,不是类)
        Class<?> personClass = Class.forName("com.gr.Person");
        //2、通过反射创建出Person类的对象(如果不转换,他是一个Object对象)
        Person o = (Person) personClass.newInstance();
        System.out.println(personClass);
//   =============  提出一个问题:为什么要通过3方法来这么麻烦的进行属性赋值,而不是简单的
//           o.setAge(12);???
//        答:因为楼上是在编译时就进行了加载,而楼下可以在编译时不去确定他要获取什么,可以通过 //        楼下方式来在运行时进行特性方法的加载。


        //3、通过反射调用运行时类的属性
        Field name = personClass.getField("name");   //只能获取public修饰的属性
        //为o这个对象的name属性赋值
        name.set(o,"姓名");
        //getDeclaredField是可以获取一个类的所有字段.
        //getField只能获取类的public 字段.
        Field age = personClass.getDeclaredField("age");
        //    在Java中可以通过反射进行获取实体类中的字段值,当未设置Field的setAccessible方法为true时,会在调用的时候进行访问安全检查,会抛出异常.
        //将此对象的accessible标志设置为指示的布尔值。true的值表表示反射对象应该在使用时抑制Java访问检查。false表示反映的对象应该强制执行Java访问
        //检查
        age.setAccessible(true);
        age.set(o,23);



    }

 

总结:

获取Class对象的几种方式

    public  void test3() throws Exception{
        //1、调用运行时类本身的.class属性
        Class personClass = Person.class;
        System.out.println(personClass);
        //2、通过运行时类的对象获取
        Person person = new Person();
        Class aClass = person.getClass();
        System.out.println(aClass);
        //3、通过Class的静态方法来获取,体现了反射的动态性
        String name = "com.gr.Person";         //包名+类名的全路径
        Class aClass1 = Class.forName(name);
        System.out.println(aClass1);
        //4、通过类加载器获取        获取当前类对象,再用ClassLoader加载器加载
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class aClass2 = classLoader.loadClass(name);
        System.out.println(aClass2);
    }

            java.lang.Class是反射的源头。

  1. 我们创建一个类,通过编译(javac.exe)生成字节码文件.class文件,之后我们使用java.exe加载(JVM的类加载器完成的)                                                                                                                                                                                      *bootstap   ClassLoader是引导类加载器,用c++编写的,是JVM自带的类加载器,负责java平台核心库,用来加载核心类库。该加载器无法直接获取。                                                                                                                                     *Extension ClassLoader是扩展类加载器:负责jre/lib/ext目录下的jar包装入工作库                                                        *System ClassLoader是负责java-classpath所有目录下的类包装入类库最常见的加载器
  2. 此.class文件加载到内存中去以后,就是一个运行时类,存在缓冲区,那么这个运行时类本身就是Class的实例
  3. 每个运行时类只加载一次
  4. 有了Class的实例之后,我们可以做如下操作

                 *创建对应的运行时类的对象

                 *获取对应的运行时类的属性,方法,构造方法,父类,所在的包,异常,接口等

                 *调用对应的运行时类的属性,方法,构造方法等

 

 

 

 

个性签名:一个人在年轻的时候浪费自己的才华与天赋是一件非常可惜的事情

        如果觉得这篇文章对你有小小的帮助的话,记得在左下角点个“👍”哦,博主在此感谢!

 

万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾! 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值