JAVA反射详解(JAVA Reflection)

JAVA Reflection 定义

  • 反射是Java被视为动态语言的关键,反射机制允许程序在执行过程中借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
  • 类加载完成后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的机构。这个对象就像一面镜子,透过这个镜子能看到类的结构,因此,被形象的称为**“反射”** 。
    • 优点:可以实现动态创建对象和编译,体现出很大的灵活性;
    • 缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

Class类

  • 定义:
    对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留了一个不变的Class类型的对象。一个Class对象包含了特定某个结构的有关信息。
  • 特点:
    • Class本身也是一个类,继承自Object
    • Class对象只能由系统建立
    • 一个加载的类在JVM中只会有一个Class实例
    • 一个Class实例对应的是一个加载到JVM中的一个.class文件
    • 每个类的实例都会记得自己是由哪个Class实例所生成
    • 通过Class可以完整地得到一个类中的所有被加载的结构
    • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得Class对象
  • Class类的实例的获取方式
    • 若已经知道具体的类,可以通过类的class属性获取,该方法最为安全可靠,性能最高
      Class clazz = String.class;
      
    • 若已经知道某个类的实例,调用该实例的getClass()方法,可以获取到Class对象
      Class clazz = str.getClass();
      
    • 若已经知道某个类的全类名,且该类在类路径下,可以通过Class类的静态方法forName()进行获取,此方法可能抛出ClassNotFoundException
      Class clazz = Class.forName("java.lang.String");
      
    • 内置的基本数据类型,可以直接用类名.Type
    • 还可以利用ClassLoader来进行获取
  • 可以有class的类型:
    @Test
    public void test02() {
        Class<Object> c1 = Object.class;//类
        Class<Comparable> c2 = Comparable.class;//接口
        Class<String[]> c3 = String[].class;//一维数组
        Class<int[][]> c4 = int[][].class;//二维数组
        Class<Override> c5 = Override.class;//注解
        Class<ElementType> c6 = ElementType.class;//枚举
        Class<Integer> c7 = Integer.class;//基本数据类型
        Class<Void> c8 = void.class;//void
        Class<Class> c9 = Class.class;//Class类
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);
    }
    
    class java.lang.Object
    interface java.lang.Comparable
    class [Ljava.lang.String;
    class [[I
    interface java.lang.Override
    class java.lang.annotation.ElementType
    class java.lang.Integer
    void
    class java.lang.Class
    

类的加载与ClassLoader

  • 加载:将class字节码文件中内容加载到内存中,并将这些静态数据转换为方法区中的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
  • 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程
    • 验证:确保加载的类信息符合JVM规范,没有安全性方面的问题
    • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都在方法区中进行分配
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
  • 初始化
    • 执行类构造器()方法的过程。类构造器方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
    • 虚拟机会保证一个类的 ()方法在多线程环境中被正确加锁和同步
  • 类加载器的作用:用来把类(class)装载进内存的。JVM规范定义了如下类型的ClassLoader:
    • 引导类加载器:用C++编写,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类库。该ClassLoader无法直接获取
    • 扩展类加载器:负责jre/lib/ext 目录下的jar包或者-D java.ext.dirs指定的目录下的jar包装入工作库
    • 系统类加载器:负责java -classpath或者-D java.class.path所指的目录下的类与jar包装如工作库,是最常用的ClassLoader

Refection的用法:

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Person {

    public String name ;
    private Integer age ;
    private Integer level ;

}

@AllArgsConstructor
@NoArgsConstructor
@Data
public class MiniPerson extends Person {
    public String email ;
    private Integer num ;
}
@Test
public void test3() {
    Class c1 = MiniPerson.class ;
    //获取本类及父类中声明的所有的pulbic的field
    Field[] fields = c1.getFields();
    for (Field field : fields) {
        System.out.println(field);
    }
    System.out.println("------------------------------------------------------");
    //获取本类中声明的所有的field
    fields = c1.getDeclaredFields();
    for (Field field : fields) {
        System.out.println(field);
    }
    System.out.println("------------------------------------------------------");
    //获取本类及父类中所有声明的public的method
    Method[] methods = c1.getMethods();
    for (Method method : methods) {
        System.out.println(method);
    }
    System.out.println("------------------------------------------------------");
    //获取本类中所有声明的method
    methods = c1.getDeclaredMethods();
    for (Method method : methods) {
        System.out.println(method);
    }
    System.out.println("------------------------------------------------------");
    //获取本类中所有public的constructor,无法获取到父类的constructor
    Constructor[] constructors = c1.getConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
    System.out.println("------------------------------------------------------");
    //获取本类中所有的constructor
    constructors = c1.getDeclaredConstructors();
    for (Constructor constructor : constructors) {
        System.out.println(constructor);
    }
}
public java.lang.String com.huwc.test.reflect.MiniPerson.email
public java.lang.String com.huwc.test.reflect.Person.name
------------------------------------------------------
public java.lang.String com.huwc.test.reflect.MiniPerson.email
private java.lang.Integer com.huwc.test.reflect.MiniPerson.num
------------------------------------------------------
public boolean com.huwc.test.reflect.MiniPerson.equals(java.lang.Object)
public java.lang.String com.huwc.test.reflect.MiniPerson.toString()
public int com.huwc.test.reflect.MiniPerson.hashCode()
public void com.huwc.test.reflect.MiniPerson.setEmail(java.lang.String)
public void com.huwc.test.reflect.MiniPerson.setNum(java.lang.Integer)
public java.lang.String com.huwc.test.reflect.MiniPerson.getEmail()
public java.lang.Integer com.huwc.test.reflect.MiniPerson.getNum()
public java.lang.String com.huwc.test.reflect.Person.getName()
public void com.huwc.test.reflect.Person.setName(java.lang.String)
public java.lang.Integer com.huwc.test.reflect.Person.getLevel()
public java.lang.Integer com.huwc.test.reflect.Person.getAge()
public void com.huwc.test.reflect.Person.setLevel(java.lang.Integer)
public void com.huwc.test.reflect.Person.setAge(java.lang.Integer)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
------------------------------------------------------
public boolean com.huwc.test.reflect.MiniPerson.equals(java.lang.Object)
public java.lang.String com.huwc.test.reflect.MiniPerson.toString()
public int com.huwc.test.reflect.MiniPerson.hashCode()
public void com.huwc.test.reflect.MiniPerson.setEmail(java.lang.String)
public void com.huwc.test.reflect.MiniPerson.setNum(java.lang.Integer)
public java.lang.String com.huwc.test.reflect.MiniPerson.getEmail()
protected boolean com.huwc.test.reflect.MiniPerson.canEqual(java.lang.Object)
public java.lang.Integer com.huwc.test.reflect.MiniPerson.getNum()
------------------------------------------------------
public com.huwc.test.reflect.MiniPerson(java.lang.String,java.lang.Integer)
public com.huwc.test.reflect.MiniPerson()
------------------------------------------------------
public com.huwc.test.reflect.MiniPerson(java.lang.String,java.lang.Integer)
public com.huwc.test.reflect.MiniPerson()

反射中获取泛型

@AllArgsConstructor
@NoArgsConstructor
@Data
public class MiniPerson extends Person {
    public String email ;
    private Integer num ;


    public List<String> testGeneric(Map miniMap, Map<String, Object> map, List<String> list){
        return list ;
    }
}


@Test
public void test4() throws Exception {
    Class c1 = MiniPerson.class;
    Method method = c1.getDeclaredMethod("testGeneric", Map.class, Map.class, List.class);

    //获取所有的参数类型
    Class<?>[] parameterTypes = method.getParameterTypes();
    for (Class<?> parameterType : parameterTypes) {
        System.out.println(parameterType);
    }
    System.out.println("--------------------------------------------------------------");
    //获取所有的参数类型,如果有泛型,显示带泛型的参数类型
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        System.out.println(genericParameterType);
        System.out.println("-----------------------------------------------------------");
        //如果是泛型化类型,获取泛型中的实际类型
        if(genericParameterType instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument.getClass());
            }
            System.out.println("-----------------------------------------------------------");
        }
    }
}
interface java.util.Map
interface java.util.Map
interface java.util.List
--------------------------------------------------------------
interface java.util.Map
-----------------------------------------------------------
java.util.Map<java.lang.String, java.lang.Object>
-----------------------------------------------------------
class java.lang.Class
class java.lang.Class
-----------------------------------------------------------
java.util.List<java.lang.String>
-----------------------------------------------------------
class java.lang.Class
-----------------------------------------------------------

反射与注解的结合

@HuwcTable("hwc_users")
public class User {
    @HuwcField(colName = "id", type = "int", length = 10)
    private int id ;
    @HuwcField(colName = "name", type = "int", length = 30)
    private String name ;
    @HuwcField(colName = "password", type = "int", length = 20)
    private String password ;

    public static void main(String[] args) throws NoSuchFieldException {
        Class c1 = User.class;
        //获取类注解
        HuwcTable huwcTable = (HuwcTable) c1.getAnnotation(HuwcTable.class);
        System.out.println(huwcTable.value());

        Field idField = c1.getDeclaredField("id");
        Field nameField = c1.getDeclaredField("name");
        Field passwordField = c1.getDeclaredField("password");

        HuwcField anno1 = idField.getAnnotation(HuwcField.class);
        System.out.println("colName : " + anno1.colName());
        System.out.println("type : " + anno1.type());
        System.out.println("length : " + anno1.length());
        System.out.println("---------------------------------------------");
        HuwcField anno2 = nameField.getAnnotation(HuwcField.class);
        System.out.println("colName : " + anno2.colName());
        System.out.println("type : " + anno2.type());
        System.out.println("length : " + anno2.length());
        System.out.println("---------------------------------------------");
        HuwcField anno3 = passwordField.getAnnotation(HuwcField.class);
        System.out.println("colName : " + anno3.colName());
        System.out.println("type : " + anno3.type());
        System.out.println("length : " + anno3.length());
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface HuwcTable {
    String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface HuwcField {
    String colName();
    int length();
    String type();
}
hwc_users
colName : id
type : int
length : 10
---------------------------------------------
colName : name
type : int
length : 30
---------------------------------------------
colName : password
type : int
length : 20

反射性能相关

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Person {

    public String name ;
    private Integer age ;
    private Integer level ;

}

@Test
public void test5() throws NoSuchFieldException, IllegalAccessException {
    Person person = new Person();
    Class c1 = person.getClass();
    Field nameField = c1.getField("name");

    long cnt = 1000000000;
    long start = System.currentTimeMillis();
    for (long i = 0; i < cnt; i++) {
        person.getName();
    }
    long end = System.currentTimeMillis();
    System.out.println("不使用反射的时间:" + (end - start));

    start = System.currentTimeMillis();
    for (long i = 0; i < cnt; i++) {
        nameField.get(person);
    }
    end = System.currentTimeMillis();
    System.out.println("使用反射的时间:" + (end - start));


    start = System.currentTimeMillis();
    nameField.setAccessible(true);
    for (long i = 0; i < cnt; i++) {
        nameField.get(person);
    }
    end = System.currentTimeMillis();
    System.out.println("使用反射并且解除安全校验的时间:" + (end - start));
}

不使用反射的时间:899
使用反射的时间:8587
使用反射并且解除安全校验的时间:6598
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值