[Java核心技术]-反射技术

反射是什么

反射: 将类的各个组成部分封装成其他对象

反射是框架实际的灵魂

框架: 半成品软件,可以在狂角点基础上进行软件开发

反射带来的好处

  • 可以在程序运行过程中,操作这些对象
  • 可以解耦

Java程序执行过程

拿一个People类说明

public class People {
    //成员变量
    private int age;
    private String name;
    
    //构造方法
    public People(){}
    
    //成员方法
    public void say(){System.out.println(name+"say...");}

		
	/**图片空间有限 下面的就不在图片标明了**/
	
	public People(int age, String name) {
        this.age = age;
        this.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;}

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

下面用一张图来说明
在这里插入图片描述

  • 源代码阶段:此时文件还处于硬盘中,并没有加载
  • class类阶段:使用类加载器吧.class文件加载成一个class对象
  • 运行时阶段:在创建对象的时候,将class里的内容封装成一个对象

获取class对象

class对象的获取方式有以下三种

  • 使用Class.forName("全类名");
  • 类名.class
  • 对象.getClass();

下面用代码来演示

public static void main(String[] args) throws Exception {
    // 1. 使用`Class.forName("全类名");`
    Class cls1 = Class.forName("test.People");
    // 2. 类名.class
    Class cls2 = People.class;
    // 3. 对象.getClass();
    People people = new People();
    Class cls3 = people.getClass();

    //输出3个对象
    System.out.println(cls1);
    System.out.println(cls2);
    System.out.println(cls3);

    //对比三个对象
    System.out.println(cls3 == cls1);
    System.out.println(cls2 == cls1);
    System.out.println(cls3 == cls2);
}

输出结果

class test.People
class test.People
class test.People
true
true
true

由此可见 他们三种的获取的class对象 都是同一个对象


使用 Class对象

获取功能

下面说几种常见的功能

  • 获取成员变量们
    • Field getField(String name)
      返回一个public的指定名称的 Field对象。

    • Field[] getFields()
      返回所有public的 Field对象数组。

    • Field getDeclaredField(String name)
      返回一个指定名称的 Field对象。

    • Field[] getDeclaredFields()
      返回所有 Field对象数组。


  • 获取构造方法们
    • Constructor<T> getConstructor(Class<?>... parameterTypes)
      返回一个指定public的 Constructor对象。

    • Constructor<?>[] getConstructors()
      返回public的Constructor对象数组。

    • Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
      返回一个指定的 Constructor对象。

    • Constructor<?>[] getDeclaredConstructors()
      返回所有Constructor对象。


  • 获取成员方法们
    • Method getMethod(String name, Class<?>... parameterTypes)
      返回一个指定的public的 Method 对象。
    • Method[] getMethods()
      返回所有public的 Method对象。
    • Method getDeclaredMethod(String name, Class<?>... parameterTypes)
      返回一个指定的 Method 对象。
    • Method[] getDeclaredMethods()
      返回所有 Method对象。

  • 获取名称 String getName()

  • 获取注解
    • <A extends Annotation> A getAnnotation(类<A> annotationClass)
      返回指定类型的注解,如果没有返回null。

    • Annotation[] getAnnotations()
      返回此元素上 存在的注释。


成员变量的修改和获取

  • 获取值 get(Object obj)
  • 设置值 set(Object obj,Object value)
  • 暴力反射 setAccessible(true)
//获取public 修饰的
Field[] names = cls1.getFields();
for (Field name : names) {
    System.out.println(name);
}

我们先来获取所有的变量,但是输出却一个也没有???
原来所有的变量都是private的

所以我们用第二种

//获取所有的变量
Field[] names = cls1.getDeclaredFields();
for (Field name : names) {
    System.out.println(name);
}

下面输出结果,这个时候就有输出了

private int test.People.age
private java.lang.String test.People.name

我们也可以对变量进行修改

People p = new People();
p.setName("李四");

//获取name变量
Field field = cls1.getDeclaredField("name");
System.out.println(field.get(p));

虽然逻辑上看上去没有一点问题,但是程序一执行立即报错

报错的原因就是访问权限修饰符的安全检查
因为private是不允许被外界访问的

所以 这里需要暴力反射
在原来的代码上加上field.setAccessible(true);

People p = new People();
p.setName("李四");

//获取name变量
Field field = cls1.getDeclaredField("name");
//允许暴力反射
field.setAccessible(true);
System.out.println(field.get(p));//李四
field.set(p,"张三");
System.out.println(field.get(p));//张三

这样就可以对private变量进行修改和获取了


构造方法是使用和创建对象

  • 创建对象方法newInstance(Object...args)
  • 暴力反射 setAccessible(true)
//获取构造器对象
Constructor wu_can = cls1.getConstructor();//无参构造
Constructor you_can = cls1.getConstructor(int.class, String.class);//有参数

//创建对象
Object p1 =  wu_can.newInstance();
System.out.println(p1);

//修改信息
People zhang_san = (People) p1;//强制转换
zhang_san.setAge(25);
zhang_san.setName("张三");
System.out.println(p1);//和zhang_san是同一个对象

//使用有参数构造器创建对象
Object p2 =  you_can.newInstance(20,"李四");
System.out.println(p2);

输出结果

People{age=0, name='null'}
People{age=25, name='张三'}
People{age=20, name='李四'}

成员方法的调用以及返回值的获取

  • 执行方法invoke(Object obj,Object...args)返回返回值
  • 暴力反射 setAccessible(true)
People p = new People(20,"张三");//执行对象
Object obj;//返回值

//调用say()
Method say = cls1.getMethod("say");
obj = say.invoke(p);//say()没有返回值
System.out.println("say-obj:"+obj);

//调用setName()
Method setName = cls1.getMethod("setName", String.class);
obj = setName.invoke(p,"李四");//setName没有返回值
System.out.println("setName-obj:"+obj);

//调用getName()
Method getName = cls1.getMethod("getName");
obj = getName.invoke(p);//这里有返回值
System.out.println("getName-obj:"+obj);

输出结果如下

张三say...
say-obj:null
setName-obj:null
getName-obj:李四
发布了65 篇原创文章 · 获赞 57 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_18604209/article/details/104394605