反射实际开发使用

奋斗吧
奋斗吧
擅长邻域:未填写

标签: 反射实际开发使用 Java博客 51CTO博客

2023-07-14 18:24:15 76浏览

反射实际开发使用,01.获得Class对象方式获得Class对象三种方式每个类被加载之后,系统就会为该类生成一个对应的Class对象。通过该Class对象就可以访问到JVM中的这个类。在Java程序中获得Class对象通常有如下三种方式:1.使用Class类的forName(StringclazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定名(必须添加完整包名)。2.调用某个类的

01.获得Class对象方式

  • 获得Class对象三种方式
  • 每个类被加载之后,系统就会为该类生成一个对应的Class对象。通过该Class对象就可以访问到JVM中的这个类。
  • 在Java程序中获得Class对象通常有如下三种方式:
  • 1.使用Class类的forName(String clazzName)静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定名(必须添加完整包名)。
  • 2.调用某个类的class属性来获取该类对应的Class对象。
  • 3.调用某个对象的getClass()方法。该方法是java.lang.Object类中的一个方法。
//第一种方式 通过Class类的静态方法——forName()来实现
class1 = Class.forName("com.lvr.reflection.Person");
//第二种方式 通过类的class属性
class1 = Person.class;
//第三种方式 通过对象getClass方法
Person person = new Person();
Class<?> class1 = person.getClass();
  • 第一种:Class.forName()
  • 1.通过JVM查找并加载指定的类(上面的代码指定加载了com.fanshe包中的Person类)
  • 2.调用newInstance()方法让加载完的类在内存中创建对应的实例,并把实例赋值给p
  • 注意:如果找不到时,它会抛出 ClassNotFoundException 这个异常,这个很好理解,因为如果查找的类没有在 JVM 中加载的话,自然要告诉开发者。
Class<?> cls=Class.forName("com.yc.Person"); //forName(包名.类名)
Person p= (Person) cls.newInstance();
  • 第二种:类.class
  • 1.获取指定类型的Class对象,这里是Person
  • 2.调用newInstance()方法在让Class对象在内存中创建对应的实例,并且让p引用实例的内存地址
Class<?> cls = Person.class;
Person p=(Person)cls.newInstance();
  • 第三种:对象.getClass()
  • 1.在内存中新建一个Person的实例,对象p对这个内存地址进行引用
  • 2.对象p调用getClass()返回对象p所对应的Class对
  • 3.调用newInstance()方法让Class对象在内存中创建对应的实例,并且让p2引用实例的内存地址
Person p = new Person();
Class<?> cls= p.getClass();
Person p2=(Person)cls.newInstance();
  • 获取Class父类对象
  • 先看一下代码
//在AppBarLayout类中
public static class Behavior extends AppBarLayout.BaseBehavior<AppBarLayout>
//BaseBehavior的父类
protected static class BaseBehavior<T extends AppBarLayout> extends HeaderBehavior<T>
  • 反射获取父类
Class<?> superclass = AppBarLayout.Behavior.class.getSuperclass();
  • 反射获取父类的父类
Class<?> superclass = AppBarLayout.Behavior.class.getSuperclass();
headerBehaviorType = superclass.getSuperclass();
  • 注意事项
  • 生成类的实例对象
  • 1.使用Class对象的newInstance()方法来创建该Class对象对应类的实例。这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时实际上是利用默认构造器来创建该类的实例。
  • 2.先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择使用指定的构造器来创建实例。
//第一种方式 Class对象调用newInstance()方法生成
Object obj = class1.newInstance();
//第二种方式 对象获得对应的Constructor对象,再通过该Constructor对象的newInstance()方法生成
Constructor<?> constructor = class1.getDeclaredConstructor(String.class);//获取指定声明构造函数
obj = constructor.newInstance("hello");
  • new对象和反射得到对象的区别
  • 在使用反射的时候,必须确保这个类已经加载并已经连接了。使用new的时候,这个类可以没有被加载,也可以已经被加载。
  • new关键字可以调用任何public构造方法,而反射只能调用无参构造方法。
  • new关键字是强类型的,效率相对较高。 反射是弱类型的,效率低。
  • 反射提供了一种更加灵活的方式创建对象,得到对象的信息。如Spring 中AOP等的使用,动态代理的使用,都是基于反射的。解耦。

02.反射调用类的方法

  • 调用类的方法
  • 1.通过Class对象的getMethods\(\)方法或者getMethod\(\)方法获得指定方法,返回Method数组或对象。
  • 2.调用Method对象中的Object invoke(Object obj, Object... args)方法。第一个参数对应调用该方法的实例对象,第二个参数对应该方法的参数。
private void method8() {
    try {
        Class<?> cl = Class.forName("com.ycbjie.other.ui.activity.Student");
        // 生成新的对象:用newInstance()方法
        Student obj = (Student) cl.newInstance();
        String student1 = obj.getStudent();
        LogUtils.i("反射调用类的方法1:"+student1);
        //首先需要获得与该方法对应的Method对象
        Method method = cl.getDeclaredMethod("setAge", int.class);
        //设置权限
        method.setAccessible(true);
        //调用指定的函数并传递参数
        method.invoke(obj, 28);
        String student2 = obj.getStudent();
        LogUtils.i("反射调用类的方法2:"+student2);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
}

//打印值
2019-06-11 18:24:40.146 23666-23666/com.ycbjie.other I/yc: 反射调用类的方法1:yc---26
2019-06-11 18:24:40.146 23666-23666/com.ycbjie.other I/yc: 反射调用类的方法2:yc---28
  • 获取方法的参数
  • 当通过Method的invoke()方法来调用对应的方法时,Java会要求程序必须有调用该方法的权限。如果程序确实需要调用某个对象的private方法,则可以先调用Method对象的如下方法。
  • setAccessible(boolean flag):将Method对象的acessible设置为指定的布尔值。值为true,指示该Method在使用时应该取消Java语言的访问权限检查;值为false,则指示该Method在使用时要实施Java语言的访问权限检查。

03.反射访问成员变量值

  • 反射访问成员变量值
  • 1.通过Class对象的getFields()方法或者getField()方法获得指定方法,返回Field数组或对象。
  • 2.Field提供了两组方法来读取或设置成员变量的值:
  • getXXX(Object obj):获取obj对象的该成员变量的值。此处的XXX对应8种基本类型。如果该成员变量的类型是引用类型,则取消get后面的XXX。
  • setXXX(Object obj,XXX val):将obj对象的该成员变量设置成val值。
private void method9() {
    try {
        Class<?> cl = Class.forName("com.ycbjie.other.ui.activity.Student");
        // 生成新的对象:用newInstance()方法
        Student obj = (Student) cl.newInstance();
        int age = obj.getAge();
        LogUtils.i("反射访问成员变量值1:"+age);
        //获取age成员变量
        //Field field = cl.getField("age");
        Field field = cl.getDeclaredField("age");
        //设置权限
        field.setAccessible(true);
        //将obj对象的age的值设置为10
        field.setInt(obj, 10);
        //获取obj对象的age的值
        int anInt = field.getInt(obj);
        LogUtils.i("反射访问成员变量值2:"+anInt);

        //反射修改私有变量
        // 获取声明的 code 字段,这里要注意 getField 和 getDeclaredField 的区别
        Field gradeField = cl.getDeclaredField("name");
        // 如果是 private 或者 package 权限的,一定要赋予其访问权限
        gradeField.setAccessible(true);
        // 修改 student 对象中的 Grade 字段值
        gradeField.set(obj, "逗比");
        Object o = gradeField.get(obj);
        LogUtils.i("反射访问成员变量值3:"+o.toString());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
}



2019-06-11 19:06:59.380 12313-12313/com.ycbjie.other I/yc: 反射访问成员变量值1:26
2019-06-11 19:06:59.380 12313-12313/com.ycbjie.other I/yc: 反射访问成员变量值2:10
2019-06-11 19:06:59.380 12313-12313/com.ycbjie.other I/yc: 反射访问成员变量值3:逗比

04.调用共有和私有区别

  • 修改Student类,将get方法都指定为公有的,将set方法指定为私有的
public class Student {

	private String name;

	private int age;

	public Student() {

	}

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

	public String getName() {
		System.out.println("调用了getName方法,Name:" + name);
		return name;
	}

	public int getAge() {
		System.out.println("调用了getAge方法,Age:" + age);
		return age;
	}

	private void setName(String name) {
		this.name = name;
		System.out.println("调用了setName方法,name:" + name);
	}

	private void setAge(int age) {
		this.age = age;
		System.out.println("调用了setAge方法,age:" + age);
	}
}
  • 反射调用公有方法
  • java.lang.reflect.Method 实例是方法的代表对象,可以使用 invoke() 方法来动态调用指定的方法
  • 首先来调用公有方法
public class Main {

	public static void main(String[] args) throws Exception {
		Class cl = Class.forName("com.czy.demo.Student");
		// 指定构造函数
		Constructor constructor = cl.getConstructor(String.class, Integer.TYPE);
		// 根据指定的构造函数来获取对象
		Object object = constructor.newInstance("杨充逗比", 25);

		// 指定方法名称来获取对应的公开的Method实例
		Method getName = cl.getMethod("getName");
		// 调用对象object的方法
		getName.invoke(object);

		// 指定方法名称来获取对应的公开的Method实例
		Method getAge = cl.getMethod("getAge");
		// 调用对象object的方法
		getAge.invoke(object);
	}
}
  • 输出结果如下所示,可以知道Student对象的两个get方法成功被调用了。
调用了getName方法,Name:杨充逗比
调用了getAge方法,Age:25
  • 反射调用私有方法
  • 一般情况下,类的私有方法只有在其内部才可以被调用,通过反射我们可以来突破这一限制
  • 受保护或私有方法的调用步骤略有不同
public class Main {
	public static void main(String[] args) throws Exception {
		Class cl = Class.forName("com.czy.demo.Student");
		// 指定构造函数
		Constructor constructor = cl.getConstructor(String.class, Integer.TYPE);
		// 根据指定的构造函数来获取对象
		Object object = constructor.newInstance("杨充逗比", 25);

		// 指定方法名称来获取对应的私有的Method实例
		Method setName = cl.getDeclaredMethod("setName", String.class);
		setName.setAccessible(true);
		setName.invoke(object, "潇湘剑雨");
		
		// 指定方法名称来获取对应的私有的Method实例
		Method setAge = cl.getDeclaredMethod("setAge", Integer.TYPE);
		setAge.setAccessible(true);
		setAge.invoke(object, 100);
	}
}
  • 输出结果如下所示,可以看到私有方法一样在外部被调用了
调用了setName方法,name:潇湘剑雨
调用了setAge方法,age:100

好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695