java-反射

2 篇文章 0 订阅

反射:框架设计的灵魂

  • 框架:办成品的软件。可以在框架的基础上进行软件的开发 ,简化代码
  • 反射:将类的各个组成部分封装为其他的对象,这就是反射机制
    • 好处:可以在运行程序的过程中操作对象,比如在IDEA中的方法提示就是通过反射去实现的,IDEA程序在运行着,去将加载到内存中的方法调用其class 类对象的 获取方法名称的方法就可以把方法列出来
    • 可以解耦合,提高程序的可扩展性

在这里插入图片描述

分析:

  • xxx.java 通过javac编译出行 xxx.class
  • xxx.class 文件比较重要的组成部分 成员变量 构造方法 成员方法 (Source源代码阶段)
  • jvm 通过类加载器加载(ClassLoader对象)将xxx.class 文件加载到内存中 class 对象 (用来描述xxx.class文件)
  • class 类对象的组成部分 成员变量 Field[] fields对象 构造方法 Constructor[] cons 成员方法Method[] methods
  • class 类对象可以对类进行初始

获取class对象的方式

Person.java
package entiy;

public class Person {
    private String name;

    private int age;

    public Person() {}

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

    public String getName() {return name;}

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

    public int getAge() {return age;}

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  1. Class.forName(“全类名”) //当在Person.class 还没有加载到内存中的时候使用这种方法获取class 对象

    *多使用于将全类名放在配置文件,读取文件加载类

    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> aClass = Class.forName("entiy.Person");
        System.out.println(aClass);//class entiy.Person
    }
    
  2. Person.class //在Person.class 已经加载到内存中的时候使用这种方式获取class 对象

    *使用于参数的传递

     Class<Person> personClass = Person.class;
     System.out.println(personClass);//class entiy.Person
    
  3. personObj.getClass() //在有person 对象的时候通过getClass方法获取

    用于获取字节码文件

    Person person = new Person();
    Class<? extends Person> personClass = person.getClass();
    System.out.println(personClass);//class entiy.Person
    
    分析
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> personClass1 = Class.forName("entiy.Person");
            System.out.println(personClass1);//class entiy.Person
    
            Class<Person> personClass2 = Person.class;
            System.out.println(personClass2);//class entiy.Person
    
            Person person = new Person();
    
            Class<? extends Person> personClass3 = person.getClass();
            System.out.println(personClass3);//class entiy.Person
    
            System.out.println(personClass1==personClass2);//true
            System.out.println(personClass1==personClass3);//true
    
        }
    /**
    *	对于同一个字节码文件.class在一次程序运行的过程中只会被加载一次,不论通过那种方法获取到的class对象都是同一个
    **/
    

使用Class 对象的功能

  • Persion.java

  • public class Person {
        private String name;
    
        private int age;
    
        private String a;
        protected String b;
        String c;
        public String d;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

获取成员变量对象Field

  • Field[] getFields() //获取所有pulic修饰的成员变量

  •     public static void main(String[] args) throws Exception {
            Person person = new Person();
            //获取person class 对象
            Class<? extends Person> personClass = person.getClass();
    		//获取Person 类对象的所有public修饰的成员变量
            Field[] fields = personClass.getFields();
    		
            for (Field field : fields) {
                System.out.println(field);//
            }
      }
    
  • Field getFields(String name) //获取指定 名称的成员变量对象

  •  public static void main(String[] args) throws Exception {
            Person person = new Person();
            //获取person class 对象
            Class<? extends Person> personClass = person.getClass();
    		//获取public 修饰的d成员变量
            Field dField = personClass.getField("d");
            //获取person对象成员变量的属性值
            Object dValue = dField.get(person);
            //null  因为person对象d变量没有初始化
            System.out.println(dValue);
            //给person对象的成员变量设置值
            dField.set(person,"d的值");
            //输出结果:d的值  因为使用 dField.set(person,"d的值");给person对象的d成员变量设置值了
            System.out.println(dField.get(person));
        }
    
  • Field[] getDeclaredFields() throws SecurityException //获取所有的成员变量对象

  • public static void main(String[] args) throws Exception {
            Person person = new Person();
            //获取person class 对象
            Class<? extends Person> personClass = person.getClass();
        
    		//获取任意修饰符号的成员变量对象
            Field[] declaredFields = personClass.getDeclaredFields();
    
            for (Field declaredField : declaredFields) {
                System.out.println(declaredField);
            }
            /**
             * private java.lang.String entiy.Person.name
             * private int entiy.Person.age
             * private java.lang.String entiy.Person.a
             * protected java.lang.String entiy.Person.b
             * java.lang.String entiy.Person.c
             * public java.lang.String entiy.Person.d
             */
    
        }
    
  • Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException //获取任意修饰符的指定名称的成员变量对象

  • public static void main(String[] args) throws Exception {
            Person person = new Person();
            //获取person class 对象
            Class<? extends Person> personClass = person.getClass();
        
    		//获取name成员变量对象
            Field nameField = personClass.getDeclaredField("name");
            /**
             * name属性不是public 没有这个操作的话 会抛出  java.lang.IllegalAccessException
             * nameField.setAccessible(true)  这种方式叫暴力反射
             */
            nameField.setAccessible(true);
            //null
            System.out.println(nameField.get(person));
            //为person 对象name 设置值
            nameField.set(person,"小神");
            //小神
            System.out.println(nameField.get(person));
        }
    

获取构造方法对象Constructor

  • Constructor<?>[] getConstructors() throws SecurityException //获取字节码文件对象的所有public 修饰的构造方法

  •     public static void main(String[] args) throws Exception {
            //获取person class 对象
           Class<Person> personClass = Person.class;
    
            //获取public 修饰的所有构造方法对象
            Constructor<?>[] constructors = personClass.getConstructors();
    
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor);
            }
            /**
             * public entiy.Person()
             * public entiy.Person(java.lang.String,int)
             */
        }
    
  • Constructor getConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException//获取的指定的public的构造方法

  •  public static void main(String[] args) throws Exception {
            //获取person class 对象
            Class<Person> personClass = Person.class;
    
            //获取public无参的构造方法对象
            Constructor<? extends Person> constructor1 = personClass.getConstructor();
    
            //public entiy.Person()
            System.out.println(constructor1);
         
            //获取public 指定参数列表的  操作方法对象
            Constructor<? extends Person> constructor2 = personClass.getConstructor(String.class, int.class);
    
            //public entiy.Person(java.lang.String,int)
            System.out.println(constructor2);
        } 
    

    使用构造函数对象 创建实例对象

            //使用constructor1  无参数的构造方法对象进行person对象的创建
            Person person1 = constructor1.newInstance();
    
            //Person{name='null', age=0}
            System.out.println(person1);
    
            //使用constructor2  有参数的构造方法对象进行person对象的
    
            Person person2 = constructor2.newInstance("小神", 1);
    
            //Person{name='小神', age=1}
            System.out.println(person2);
    
  • Constructor<?>[] getDeclaredConstructors() throws SecurityException //获取所有的构造方法对象

  •  public static void main(String[] args) throws Exception {
            //获取person class 对象
            Class<Person> personClass = Person.class;
    		
         	//获取所有的构造方法对象
            Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
    
            for (Constructor<?> declaredConstructor : declaredConstructors) {
                System.out.println(declaredConstructor);
            }
            /**
             * public entiy.Person()
             * public entiy.Person(java.lang.String,int)
             */
        } 
    
  • Constructor getDeclaredConstructor(Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

    //获取指定参数列表的构造方法对象

  •  public static void main(String[] args) throws Exception {
            //获取person class 对象
            Class<Person> personClass = Person.class;
    		
            //获取指定的参数构造方法对象
            Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class,int.class);
    
            //public entiy.Person(java.lang.String,int)
            System.out.println(declaredConstructor);
        } 
    
  • 注意:

    • 当想使用非public的构造方法进行对象的创建的时候 需要调用 ConstructorObj.setAccessible(true) 进行暴力反射

    • 在获取字节码文件对象只会 可以直接调用 objClass.newInstance() 使用无参数构造方法对象进行实例的创创建

    •  public static void main(String[] args) throws Exception {
              //获取person class 对象
              Class<Person> personClass = Person.class;
      		//使用无参数的构造方法对象进行初始
              Person person = personClass.newInstance();
          } 
      

获取成员方法对象 Method

  • Method[] getMethods() throws SecurityException //获取所有的public的成员方法(包括继承得来的)

  •  public static void main(String[] args) throws Exception {
            Person personObj = new Person();
    
            //获取Person Class对象
            Class<? extends Person> personClass = personObj.getClass();
    
            //获取personClass 所有的public 修饰的成员方法对象
            Method[] methods = personClass.getMethods();
    
            for (Method method : methods) {
                System.out.println(method);
            }
            /**
             * public java.lang.String entiy.Person.toString()
             * public java.lang.String entiy.Person.getName()
             * public void entiy.Person.setName(java.lang.String)
             * public int entiy.Person.getAge()
             * public void entiy.Person.setAge(int)
             * public final void java.lang.Object.wait() throws java.lang.InterruptedException
             * public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
             * public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
             * public boolean java.lang.Object.equals(java.lang.Object)
             * public native int java.lang.Object.hashCode()
             * public final native java.lang.Class java.lang.Object.getClass()
             * public final native void java.lang.Object.notify()
             * public final native void java.lang.Object.notifyAll()
             */
        }
    
  • Method getMethod(String name, Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException

    获取指定的名称和参数列表的public修饰的对象

     public static void main(String[] args) throws Exception {
            Person personObj = new Person();
    
            //获取Person Class对象
            Class<? extends Person> personClass = personObj.getClass();
    
    
            //获取personClass的 getName 方法对象
            Method getNameMethod = personClass.getMethod("getName");
    
            //public java.lang.String entiy.Person.getName()
            System.out.println(getNameMethod);
    
            //通过getName方法对象(Method) 来执行personObj 对象的getName方法
            Object name = getNameMethod.invoke(personObj);
    
            //null
            System.out.println(name);
    
            //获取personClass的 setName 方法对象
            Method setNameMethod = personClass.getMethod("setName", String.class);
    
            //通过setName方法对象(Method)   来执行personObj 对象的setName方法
            setNameMethod.invoke(personObj,"小神");
    
            //小神
            System.out.println(getNameMethod.invoke(personObj));
        }
    
    • Object invoke(Object obj, Object… args) 用于对成员变量方法的执行
  • Method[] getDeclaredMethods() throws SecurityException //获取所有的成员方法对象

    	   //获取所有的成员方法对象
            Method[] declaredMethods = personClass.getDeclaredMethods();
    
            for (Method declaredMethod : declaredMethods) {
                System.out.println(declaredMethod);
            }
    
  • Method getDeclaredMethod(String name, Class<?>… parameterTypes) //

  •  		//获取指定名称和参数列表的成员方法对象
            Method getNameDeclaredMethod = personClass.getDeclaredMethod("getName");
    
            Method setNameDeclaredMethod = personClass.getDeclaredMethod("setName", String.class);
    

    注意:

    • 在使用 Method 的 invoke 方法调用 对象的方法的时候,当方法不是 public 的时候 需要先调用 setAccessible(true) 进行暴力反射 然后才可以调用

获取类名

  •     public static void main(String[] args) throws Exception {
            Class<Person> personClass = Person.class;
            System.out.println(personClass.getName());
        }
    

反射的的小dome

说明

  • 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
  • 在程序中去加载配置文件
  • 使用反射技术将类文件加载进内存
  • 创建对象
  • 调用方法

准备工作

  1. 在entiy 包下创建 一个Student类

    package entiy;
    
    public class Student {
        public void  sleep(){
            System.out.println("睡觉...");
        }
    }
    
  2. 在src 目录下创建一个pro.properties 文件

    classPath="entiy.Student"
    methodName="sleep"
    

具体实现

public class ReflexTest {
    public static void main(String[] args) throws Exception{
        //1 加载配置文件
        Properties properties = new Properties();

        //获取reflexTestClass的类文件对象
        Class<ReflexTest> reflexTestClass = ReflexTest.class;

        /**
         * 获取类加载器  因为在执行程序的时候 ReflexTest.class会被ClassLoader加载到内存中
         * 因为 ReflexTest.java 和 pro.properties 文件都是在src 下的所以可以使用加载ReflexTest.class 的ClassLoader 去加载资源文件
         *
         */
        //获取reflexTestClass的类加载器
        ClassLoader classLoader = reflexTestClass.getClassLoader();
        //获取 pro.properties  输入流
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");

        //加载配置文件
        properties.load(resourceAsStream);

        String classPath = properties.getProperty("classPath");

        String methodName = properties.getProperty("methodName");

        System.out.println(classPath);
        System.out.println(methodName);

        //关闭输入流
        resourceAsStream.close();

        //加载Student 的类字节码文件生成字节码文件   对象
        Class<?> studentClass = Class.forName(classPath);

        //获取sleep方法对象
        Method sleepMethod = studentClass.getDeclaredMethod(methodName);

        //暴力反射  在这里其实不需要因为 sleep 方法是publlic 的
        sleepMethod.setAccessible(true);

        //创建Student 对象
        Student studentObj=new Student();

        //执行 studentObj 的sleep 方法
        sleepMethod.invoke(studentObj);
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值