欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java 反射原理详解及使用反射解决的问题

程序员文章站 2022-04-12 18:38:05
public class Person { public int age; public String name; @Override public String toString() { return "Person{" + "age=" + age + ", name='" + name + '\'' + '}'; } publ......

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

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的实例之后,我们可以做如下操作

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

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

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

如果觉得这篇文章对你有小小的帮助的话,多多支持网站

原文地址:https://blog.csdn.net/qq_42000661/article/details/108245585