Java反射获取类的信息、动态创建对象、操作泛型、注解

1、通过反射获取类的类名、属性等信息

package cn.sxy.demo02;

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

public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("cn.sxy.demo02.User");

        //获取类名
        System.out.println(c1.getName());
        System.out.println(c1.getSimpleName());
        System.out.println("==============");
        //获取类的属性
        Field[] fields = c1.getDeclaredFields(); //找到全部属性
        //Field[] fields = c1.getFields(); //只能找到public属性
        for (Field field : fields) {
            System.out.println(field);
        }
        //获取指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);
        System.out.println("==================");
        //获得类的方法
        Method[] methods = c1.getMethods();//获得本类及其父类的全部public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-------------------");
        methods = c1.getDeclaredMethods();//获得本类的所有方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("====================");
        //获得指定的方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        System.out.println("====================");
        //获得构造器
        Constructor[] constructors = c1.getConstructors();//public方法
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        constructors = c1.getDeclaredConstructors();//本类的全部方法
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println("=====================");
        //获得指定的构造器
        Constructor constructor = c1.getConstructor();
        System.out.println(constructor);
    }
}

2、 通过反射动态的创建对象 

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

(2)创建步骤:

         ① 通过Class类的getDeclaredConstructor(Class ... parameterTypes)获取本类的指定形参类型的构造器

         ② 向构造器的形参中传递一个对象数组进去,包含构造器中所需的各个参数

         ③ 通过Constructor实例化对象

(3)调用指定的方法:通过反射,调用类中的方法,使用Method类完成

         ① 通过Class类的getMethod(String name,Class ...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型

         ② 使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的object对象的参数信息

         ③ Object对应原方法的返回值,若原方法无返回值,则返回null

         ④ 若原方法为静态方法,则形参Object obj 可为 null

         ⑤ 若原方法形参列表为空,则Object[] args 为 null

         ⑥ 若原方法声明为private,则需要在调用invoke()方法之前,显式调用方法对象的setAccessible(true)方法,将可以访问private修饰的方法

package cn.sxy.demo02;

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

//通过反射,动态的创建对象
public class Test08 {
    public static void main(String[] args) throws Exception {
        //获得class对象
        Class c1 = Class.forName("cn.sxy.demo02.User");
        //构造一个对象
        /*User user = (User) c1.newInstance(); //本质上是调用了类的无参构造器
        System.out.println(user);*/

        //通过构造器创建对象
        /*Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, int.class);
        User user2 = (User) constructor.newInstance(1, "ceshi", 18);
        System.out.println(user2);*/

        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke :激活
        //(对象,"方法的值")
        setName.invoke(user3, "测试");
        System.out.println(user3.getName());
        System.out.println("===============");

        //通过反射操作属性
        User user4 = (User) c1.newInstance();

        Field name = c1.getDeclaredField("name");

        //不能直接操作私有属性,需要关闭程序的安全检测,属性或方法的setAccessible(true)
        name.setAccessible(true);
        name.set(user4, "测试2");
        System.out.println(user4.getName());

    }
}

注:① Mehtod和Filed、Constructor对象都有setAccessible()方法

       ② setAccessible()的作用是启动和禁用访问安全检查的开关

       ③ 参数值为true,则指示反射的对象在使用时应该取消Java语言访问检查(提高反射的效率,若代码中必须使用反射,而该句代码频繁被调用,则设置为true;使得原本无法访问的私有成员也可以访问)反之,参数值为false,则指示反射的对象应该实施Java语言访问检查。

3、性能对比分析(普通方式,反射中使用setAccessible与不使用)

package cn.sxy.demo02;

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

/**
 * 性能对比分析
 */
public class Test09 {

    //普通方式
    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 InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getMethod("getName");

        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 InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getMethod("getName");
        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 InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        test01();
        test02();
        test03();
    }
}

4、反射操作泛型

(1)Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是一旦编译完成,所有和泛型有关的类型全部擦除。

(2)为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。

(3)ParameterizedType:表示一种参数化类型,比如Collection<String>

(4)GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

(5)TypeVariable:是各种类型变量的公共父接口

(6)WildcardType:代表一种通配符类型表达式

package cn.sxy.demo02;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

//通过反射获取泛型
public class Test10 {

    public static void test01(Map<String, User> map, List<User> list) {
        System.out.println("test01");
    }

    public static Map<Integer, User> test02() {
        System.out.println("test02");
        return null;
    }


    public static void main(String[] args) throws NoSuchMethodException {
        //获取方法
        Method method = Test10.class.getMethod("test01", Map.class, List.class);
        //通过方法获取泛型的参数化类型
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println(genericParameterType);
            if (genericParameterType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        System.out.println("=====================");
        //获取参数的返回值类型
        method = Test10.class.getMethod("test02", null);

        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            //获取真实类型参数
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}

5、反射操作注解(getAnnotations、getAnnotation)

 

package cn.sxy.demo02;

import java.lang.annotation.*;
import java.lang.reflect.Field;

//通过反射操作注解
public class Test11 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("cn.sxy.demo02.Account");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获得注解的value值
        Table_Test table_test = (Table_Test) c1.getAnnotation(Table_Test.class);
        String value = table_test.value();
        System.out.println(value);
        System.out.println("==============");

        //获取类的指定注解
        Field id = c1.getDeclaredField("id");
        Filed_Test filed_test = id.getAnnotation(Filed_Test.class);
        System.out.println(filed_test.columnName());
        System.out.println(filed_test.type());
        System.out.println(filed_test.length());
    }
}

@Table_Test("tb_account")
class Account {
    @Filed_Test(columnName = "_id", type = "int", length = 10)
    private int id;
    @Filed_Test(columnName = "_name", type = "int", length = 10)
    private String name;
    @Filed_Test(columnName = "_age", type = "int", length = 10)
    private int age;

    public Account() {
    }

    public Account(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table_Test {
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Filed_Test {
    String columnName();

    String type();

    int length();
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shexianyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值