侧边栏壁纸
博主头像
Dioxide-CN博主等级

茶边话旧,看几许星迢露冕,从淮海南来。

  • 累计撰写 50 篇文章
  • 累计创建 49 个标签
  • 累计收到 21 条评论

目 录CONTENT

文章目录

Java基础知识:注解与反射

Dioxide-CN
2022-03-12 / 0 评论 / 7 点赞 / 123 阅读 / 7,089 字
温馨提示:
本文最后更新于 2022-08-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

反射的概念

什么是反射

反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

每个类都有一个自身的 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。

反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。

Classjava.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用 private 方法)
  • 在运行时调用任意一个对象的方法

反射的优点

  • 可扩展性:应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
  • 类浏览器和可视化开发环境:一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
  • 调试器和测试工具:调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。

反射的缺点

  • 性能开销:反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
  • 安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
  • 内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

反射构造对象

package cn.dioxide.cn;

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

public class arraylist_t {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得一个class类对象  
        Class c1 = Class.forName("cn.dioxide.cn.User");
        User user = (User) c1.newInstance(); //调用类的无参构造器  
        System.out.println(user);

        //通过构造器创建对象  
        Constructor con = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User) con.newInstance("李四", 001, 18);
        System.out.println(user2);

        //通过反射调用普通方法  
        User user3 = (User) c1.newInstance();
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user3, "张三"); //invoke方法激活:("方法名", "对象值")  
        System.out.println(user3.getName());

        //通过反射操作属性  
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true); //绕过private保护  
        name.set(user4, "王五");
        System.out.println(user4.getName());
    }
}

反射与注解

package cn.dioxide.cn;

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

public class arraylist_t {
    //普通构造器	  19ms
    public static void demo1() {
        User u1 = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            u1.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cost time: " + (endTime - startTime) + "ms");
    }
    //反射构造器	  2183ms
    public static void demo2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User u1 = new User();
        Class c1 = u1.getClass();
        Method getname = c1.getDeclaredMethod("getName", null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getname.invoke(u1, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cost time: " + (endTime - startTime) + "ms");
    }
    //反射构造器 权限越级	1138ms
    public static void demo3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User u1 = new User();
        Class c1 = u1.getClass();
        Method getname = c1.getDeclaredMethod("getName", null);
        getname.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getname.invoke(u1, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("cost time: " + (endTime - startTime) + "ms");
    }
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        demo1();
        demo2();
        demo3();
    }
}

反射操作泛型

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

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 arraylist_t {
    //反射解析泛型  
    public static void demo1(Map < String, User > map, List < User > list) {
        System.out.println("test01");
        return;
    }
    public Map < String, User > demo2() {
        System.out.println("test02");
        return null;
    }
    public static void main(String[] args) throws NoSuchMethodException {
        Method method = arraylist_t.class.getMethod("demo1", 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("demo1 " + actualTypeArgument);
                }
            }
        }
        method = arraylist_t.class.getMethod("demo2", null);
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            //判断参数类型  
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument: actualTypeArguments) {
                System.out.println("demo2 " + actualTypeArgument);
            }
        }
    }
}

反射操作注解

package cn.dioxide.cn;

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

public class arraylist_t {
    //反射操作注解  
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("cn.dioxide.cn.student");
        //通过反射获得注解类  
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation: annotations) {
            System.out.println(annotation);
        }
        //获得注解的value值  
        Dioxide dioxide = (Dioxide) c1.getAnnotation(Dioxide.class);
        String value = dioxide.value();
        System.out.println(value);
        //获得类指定的注解  
        Field f = c1.getDeclaredField("name");
        FieldDioxide annotation = f.getAnnotation(FieldDioxide.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}

@Dioxide(value = "db_student")
class student {
    @FieldDioxide(columnName = "db_id", type = "int", length = 10)
    private int id;
    @FieldDioxide(columnName = "db_age", type = "int", length = 10)
    private int age;
    @FieldDioxide(columnName = "db_name", type = "varchar", length = 10)
    private String name;

    public student() {}

    public student(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.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;
    }

    @Override
    public String toString() {
        return "student{" +
            "id=" + id +
            ", age=" + age +
            ", name='" + name + '\'' +
            '}';
    }
}
//类名注解  
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Dioxide {
    String value();
}
//属性注解  
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldDioxide {
    String columnName();
    String type();
    int length();
}
7

评论区