Thinking in java:RTTI和反射机制

摘抄别人的一句话:要想理解反射的原理,首先要了解什么是类型信息。Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息

一.RTTI

为理解RTTI在Java里如何工作,首先必须了解类型信息在运行期是如何表示的。这时要用到一个名为“Class对象”的特殊形式的对象,其中包含了与类有关的信息(有时也把它叫作“元类”)。事实上,我们要用Class对象创建属于某个类的全部“常规”或“普通”对象。RTTI在java里表现为3种形式:

  • 经典造型,即下溯造型,造型失败产生一个ClassCastException违例
  • 代表对象类型的Class对象。可查询Class对象,获取有用的运行期资料
  • instanceof,它会返回一个布尔值

第一种和第三种忽略,主要是第二种。
关于Class类
每一个class都有一个Class对象,可以理解为类对象,有且仅有一个。在运行期,一旦我们需要new一个class的对象时,JVM首先会去检查这个class是否已经载入,如果没有载入,JVM会去查同名的.class文件,并将其载入,载入时便会生成一个Class对象,它保存了这个class的相关信息,静态变量也是在类载入的时候初始化。在java1.0种,使用Class实现RTTI有3种形式:

  • Class.forName(“类名”);
  • 类型.class;
  • 对象.getClass();

3种形式得到的都是一个class的Class对象,第二种相较第一种要更安全和快捷,因为第二种在编译器会进行检查,并且没有调用方法,但就实用性而言我觉得第一种较为常用。

二.反射

在java1.1种,Class类得到了扩展,我们可以从一个Class对象种获取这个class类型的成员信息,但要注意的一点是:获取的信息是Class对象的,并不是某个具体的class对象的信息,因此我们要用某些信息的时候都要与一个具体的class对象相绑定。
1.通过反射获取构造方法并使用

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

public class Test
{
    public static void main(String[] args)
    {
        try {
            Class clazz=Class.forName("Student");
            //Constructor[] constructors=clazz.getConstructors();获取所有公有的构造方法
            //Constructor[] constructors=clazz.getDeclaredConstructors();//获取所有的构造方法
            Constructor con=clazz.getConstructor(String.class);//获取公有的参数类型为String的构造方法,注意参数为对应类型Class对象!!
            Student st=(Student) con.newInstance("老李");//用构造方法生成一个Student对象
            System.out.println(st.name);
            con=clazz.getDeclaredConstructor(String.class,int.class);//获取构造方法种参数为String和int的方法,这儿获取的私有构造方法
            con.setAccessible(true);//将私有构造的访问权限设为true,否则无法用构造方法创建对象
            st =(Student) con.newInstance("小李",7991);
            System.out.println(st.name+"  "+st.ID);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class Student
{
    String name;
    public int ID;
    public Student(String name)
    {
        this.name=name;
    }
    public Student()
    {
        this.name="老张";
    }
    private Student(String name,int id)
    {
        this.name=name;
        this.ID=id;
    }
    public void print()
    {
        System.out.println("name="+name+",ID="+ID);
    }
    private void add(int num){ID+=num;}
    private void change(String name){this.name=name;}
}

输出如下:
这里写图片描述
2.通过反射获取成员变量并使用

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

public class Test
{
    public static void main(String[] args)
    {
        Student student=new Student("老李");
        student.ID=7881;
        try {
            Class clazz=Class.forName("Student");
            //Field[] fields=clazz.getFields();获取公有的成员变量
            //Field[] fields=clazz.getDeclaredFields();获取所有的成员变量
            Field name=clazz.getDeclaredField("name");//获取name变量
            Field id=clazz.getDeclaredField("ID");//获取ID变量
            name.set(student,"老张");
            id.set(student,5000);
            System.out.println(student.name+"  "+student.ID);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class Student
{
    String name;
    public int ID;
    public Student(String name)
    {
        this.name=name;
    }
    public Student()
    {
        this.name="老张";
    }
    private Student(String name,int id)
    {
        this.name=name;
        this.ID=id;
    }
    public void print()
    {
        System.out.println("name="+name+",ID="+ID);
    }
    private void add(int num){ID+=num;}
    private void change(String name){this.name=name;}
}

输出如下:
这里写图片描述
3.通过反射获取方法并使用

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

public class Test
{
    public static void main(String[] args)
    {
        Student student=new Student();
        try {
            Class clazz=Class.forName("Student");
            //Method[] methods=clazz.getMethods();获取公有的方法
            //Method[] methods=clazz.getDeclaredMethods();获取所有的方法
            Method me=clazz.getMethod("print");//获取print方法
            me.invoke(student);//调用student对象的print方法
            me=clazz.getDeclaredMethod("add",int.class);//获取add方法
            me.setAccessible(true);//设置访问权限为true;
            me.invoke(student,50);//调用student对象的add方法
            student.print();
            me=clazz.getDeclaredMethod("down");
            me.invoke(null);//调用静态方法不需要对象,静态成员同理
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class Student
{
    String name;
    public int ID;
    public Student(String name)
    {
        this.name=name;
    }
    public Student()
    {
        this.name="老张";
    }
    private Student(String name,int id)
    {
        this.name=name;
        this.ID=id;
    }
    public void print()
    {
        System.out.println("name="+name+",ID="+ID);
    }
    private void add(int num){ID+=num;}
    private void change(String name){this.name=name;}
    public static void down(){System.out.println("调用静态方法");}
}

输出如下:
这里写图片描述

推荐一篇关于反射的博客:https://blog.csdn.net/sinat_38259539/article/details/71799078

猜你喜欢

转载自blog.csdn.net/qq_27368993/article/details/82704846