Java学习之反射机制

反射机制

  • 动态语言
  • 反射机制的本质和Class类
    • 本质
    • java.lang.Class类
  • 反射机制常见操作
    • Constructor类
    • Field类
    • Method类
  • 效率问题

反射机制,反射是Java的高级特性,是Java“动态性”的重要体现。反射机制可以让程序在运行时加载编译期完全未知的类,使设计的程序更加灵活、开放,但对大大降低程序执行的效率。

动态语言

动态语言是指程序在运行时,可以改变程序结构或变量的类型。典型的有Python、JavaScipt等。例如下面的JS代码:

function test(){
     
	var s = "var a = 3; var b = 5; alert(a + b);";
	eval(s);
}

JS可执行位于字符串里面的源码。也就是说,外部传入的字符串是什么内容,JS就执行什么。这样,在执行的时候就完全改变了源码结构。这种动态特性,让程序更灵活,更开放。
Java虽然有动态性,但不是动态语言,可以利用反射机制或者字节码操作获得类似动态语言的特性。

反射机制的本质和Class类

Java反射机制让我们在程序运行状态中,对于任意一个类,都能知道该类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。这种动态获取以及动态调用对象方法的功能就是“Java的反射机制”

本质

来看下面这个代码

public class Study{
     
    public static void main(String[] args) {
     
        Person person = new Person("xxx");
    }
    static class Person{
     
        String name;
        public Person(String name){
     
            this.name = name;
        }
    }
}

分析内存结构:
Java学习之反射机制_第1张图片
Java在加载任何一个类时都会在方法区建立这个类对应的Class对象,由于Class对象包含了这个类的整个信息结构,所以可以通过这个Class对象来操作这个类。
在使用一个类之前要先加载它,在加载完类后,会在对内存中产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,可以通过这个对象知道类的结构。这个对象如图一面镜子,透过它可以看到类的结构,因此被称为反射。“Class对象”是反射机制的核心。获得了Class对象,就相当于获得了类结构。通过“Class对象”可以调用该类的所有属性、方法和构造器,中依旧可以动态加载和运行相关的类。

java.lang.Class类

java.lang.Class类是实现反射(Reflection)的根源。针对任何想动态加载、运行的类,只有先获得相对于的Class对象。java.lang.Class类用于表示Java中的类型(class,interface,enum,annotation,primitive type,void)本身。
Class对象可用以下方法获取
1)getClass()方法
2).class语法
3)运行Class.forName(),这个最常用
示例如下:

package blog.Study;

public class Study{
     
    public static void main(String[] args) throws Exception{
     
        Person person = new Person("xxx");
        Class c1 = person.getClass();
        Class c2 = Person.class;
        Class c3 = Class.forName("blog.Study.Person");
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c1.equals(c2));
        System.out.println(c1.equals(c3));
        System.out.println(c1.getName());
        System.out.println(c1.getSimpleName());
    }
}
class Person{
     
    String name;
    public Person(String name){
     
        this.name = name;
    }
}
//输出如下
class blog.Study.Person
class blog.Study.Person
class blog.Study.Person
true
true
blog.Study.Person
Person

反射机制常见操作

1)动态加载类、动态获取类的信息
2)动态构造对象
3)动态调用类和对象的任意方法
4)动态调用和处理属性
5)获取泛型信息
6)处理注解
常用类如下

  • Class类:代表类的结构信息
  • Method类:代表方法的结构信息
  • Field类:代表属性的结构信息
  • Construcor类:代表构造器的结构信息
  • Annotation类:代表注解的结构信息

首先定义Person类:

package blog.Study;

public class Person{
     
    private String name;
    private int age;
    public Person(String name, int age){
     
        this.name = name;
        this.age = age;
    }
    public Person(String name){
     
        this.name = name;
    }
    public Person(){
     
    }

    public void print() {
     
        System.out.println("Person{" + "name='" + name + '\'' + ", age=" + age + '}');
    }
    public String getName(){
     
        return this.name;
    }
    public int getAge(){
     
        return this.age;
    }
    public void setName(String name){
     
        this.name = name;
    }
    public void setAge(int age){
     
        this.age = age;
    }
}

Constructor类

import blog.Study.Person;

import java.lang.reflect.Constructor;

public class study {
     
    public static void main(String[] args) throws Exception{
     
        String path = "blog.Study.Person";
        Class c = Class.forName(path);
        Constructor[] constructors = c.getDeclaredConstructors();
        for(Constructor temp : constructors)
            System.out.println(temp);
        System.out.println(c.getDeclaredConstructor(null));
        System.out.println(c.getDeclaredConstructor(String.class));
        System.out.println(c.getDeclaredConstructor(String.class, int.class));
        Person person = (Person)c.newInstance();
        Person person1 = (Person)c.getDeclaredConstructor(null).newInstance();
        Person person2 = (Person)c.getDeclaredConstructor(String.class).newInstance("XXX");
        Person person3 = (Person)c.getDeclaredConstructor(String.class,int.class).newInstance("xxx", 18);
        person.print();
        person1.print();
        person2.print();
        person3.print();
    }
}//输出如下
public blog.Study.Person(java.lang.String,int)
public blog.Study.Person()
public blog.Study.Person(java.lang.String)
public blog.Study.Person()
public blog.Study.Person(java.lang.String)
public blog.Study.Person(java.lang.String,int)
Person{
     name='null', age=0}
Person{
     name='null', age=0}
Person{
     name='XXX', age=0}
Person{
     name='xxx', age=18}

Field类

import blog.Study.Person;

import java.lang.reflect.Field;

public class study {
     
    public static void main(String[] args) throws Exception{
     
        String path = "blog.Study.Person";
        Class c = Class.forName(path);
        Field[] fields = c.getDeclaredFields();
        for(Field temp : fields)
            System.out.println("属性->" + temp);
        Field field = c.getDeclaredField("name");
        System.out.println(field);
        Person person = (Person)c.newInstance();
        Field field1 = c.getDeclaredField("age");
        field.setAccessible(true);//跳过安全检查,直接访问私有属性和方法
        field1.setAccessible(true);
        field.set(person, " xxx ");
        field1.set(person, 18);
        person.print();
    }
}//输出如下
属性->private java.lang.String blog.Study.Person.name
属性->private int blog.Study.Person.age
private java.lang.String blog.Study.Person.name
Person{
     name=' xxx ', age=18}

Method类

import blog.Study.Person;

import java.lang.reflect.Method;

public class study {
     
    public static void main(String[] args) throws Exception{
     
        String path = "blog.Study.Person";
        Class c = Class.forName(path);
        Method[] methods = c.getDeclaredMethods();
        for(Method temp : methods)
            System.out.println("方法->" + temp);
        Method method = c.getDeclaredMethod("setName", String.class);
        Method method1 = c.getDeclaredMethod("setAge", int.class);
        Method method2 = c.getDeclaredMethod("print", null);
        Person person = (Person) c.newInstance();
        method.invoke(person, "xxx");
        method1.invoke(person, 18);
        method2.invoke(person, null);
    }
}//输出如下
方法->public java.lang.String blog.Study.Person.getName()
方法->public void blog.Study.Person.setName(java.lang.String)
方法->public void blog.Study.Person.print()
方法->public void blog.Study.Person.setAge(int)
方法->public int blog.Study.Person.getAge()
Person{
     name='xxx', age=18}

效率问题

测试代码如下:

import blog.Study.Person;

import java.lang.reflect.Constructor;

public class study {
     
    public static void main(String[] args) throws Exception{
     
        String path = "blog.Study.Person";
        Class c = Class.forName(path);
        long RTimeStart = System.currentTimeMillis();
        Person person1;
        Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
        for(int i = 0; i < 999999; i++)
            person1 = (Person) constructor.newInstance("xxx", 18);
        long RTimeEnd = System.currentTimeMillis();
        Person person2;
        for(int i = 0; i < 999999; i++)
            person2 = new Person("xxx", 18);
        long UTmieEnd = System.currentTimeMillis();
        System.out.println("反射时间:" + (RTimeEnd - RTimeStart) + "ms");
        System.out.println("普通时间:" + (UTmieEnd - RTimeEnd) + "ms");
    }
}//输出如下
反射时间:58ms
普通时间:4ms

采用反射机制的Java程序要经过字节码解析过程,将内存中的对象进行解析,包括了一些动态类型,而JVM无法对这些代码进行优化,因此,反射机制的效率比那些非反射操作效率低得多。

你可能感兴趣的:(Java学习笔记)