阅读 44

Java基础之反射机制

前言

在讲反射之前,我们先讲解下java代码运行的基本流程。 首先我们写源代码文件,然后用javac编译了代码,然后用java 命令执行,其中我们在javac后会看见.class 文件的存在。这里.class 文件就是字节码文件,后续交给java虚拟机处理。

其实.class文件 就是一个类文件,我们运行java命令时将其加载到内存里供后续使用。当我们执行new 操作到时候,就根据类来创建对象并放到内存堆空间。

public class Person {//Person.java
    public static void main(String[] args) {
    	Student student= new Student();
    	student.hello();
    	System.out.println(student);
    }

}
复制代码
public class Student {//Student.java
    public void hello(){
    	System.out.println(" how are you");
    }

}
复制代码

由上面我们知道首先是将类加载到内存中,然后利用这个类创建出对应类型到对象,类差不多是个模型到存在。

那么我们通过对象能否得知这个类是啥样到呢? 如果一个类的结构,那能不能创建对象并调用方法呢? 答案是肯定到!且这就是反射。

反射

反射是被视为动态语言到关键,反射机制允许程序在执行期间借助与Reflection 取得任何类到内部信息,并能直接操作任意对象的内部属性和方法。 反射可以做什么?

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员和方法
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

可能很多人对“运行时”不理解,其实运行时就是指类class已经被加载了。 有几个api需要注意下,java.lang.Class java.reflect.Method java.lang.relect.Field java.lang.reflect.Constructor.

获取类并构建对象

public class Person {
    public   String name;
    private int age;
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name) {
        this.name = name;
    }
    public  void  show(){
        System.out.println("i am a person!");
    }
    public  void display(String nation){
        System.out.println("i come from "+nation);
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 Class clazz= Person.class;//获得类
 Person p=(Person) clazz.newInstance();//构建对象
复制代码

获取类的属性并给实例对象设置属性

Field f1=clazz.getField("name");//name 为public
f1.set(p,"lili");//设置属性
Field f2=clazz.getDeclaredField("age");//age 为private
f2.setAccessible(true);//设置访问权限
f2.set(p,15);//设置属性
复制代码

获取类方法,并在指定对象上调用该方法

 Method m1=clazz.getMethod("show"); //无参数方法
 m1.invoke(p);
 Method m2=clazz.getMethod("display", String.class);//有参数方法
 m2.invoke(p,"china");
复制代码

通过实例对象获取class类

Person p2= new Person();
Class clazz2=p2.getClass();
复制代码

通过运行时类的对象,调用getClass 获得其运行时的类

Class的秘密

我们在上面的例子中多次用到了这个java.lang.Class类型的clazz,这个clazz到底是什么呢?

回到前言中提到的,我们知道我们新建一个类,然后javac编译成.class文件,然后java命令加载到内存中去,存放在缓存区,这个clazz就是这个加载的运行时类,且是Class类型的实例。 我们有以下方法获得这个运行时类

  • 通过类获取
Class clazz= Person.class;
复制代码
  • 通过对象获取
Person p=new Person();
Class clazz1=p.getClass();
复制代码
  • 通过Class类的静态属性
 Class clazz3=Class.forName("com.zhang.Person");
 System.out.println(clazz3);
复制代码

总结

为什么叫反射?平时我们通过new + 类名操作来实例化对象,反过来,我们可以通过这个对象来找到该对象的“原型”--运行时类,然后用运行时类做更多的操作。 可见这个Class 类型的运行时是时整个反射机制的核心。

  • 运行时类是java虚拟机加载进来且只加载一次
  • 运行时类是java.lang.Class的一个实例
  • 运行时类的获取成为重中之重

喜欢本文的朋友们,欢迎长按下图关注订阅号"我的编程笔记",收看更多精彩内容~~