java反射

反射机制
类加载:

当一个程序要使用某个类时,如果类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化,如果不发生意外,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或类初始化。
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息和动态调用对象的方法的功能称为java语言反射机制。
优点:可以在程序运行过程中,操作这些对象,动态加载类,可以解耦,提高代码灵活性。(反射是框架的灵魂)
缺点:反射相当于一系列解释操作,通知JVM要做的事,性能比直接的java代码要慢的多,并且动态操作改变类的属性同时增加安全隐患。
框架是半成品软件,可以在框架的基础上进行软件开发,简化编码。
反射将类的各个组成部分封装为其他对象,这就是反射机制。

获取class对象的方式:
1,Class.forName(“全类名”):将字节码文件加载到内存中,返回class对象多用于配置文件,将类名定义在配置文件中,读取文件,加载类。
2,类名.class:通过类名属性class获取,多用于参数的传递。
3,对象.getClass():getClass()方法在Object类中定义,多用于对象获取字节码的方式。
结论:同一个字节码文件(*class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

第一种情况:

package com.wzc;

public class Student {
}

package com.wzc;

public class Person {
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", 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;
    }

    public Person(){

    }
}

 

package com.wzc;
//获取字节码Class对象的三种方式
public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {
//        Class.forName("全类名"):将字节码文件加载到内存中,返回Class对象。
//        Class.forName("全类名")
        Class aClass = Class.forName("com.wzc.Person");
        System.out.println(aClass);
//        类名.class:通过类名的属性class获取
        Class personClass = Person.class;
        System.out.println(personClass);
//        对象.getClass():getClass()方法在Object类中定义着
        Person p = new Person();
        Class aClass1 = p.getClass();
        System.out.println(aClass1);
//        比较这三个对象,如果都是true,说明三者指向同一个对象
        System.out.println(aClass == aClass1);
        System.out.println(aClass == personClass);
          Class studentClass = Student.class;
        System.out.println(studentClass == aClass);
//        每个字节码文件所对应的类对象都不相同
          }
        }
//        得出结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次
//        不论哪种方式获取的Class对象都是同一个

Class对象功能:

获取功能:
获取成员变量们

                Field[] getFields():获取所有public修饰的成员变量
Field getField(String name):获取指定名称的public修饰的成员变量
Field[] getDeclaredFields()
Field getDeclaredField(String name)
获取构造方法们
Constructor <>[] getConstructors()
Constructor<> get Constructor(类<>…parameterTypes)
Constructor <>[] getDeclaredConstructor(类<> …parameterTypes)
Constructor<> getDeclaredConstructors()
获取成员方法们
Method[] getMethods()
Method getMethod(String name,类<>… parameterTypes)
Method[] getMethods()
Method getMethod(String name,类<>… parameterTypes)
获取类名
String getName()
获取成员变量:

 

package com.wzc;

public class Person {
    private String name;
    private int age;
    public String a;
    protected String b;
    String c;
    private String d;

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

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

    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;
    }

    public Person(){

    }
}

 

package com.wzc;

import java.lang.reflect.Field;

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception{
        //    1.获取Person的Class对象
        Class PersonClass  = Person.class;
//    获取成员变量们
        Field[] fields = PersonClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("----------------");
        Field field1 = PersonClass.getField("a");
//        Field :成员变量 操作:1,设置值 2,获取值 3,暴力反射
//        获取成员变量a的值
        Person p = new Person();
       Object value =  field1.get(p);
        System.out.println(value);
//        设置a的值
        field1.set(p,"wang");
        System.out.println(p);
        System.out.println("-----------------");
//      Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = PersonClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
//       Field[] getDeclaredFields(String name):
        Field d = PersonClass.getDeclaredField("d");
//        忽略访问权限修饰符的安全检查
//        使用暴力反射
        d.setAccessible(true);
        Object o = d.get(p);
        System.out.println(o);
    }
}

获取构造方法们:

package com.wzc;

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

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception{
        //    1.获取Person的Class对象
        Class PersonClass  = Person.class;
//        获取构造方法们,构造方法:1,创建对象
//        Constructor<T> getConstructor(类<>... parameterType)
        Constructor constructor = PersonClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
//        创建对象
        Object wang = constructor.newInstance("wang", 23);
        System.out.println(wang);
        System.out.println("-----------------");
//           如果使用空参数构造方法创建对象,操作可以简化:class对象的newInstance方法
        Object o = PersonClass.getConstructor().newInstance();
        System.out.println(o);



    }
}

 

获取成员方法们:

package com.wzc;

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

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception{
        //    1.获取Person的Class对象
        Class PersonClass  = Person.class;
//Method:1,执行方法:Object invoke(Object obj,Object... args)
// 2,获取方法名称:getName()
//获取指定名称的方法
        Method eat_method = PersonClass.getMethod("eat");
        Person p = new Person();
//        执行方法
        eat_method.invoke(p);
        Method eat_method2 = PersonClass.getMethod("eat", String.class);
        eat_method2.invoke(p,"饭");
        System.out.println("---获取所有public修饰的方法---");
        Method[] methods = PersonClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            String name = method.getName();
            System.out.println(name);
//            method.setAccessible(true);
        }
//         获取类名
        String name = PersonClass.getName();
        System.out.println(name);

    }
}

package com.wzc;

public class Person {
    private String name;
    private int age;
    public String a;
    protected String b;
    String c;
    private String d;

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

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

    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;
    }

    public Person(){

    }
    public void eat(){
        System.out.println("吃");
    }
    public void eat(String food){
        System.out.println("吃"+food);
    }
}

 

 

 反射案例:

感受反射魅力所在 需求:写一个“框架”,在不改变该类的任何代码的前提下,可以帮助我们创建任意类的对象,并且执行其中任意方法
实现:
1,配置文件
2,反射
步骤:
1,将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2,在程序中加载读取配置文件
3,使用反射技术来加载类文件进内存
4,创建对象
5,执行方法
改配置文件的方式可以让程序扩展性更强
首先创建一个配置文件

 

package com.wzc;

public class Student {
    public void sleep(){
        System.out.println("睡觉");
    }
}

 

package com.wzc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

import static java.lang.Class.forName;

//框架类
public class ReflectTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
//        可以创建任意类的对象,可以执行任意方法
       /*
        前提是不能改变该类的任何代码,所以不能直接创建对象调用
        */
//1,加载配置文件
//        创建properties对象
        Properties pro = new Properties();
//        加载配置文件,转化为一个集合
//        获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
        pro.load(resourceAsStream);
//        获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
//        加载该类进内存
        Class aClass = forName(className);
//        创建方法
        Method method = aClass.getMethod(methodName);
//        传入对象,执行方法,由于是java15,所以类对象的newInstance方法过时了,所以这样传
        method.invoke(aClass.getDeclaredConstructor().newInstance());
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值