java的反射机制

一、反射

  1. java反射机制:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
  2. 反射就是把java类的各种成分映射成一个个java对象。
    要想解剖一个类,必须先要获取该类的字节码文件对象;而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
  3. 一个类有:成员变量、方法、构造方法、包等信息,利用反射技术可以对一个类进行解剖。把各个组成部分映射成一个个对象。
    Class对象的由来是将class文件读入内存,并为之创建一个class对象。


    java的反射机制_第1张图片
    类正常加载过程

二、反射的理解

1.正射

一般情况下,我们使用某个类时必定知道它是什么类,是用来干什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。

User user = new User();   //直接初始化,正射 
user.setAge(20);

2. 反射

反射则是一开始并不知道我们要初始化的类对象是什么,自然无法使用new关键字来创建对象。

反射就是在运行时才知道要操作的类是什么,并且可以运行时获取类的完整构造,并调用对应的方法。

@Test
    public void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取类的Class对象
        Class c1 = Class.forName("demo01.User");

        //根据 Class对象 实例获取 Constructor对象
        Constructor constructor = c1.getConstructor();
        //根据 Constructor对象 的 newInstance方法 获取反射类对象
        Object o = constructor.newInstance();

        //获取方法的 Method对象
        Method setAgeMethod = c1.getMethod("setAge", Integer.class);
        //利用 invoke方法 调用方法
        setAgeMethod.invoke(o,13);
        Method getAge = c1.getMethod("getAge");
        System.out.println(getAge.invoke(o));

    }

三、反射的常用API

1.获取反射中的Class对象

  1. 使用Class.forName静态方法。当我们知道某类的全路径名时,可以使用此方法获取Class类对象。用的最多,但可能抛出 ClassNotFoundException 异常。
Class c1 = Class.forName("java.lang.String");
  1. 直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高。这说明任何一个类都有一个隐含的静态成员变量class。这种方法只适合在编译前就知道操作的class。
Class c2 = String.class;
  1. 通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object 类型的对象,而我不知道你具体是什么类,用这种方法。
String str = new String("Hello");
Class c3 = str.getClass();

需要注意的是:一个类在 JVM 中只会有一个 Class 实例,即我们对上面获取的 c1、c2和c3进行 equals 比较,发现都是true。

2. 通过反射创建类对象

  1. 通过 Class对象 的newInstance()方法
Class c1 = User.class;
User user = (User)c1.newInstance();
  1. 通过 Constructor对象 的newInstance()方法
Class c1 = User.class;
Constructor constructor = c1.getConstructor();
User user = (User)constructor.newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

Class c1 = User.class;
Constructor constructor = c1.getConstructor(String.class,Integet.class);
User user = (User)constructor.newInstance("aaa",12);

3.通过反射获取类属性、方法、构造器

  1. 我们通过 Class 对象的 getFields() 方法可以获取 Class 类的属性,但无法获取私有属性。
Class clz = Phone.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

输出的结果是:
price

  1. 如果使用 Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性
Class clz = Phone.class;
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

输出结果是:
name
price

四、使用反射函数的例子

反射就是把java类中的各种成分映射成一个个对象
User.java

public class User {
    private String username;
    public void sayHi(String words){
        System.out.println(username+":"+words);
    }

    private String sayHello(String tag){
        return tag;
    }
}

ReflectDemo.java

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class aClass = Class.forName("com.msj.reflect.User");
        System.out.println(aClass.getName());
        User user = (User)aClass.newInstance();
//        私有方法
        Method sayHello = aClass.getDeclaredMethod("sayHello", String.class);
        //访问私有方法、属性都要设置setAccessible(true)
        sayHello.setAccessible(true);
        Object aaa = sayHello.invoke(user, "aaa");
        System.out.println(aaa);

//        公有方法
        Method sayHi = aClass.getMethod("sayHi", String.class);
        sayHi.invoke(user, "bbb");

//        私有属性
        Field username = aClass.getDeclaredField("username");
        username.setAccessible(true);
        username.set(user,"msj");
        sayHi.invoke(user,"bbb");
    }
}

五、new 对象和反射得到对象的区别

  1. 在使用反射的时候,必须确保这个类已经加载并已经连接了。使用new的时候,这个类可以没有被加载,也可以已经被加载。
  2. new关键字可以调用任何public构造方法,而反射只能调用无参构造方法。
  3. new关键字是强类型的,效率相对较高。反射是弱类型的,效率较低。
  4. 反射提供了一种更加灵活的方式创建对象,得到对象的信息。如Spring中AOP等的使用,动态代理的使用,都是基于反射的。

你可能感兴趣的:(java的反射机制)