Java 反射基础

2022-07-22  本文已影响0人  Tinyspot

1. 反射

1.1 反射应用场景

1.2 优缺点

2. 反射相关的类

3. 示例

反射技术:就是一套用来描述类的API
一个类被加载后,类的整个结构都被封装在 Class 对象中

// this.getClass().getClassLoader()
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = classLoader.loadClass("com.example.pojo.Person");

3.1 反射获取属性

不能直接操作私有属性,需关闭程序的安全检测 filed.setAccessible(true);

/**
 * all the accessible public fields
 * including all its superclasses, all its superinterfaces
 */
Field[] fields = clazz.getFields();
/**
 * This includes public, protected, default (package) access, and private fields
 * but excludes inherited fields
 */
Field[] declaredFields = clazz.getDeclaredFields();
Class<?> clazz = Student.class;
Student student = (Student) clazz.newInstance();
Field filed = clazz.getDeclaredField("age");
// 允许访问私有属性
filed.setAccessible(true);
filed.set(student, 20);

3.2 反射获取方法

/**
 * all the public methods
 * including inherited from superclasses and superinterfaces.
 */
Method[] methods = clazz.getMethods();
/**
 * all the declared methods, including public, protected, default (package) access, and private methods, 
 * but excluding inherited methods.
 */
Method[] declaredMethods = clazz.getDeclaredMethods();

// demo
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    // 打印看看
    System.out.println(method.toString());
}

// java.lang.reflect.Method#invoke(对象,"方法的参数值")
public Object invoke(Object obj, Object... args) {
}

反射获取方法,要加参数,因为方法有重载

public static void main(String[] args) throws Exception {
    Class<?> clazz = Student.class;
    Student student = (Student) clazz.newInstance();

    Method publicMethod = clazz.getMethod("setName", String.class);
    publicMethod.invoke(student, "boy");

    /**
     * with modifiers "private"
     * 调用私有方法要设置访问权限
     */
    Method privateMethod = clazz.getDeclaredMethod("test");
    privateMethod.setAccessible(true);
    privateMethod.invoke(student);

    // 调用静态方法不需要传对象,直接写 null
    Method staticMethod = clazz.getDeclaredMethod("demo", String.class);
    staticMethod.setAccessible(true);
    staticMethod.invoke(null, "boy");
}

3.3 获取构造方法

public class Student extends Person implements Serializable {
    private String lesson;
    public Student() {}
    public Student(String lesson) {
        this.lesson = lesson;
    }
    @Override
    public String toString() {
        return "Student [lesson=" + lesson +"]";
    }
}

public static void main(String[] args) throws Exception {
    Class<?> clazz = Student.class;
    Constructor<?>[] constructors = clazz.getConstructors();
    System.out.println(Arrays.toString(constructors));

    Constructor<?> constructor = clazz.getConstructor();
    // Constructor.newInstance(Object ... initargs) 不传参数表示调用无参构造方法
    Student student = (Student) constructor.newInstance();
    System.out.println(student.toString());

    Constructor<?> constructor2 = clazz.getConstructor(String.class);
    Student student2 = (Student) constructor2.newInstance("English");
    System.out.println(student2.toString());
}

3.4 操作对象实例

一旦某个类型的Class对象已经被加载到内存,就可以用它来产生该类型的所有对象

// ----------- 静态方法和非静态方法调用是不一样的 ------------
// main() 静态方法
Method staticMethod = clazz.getMethod("main", String[].class);
staticMethod.invoke(null, (Object) new String[] {});

/**
 * 非静态方法的调用要有一个类实例
 * newInstance() 不传参数时,调用类中缺省的构造方法(本质是调用类的无参构造器)
 */
User user = (User) clazz.newInstance();
// User user = clazz.getDeclaredConstructor().newInstance();
Constructor<User> constructor = clazz.getDeclaredConstructor(int.class, String.class);
User user2 = constructor.newInstance(20, "xiao");

动态语言与静态语言

其他

JackSON 如何序列化和反序列化的
Junit 如何找到 加了 @Test, @After, @Before 注解的方法, 并自动编排这些方法,完成整个单元测试流程的

上一篇 下一篇

猜你喜欢

热点阅读