注解与反射 - 反射 - 操作反射

获取类的运行时状态

//获取类的信息
public class Test05 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.mayb.demo02.Son");

        Son01 son01 = new Son01();
        //通过反射
        c1 = son01.getClass();
        System.out.println(c1.getName());//获取类的名称  包名 + 类名
        System.out.println(c1.getSimpleName());//获取类的简单名称  类名
    }
}

class Son01{
    private int m = 10;
}

通过反射获取运行时类的完整结构
Field(属性)、Method(方法)、Constructor(构造器)、 Superclass(父类)、 Interface(接口)、 Annotation(注解)

实现的全部接口 ,所继承的父类,全部的构造器,全部的方法,全部的Field,注解等

获取在运行时类的完整结构

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

//获取类的信息
public class Test05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.mayb.demo02.Son");

        System.out.println(c1.getName());//获取类的名称  包名 + 类名
        System.out.println(c1.getSimpleName());//获取类的简单名称  类名
        System.out.println("<-------------------------->");

        //获取类的属性
        Field[] fields = c1.getFields();//只能找到public属性
        for (Field field : fields) {
            System.out.println(field);
        }

        fields = c1.getDeclaredFields();//获取全部属性
        for (Field field : fields) {
            System.out.println(field);
        }

        Field m = c1.getDeclaredField("m");//获取指定属性
        System.out.println(m);
        System.out.println("<-------------------------->");

        //获取类的方法
        Method[] methods = c1.getMethods(); // 包括本类和父类的全部public方法
        for (Method method : methods) {
            System.out.println("public : "+method);
        }

        methods = c1.getDeclaredMethods();//仅获取本类的所有方法
        for (Method method : methods) {
            System.out.println("全部的 : "+ method);
        }
        //获取指定方法 小心重载
        Method method = c1.getMethod("aVoid", String.class); //需要public
        System.out.println(method);
        method = c1.getDeclaredMethod("cVoid", String.class);//这个是全部的
        System.out.println(method);
        method = c1.getMethod("bVoid", String.class, int.class, int.class);
        System.out.println(method);
        System.out.println("<-------------------------->");

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

        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("All : "+constructor);
        }
        //获取指定的构造器
        Constructor constructor = c1.getConstructor(int.class, int.class);
        System.out.println(constructor);
        constructor = c1.getDeclaredConstructor();
        System.out.println("All"+constructor);
    }
}

Class.forName 的Son类

public class Son {
    private int m = 100;
    public  int M = 1;
    public void aVoid(String a ){}
    private void cVoid(String a ){}
    public void  bVoid(String a ,int b,int c){}
    public Son() {}
    public Son(int m, int m1) {
        this.m = m;
        M = m1;
    }
}

使用反射操作对象

创建类的对象:调用Class对象的newInstance()方法

  1. 类必须有一个无参数的构造器。
  2. 类的构造器的访问权限需要足够

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

步骤如下:

  1. 通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构
    造器
  2. 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
  3. 通过Constructor实例化对象
//动态的创建对象,通过反射
public class Test05 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        // 获得Class对象
        Class c1 = Class.forName("com.mayb.demo02.Son");

        // 构造一个对象
        Son son1 = (Son) c1.newInstance();//本质上调用无参构造 没无参构造就会错误
        System.out.println(son1);

        //通过构造器构造对象
        Constructor constructor =  c1.getConstructor(int.class,int.class);
        Son son2 = (Son) constructor.newInstance(1,1);
        System.out.println(son2);

        //  通过反射调用方法
        Son son3 = (Son) c1.newInstance();

        Method method =  c1.getDeclaredMethod("setName", String.class);
        //给那个对象调用方法传入的参数 invoke 激活方法
        //第一参数为对象  第二为参数值
        method.invoke(son3,"Mayb");
        System.out.println(son3.getName());

        // 通过反射操作属性
        Son son4 = (Son) c1.newInstance();
        Field name = c1.getDeclaredField("name");//不能为私有的属性
        // 是否开启关闭检查 开启了就可以给私有属性设值(程序的安全检测 setAccessible)
        name.setAccessible(true);//降低程序效率
        name.set(son4,"Mayb2");
        System.out.println(son4.getName());
    }
}

setAccessible

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

//分析性能问题
public class Test06 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }

    // 普通方式调用
    public static void test01(){
        Son son = new Son("Mayb");

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            son.getName();
        }
        long endTime = System.currentTimeMillis();

        System.out.println("普通方法执行时间:" + (endTime - startTime));
    }

    // 反射方式调用
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Son son = new Son("Mayb");
        Class c1 = son.getClass();
        Method getName = c1.getDeclaredMethod("getName",null);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(son,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方式调用:" + (endTime - startTime));
    }

    // 反射方式调用  关闭安全检查
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Son son = new Son("Mayb");
        Class c1 = son.getClass();
        Method getName = c1.getDeclaredMethod("getName",null);
        getName.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(son,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("关闭安全检查:" + (endTime - startTime));
    }
}

结果

普通方法执行时间:3
反射方式调用:1999 
关闭安全检查:1320

如果在使用时调用很多次反射方法可以关闭安全检测

通过反射获取泛型

泛型是一种约束机制

  • Java采用泛型擦除的机制来弓|入泛型, Java中的泛型仅仅是给编译器javac使用的,确保数据
    的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除
  • 为了通过反射操作这些类型, Java新增了ParameterizedType , GenericArrayType,
    TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原
    始类型齐名的类型.
  • ParameterizedType :表示- -种参数化类型,比如Collection
  • GenericArrayType :表示一种元素类型是参 数化类型或者类型变量的数组类型
  • TypeVariable :是各种类型变量的公共父接口
  • WildcardType :代表一种通配符类型表达式
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 Test07 {

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

    public Map<String,Son> test02(){
        System.out.println("test02");
        return null;
    }
    
    public static void main(String[] args) throws NoSuchMethodException {
        Method test01 = Test07.class.getDeclaredMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = test01.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("genericParameterType : "+genericParameterType);
            //如果泛型的参数类型 genericParameterType 属于 参数化类型
            if (genericParameterType instanceof ParameterizedType){
                //获取真实类型
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        
        test01 = Test07.class.getDeclaredMethod("test02",null);
        Type genericReturnType = test01.getGenericReturnType();//返回类型
        if (genericReturnType instanceof ParameterizedType){
            //获取真实类型
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("actualTypeArgument: " + actualTypeArgument);
            }
        }

    }
}

反操作注解

getAnnotations
getAnnotation

通过注解和反射完成ORM 对象关系映射

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

public class Test08 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.mayb.demo02.Student");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解value 的值
        TableStudent tableStudent = (TableStudent)c1.getAnnotation(TableStudent.class);
        String value = tableStudent.value();
        System.out.println(value);


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

    }

}

@TableStudent("db_student")
class Student{
    @FieldInterface(columnName = "db_id",type = "int",length = 10)
    private int id;
    @FieldInterface(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldInterface(columnName = "db_name",type = "varchar",length = 10)
    private String name;

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

    public int getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public Student() {
    }

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


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

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldInterface{
     String columnName();
     String type();
     int length();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值