5 创建类的对象与调用方法的方式

1 有了Class对象,能做什么?

  • 创建类的对象:调用Class对象的newInstance() 方法
    • 1)类必须有一个无参数的构造器
    • 2)类的构造器的访问权限需要足够

思考? 难道没有无参的构造器就不能创建对象了吗?只要在操作时明确的调用类的构造器,并把参数传递进去之后,才可以实例化操作。

步骤如下:

  • 1)通过Class类的getDeclaredConstructor(Class … parameterTypes) 取得本类的指定形参类型的构造器
  • 2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
  • 3)通过Constructor实例化对象

2 调用指定的方法

通过反射,调用类中的方法,通过Method类完成。
① 通过Class类的getMethod(String name, Class…parameterTypes) 方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
② 之后使用Object invoke(Object obj,Object[] args) 进行调用,并向方法中传递要设置的obj对象的参数信息。

5 创建类的对象与调用方法的方式_第1张图片

3 调用指定的方法

Object invoke(Object obj,Object … args)

  • Object对应原方法的返回值,若原方法无返回值,此时返回null
  • 若原方法为静态方法,此时形参Object obj可为null
  • 若原方法形参列表为空,则Object[] args为null
  • 若原方法声明为private,则需要在调用此invoke()方法前,显示调用方法对象的setAccessible(true)方法,将可访问private的方法。

4 setAccessible

  • Method和Field、Constructor对象都要setAccessible()方法
  • setAccessible作用是启动和禁用访问安全检查的开关
  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查
    • 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
    • 使得原本无法访问的私有成员也可以访问
  • 参数值为false则指示反射的对象应该实施Java语言访问检查

4.1 提高反射效率的代码演示

package com.annotation;

import com.annotation.bean.User;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test9 {
    public static void test01(){
        User user = new User();

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法执行10亿次所需时间:"+(endTime-startTime)+"ms");
    }

    public static void test02() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class c1 = Class.forName("com.annotation.bean.User");
        User user = (User) c1.newInstance();
        //User user = new User();
        Method getName = c1.getDeclaredMethod("getName", null);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法执行10亿次所需时间:"+(endTime-startTime)+"ms");
    }

    public static void test03() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class c1 = Class.forName("com.annotation.bean.User");
        User user = (User) c1.newInstance();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("关闭检测执行10亿次所需时间:"+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        test01();
        test02();
        test03();
    }
    
    /* 运行结果:
    普通方法执行10亿次所需时间:7ms
    反射方法执行10亿次所需时间:4251ms
    关闭检测执行10亿次所需时间:2423ms
     */
}

5 代码演示

(1)创建实体类 User

package com.annotation.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
}

(2)测试

package com.annotation;

import com.annotation.bean.User;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test8 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        // 获得Class对象
        Class c1 =  Class.forName("com.annotation.bean.User");

        // 构造一个对象
        User user = (User)c1.newInstance(); // 本质是调用了无参构造
        System.out.println(user);
        /* 结果:User(id=0, name=null) */

        // 通过构造器创建对象
        System.out.println("----");
        Constructor constructor = c1.getDeclaredConstructor(int.class,String.class);
        User user2 = (User) constructor.newInstance(1,"张三");
        System.out.println(user2);
        /* 结果:User(id=1, name=张三) */

        // 调用普通方法
        System.out.println("----");
        user.setName("张三");
        System.out.println(user.getName());
        /* 结果:张三 */

        // 通过反射获取一个方法,然后调用普通方法
        System.out.println("----");
        Method setName = c1.getDeclaredMethod("setName",String.class);
        setName.invoke(user,"狂神");  // invoke:激活的意思
        System.out.println(user.getName());
        /* 结果:狂神 */

        // 通过反射操作属性
        System.out.println("----");
        Field name = c1.getDeclaredField("name");
        // 不能直接操作私有属性,我们需要关闭程序的安全检测
        name.setAccessible(true);
        name.set(user,"狂神2");
        System.out.println(user.getName());
        /* 结果:狂神2 */
    }
}

你可能感兴趣的:(java)