Java进阶笔记--反射机制

反射中几个类的定义和获取

Class类的获取

Class中包含了某个类中的所有信息,比如构造函数、变量域、函数等信息,还可以通过Class类来实例化,在动态加载类中使用较广泛。

首先,设置背景,假设有一个类Person,置于src包中的com.ss包中:

package com.ss;

import java.util.Date;

public class Person{

    public Person(){}
    public Person(String name, int age){}
    protected Person(boolean sex){};
    private Person(Date birthday){};

    void speak(){
        System.out.println("Hello world, I am a person");
    }
}

  1. 通过.class属性
   Class<Person> clazz = Person.class;
  1. 通过getClass() 方法
   Person person;
   Class<Person> clazz = (Class<Person>) person.getClass(); //此处注意需要进行类型强制转换
  1. 通过forName()方法

    注意传入的参数,类名应为全称,package之间的包含关系使用.号进行间隔。

   String className = "com.ss.Person";
   Class<?> clazz = Class.forName(className);

测试时,可以直接使用Class类的toString方法,打印出class的信息,如:

 public static void main(String[] args) {
        Person person;
        Class<Person> clazz = Person.class;
        System.out.println(clazz.toString());
 }

输出结果为:

class com.ss.Person

Constructor对象的获取

Constructor类专门用来描述构造函数,可以通过它来获取类的构造方法名称、访问权限,还可以通过Constructor来创建类的实例。

首先,假设Person类中有四个不同的构造函数:

public class Person{
    public Person(){}
    public Person(String name, int age){}
    protected Person(boolean sex){};
    private Person(Date birthday){};
}
  1. 通过指定参数列表获取

    只能获取public的构造函数

    Class<Person> clazz = Person.class;
    Constructor constructor; 
    constructor = clazz.getConstructor();
    constructor = clazz.getConstructor(String.class, int.class);
    

    可以获取所有构造函数

   Class<Person> clazz = Person.class;
   Constructor constructor;
   constructor = clazz.getDeclaredConstructor();
   constructor = clazz.getDeclaredConstructor(String.class, int.class);
   constructor = clazz.getDeclaredConstructor(boolean.class);
   constructor = clazz.getDeclaredConstructor(Date.class);
  1. 获取全部构造函数,返回Constructor数组

    只能获取public的所有构造函数

    Class<Person> clazz = Person.class;
    Constructor[] constructors = clazz.getConstructors();
    

    可以获取所有构造函数

   Class<Person> clazz = Person.class;
   Constructor[] constructors = clazz.getDeclaredConstructors();

与打印Class类的信息相同,只需要用toString方法就可以得到某个类构造函数的信息,如:

public static void main(String[] args) {
    Person person;
    Class<Person> clazz = Person.class;
    Constructor[] constructors = clazz.getDeclaredConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor.toString());
    }
}

输出结果为:

private com.ss.Person(java.util.Date)
protected com.ss.Person(boolean)
public com.ss.Person(java.lang.String,int)
public com.ss.Person()

Method对象的获取

Method类的对象用于描述类的单个方法,可以通过Method类来获取方法的访问权限、参数类型、返回值类型等信息。并且可以通过获取的Method对象来动态执行方法。

首先,设置背景,有一接口Speakable:

public interface Speakable {
    public void speak();
    public void speak(String message);

}

Person抽象类实现接口Speakable:

public abstract class Person implements Speakable{
    private void useTool(){};
    private void useTool(String toolName){};
    public void eat(String food){};
    public final void fly(){};
    public native void think();
}
  1. 通过参数列表获取

    只能获取public的方法

    //仅有一个参数时,代表得到参数列表为空的speak方法
    Class clazz = Person.class;
    Method method = clazz.getMethod("speak"); 
    
    //两个以上的参数,第一个参数是方法名,后面紧跟参数列表的class
    Class clazz = Person.class;
    Method method = clazz.getMethod("eat",String.class);
    

    获取所有的方法

   Class clazz = Person.class;
   Method method = clazz.getDeclaredMethod("useTool");
   method = clazz.getDeclaredMethod("useTool", Stirng.class);
  1. 获取所有方法,用数组返回

    只能获取public的所有函数

    Class clazz = Person.class;
    Method[] methods = class.getMethods();
    

    获取所有函数方法

    Class clazz = Person.class;
    Method[] methods = class.getDeclaredMethods();
    

打印出所有函数方法:

public static void main(String[] args) {
    Person person;
    Class<Person> clazz = Person.class;
    Method[] methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
        System.out.println(method.toString());
    }
}

输出结果为:

private void com.ss.Person.useTool(java.lang.String)
private void com.ss.Person.useTool()
public void com.ss.Person.eat(java.lang.String)
public final void com.ss.Person.fly()
public native void com.ss.Person.think()

Field对象的获取

Field类的对象用于描述类的单个字段,可以通过Field对象来获取字段的访问权限、字段类型等信息。并且可以通过获取的Field对象来动态修改字段值。

与Method和Constructor的获取方法基本一致,不再赘述。

//返回一个Field对象,反映此Class对象所表示的类或接口指定的public成员字段
public Field getField(String name); 

//返回一个包含Field 对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问public字段 
public Field[] getFields();

//返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段
public FieldgetDeclaredField(Stringname);

//返回一个Field的数组,该数组记录指定类的所有属性的描述对象。如果指定类没有属性,则返回一个空数组
public Field[] getDeclaredFields();

反射的具体操作

通过反射实例化类

  1. Class类的newInstance()方法

    Class<Person> clazz = Person.class;
    Person person = (Person) clazz.newInstance(); //需要强制类型转换
    
  2. Constructor的newInstance()方法

    Class<Person> clazz = Person.class;
    Constructor constructor = clazz.getConstructor();
    Person person;
    
  3. invoke方法的第一个参数,传入指定的对象(即指定需要执行哪个对象的函数),接下来的参数是执行方法中需要传入的函数参数。

    Class<Person> clazz = Person.class;
    Person teacher = clazz,=.newInstance();
    Method method = clazz.getMethod("speak",String.class);
    method.invoke(teacher,"Lesson one!");  
    

通过反射修改属性

Teacher teacher;
Constructor constructor = clazz.getConstructor();
teacher = (Teacher) constructor.newInstance();
Field field = (Field) clazz.getField("teacherName");
field.set(teacher,"Jack");

修改访问权限

Field、Method以及Constructor的父类AccessiableObject提供一个方法setAccessiable(boolean flag),该方法用于设置访问对象的accessiable标志,该标志为true时,反射的对象在使用时取消java语言访问检查,此时就可以顺利使用反射对象。

猜你喜欢

转载自blog.csdn.net/m0_37281837/article/details/86177691
今日推荐