JAVA 反射机制

71 阅读4分钟

反射机制概述(Reflection)

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看 到类的结构,所以,我们形象的称之为:反射。

正常的对象获取流程

image.png

通过反射获取

image.png

静态语言和动态语言

静态语言

程序在运行和时候其结构不能被改变的语言称之为 "静态语言" 例如:C、C++、Java

动态语言

程序在运行的过程中其结构可以被改变的语言称之为 "动态语言" 例如:python、PhP

通过反射获取class实例的几种方法

方式一:通过class的方式

Class<String> aClass = String.class;
System.out.println(aClass);

方式二:通过getClass()方式

Class<? extends String> aClass1 = "hello Java".getClass();
System.out.println(aClass1);

方式三:通过Class.forName()

try {
    Class<?> hello_java = Class.forName("java.lang.String");
    System.out.println(hello_java);
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

方式四:通过类的加载器

ClassLoader classLoader = ReflectionDemo.class.getClassLoader();
Class<?> aClass2 = classLoader.loadClass("java.lang.String");
System.out.println(aClass2);

读取配置文件

方式1 Properties + FileInputStream 的方式

@Test
public void reflectionTest2() throws IOException {
    Properties pros = new Properties();
    FileInputStream fis = new FileInputStream("prop.properties");
    pros.load(fis);
    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    System.out.println("user = " + user + "  password = " + password);
}

方式2:通过类名.classLoader的方式,默认配置文件识别在module 的src下

@Test
public void reflectionTest3() throws IOException {
    Properties pros = new Properties();

    ClassLoader classLoader = ReflectionDemo.class.getClassLoader();
    InputStream is = classLoader.getResourceAsStream("prop1.properties");
    pros.load(is);

    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    System.out.println("user = " + user + "  password = " + password);
}

通过反射获取实例对象

方式1:通过newInstance的方式

在这里要注意,使用newInstance的方式调用的是空参的构造器,如果没有空参构造,会报异常 在空参构造器权限为private 的时候也会报异常

@Test
public void reflectionTest4() throws IllegalAccessException, InstantiationException {
    Class<Person> clazz = Person.class;
    Person person = clazz.newInstance();
    System.out.println(person);
}

获取运行时类的属性结构

测试的Bean

public class Creature<T> implements Serializable {

    private char gender;
    public double weight;
    private void breath(){
        System.out.println("生物呼吸");
    }
    public void eat(){
        System.out.println("生物吃东西");
    }
}



public interface MyInterface {
    void info();
}


@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotition {
    String value() default "hello";
}


@MyAnnotition("hi")
public class Person extends Creature<String> implements Comparable<String>,MyInterface{
    private String name;
    int age;
    public int id;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @MyAnnotition()
    public String show(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }

    public String display(String insterests){
        return insterests;
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    @Override
    public void info() {
        System.out.println("我是一个人");
    }
}

获取属性

  • getFields()
Class<Person> clazz = Person.class;
Field[] fields = clazz.getFields();
for (Field item : fields){
    System.out.println(item);
}

执行结果 image.png 可以看到他只是打印了类型为public的属性。所以通过getFieIds获取属性他只会获取到子类和父类中属性为public的属性

  • getDeclaredFields()
Class<Person> clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field item : declaredFields){
    System.out.println(item);
}

image.png 获取到它自身的属性但是不包含它父类中的属性,任何权限的都可以获取的到

获取权限修饰、数据类型、变量名

  • getModifiers()
  • getType()
  • getName()
Class<Person> clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field item : declaredFields){
    //获取权限修饰符
    int modifiers = item.getModifiers();
    System.out.print(Modifier.toString(modifiers) + "\t");
    //获取数据类型
    Class type = item.getType();
    System.out.print(type.getName() + "\t");
    //获取变量名
    String fname = item.getName();
    System.out.print(fname);
    System.out.println();
}

获取方法

  • getMethods
Class<Person> clazz = Person.class;

Method[] methods = clazz.getMethods();
for (Method mItem : methods){
    System.out.println(mItem);
}

image.png 获取当前运行时类及其所有父类中声明为public权限的方法

  • getDeclaredMethods()
Class<Person> clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method mItem : declaredMethods){
    System.out.println(mItem);
}

image.png 获取到运行时类中的所有的方法(不包含父类中声明的方法)

获取方法的内部结构

  • 获取方法声明的注解 getAnnotations()

  • 获取权限的修饰符 getModifiers()

  • 获取到方法的权限 getReturnType().getName()

  • 获取到方法名 getName()

Class<Person> clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method mItem : declaredMethods){
    //1.获取到声明方法的注解
    Annotation[] annotations = mItem.getAnnotations();
    for (Annotation aItem:annotations){
        System.out.print(aItem);
    }
    //2.权限修饰符
    System.out.print(Modifier.toString(mItem.getModifiers()) + "\t");
    //3.方法的返回值类型
    System.out.print(mItem.getReturnType().getName() + "\t");
    //4.获取到方法名
    System.out.print(mItem.getName() + "\t");
    System.out.println(mItem);

获取到运行时类的构造器

  • 获取到当前运行时类中声明为public的构造器 getConstructors()
Class<Person> clazz = Person.class;
Constructor[] constructors = clazz.getConstructors();
for (Constructor cItem:constructors){
    System.out.println(cItem);
}
  • 获取到当前类中的构造器 getDeclaredConstructors()
Class<Person> clazz = Person.class;
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor cItem : declaredConstructors){
    System.out.println(cItem);
}

获取运行时类的指定属性

Class<Person> clazz = Person.class;
Person person = clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(person,"tom");
System.out.println(person);

获取指定的构造器

Class<Person> clazz = Person.class;
Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Person per = constructor.newInstance("Tom");
System.out.println(per);