JAVA反射(原理+使用)

引言

反射是一种机制,能够使java程序在运行过程中,检查,获取类的基本信息(包,属性,方法等),并且可以操作对象的属性和方法
反射是框架实现的基础

反射的原理

在这里插入图片描述
讲述反射的原理之前,我们先看下java是如何创建对象的

  1. javac将java源文件,编译成 字节码文件(class文件)
  2. JVM 按需加载 字节码文件,将class文件加载为 对应的Class 对象,存放在 堆内存
    (每个class文件只会被加载成一个 Class对象, 因为类只加载一次且类加载是同步机制,只能有一个线程加载这个类)
  3. 根据Class对象 生成 我们熟知的 java对象
    也就是说 平时我们通过new 的方式创建对象就是通过 内存中的Class对象 来创建的。
    而反射是如何创建的呢?可以看下面这张图
    在这里插入图片描述

首先可以确定的是,反射也是通过 Class对象来创建的。因为只有Class对象 有目标对象的详细信息。
与new 一个对象不同的是:
反射在执行之前,不知道自己要创建什么样的类,甚至不知道这个类是否存在,所以说,反射只有在运行到自己时,才能获取Class对象。也只有在运行时,可以检查和使用对应的类信息。

如上图 红色箭头所指,反射是在运行时,根据用户配置的参数(全限定名等)获取对应的Class对象,然后才能创建对象。

那么这样有什么好处呢?

根据反射可以通过类名参数,动态的生成对象,降低了耦合性,可以使程序更加灵活,几乎所有的框架技术都是依赖反射完成的

有什么弊端?

前面说了,反射是在运行时去找自己的Class对象,那么就有一些问题要处理,这个Class对象是否真的存在,或者是否合法等。处理这些问题自然需要时间的,所以反射的性能肯定不如直接new对象

但以现在的硬件水平,这种差距几乎是微乎其微的
new 一个对象 是在 编译期就进行了合法性检查

反射的使用介绍

相关类

java.lang.Class

代表一个类,Class对象表示某个类加载后在堆中的对象
内部含有类的所有信息,是创建的对象的关键
获得方法

// 1. 通过对象类
Class<Cat> cls1 = Cat.class;
Cat cat1 = cls1.newInstance();

// 2. 通过全限定名
Class<?> cls2 = Class.forName("com.wenzhen.interview.basics.reflection.Cat");
Cat cat2 = (Cat) cls2.newInstance();

// 3. 通过对象
Cat cat = new Cat();
Class<? extends Cat> cls3 = cat.getClass();
Cat cat3 = cls3.newInstance();

// 4. 通过类加载器(4种)
ClassLoader classLoader = cat.getClass().getClassLoader();
Class<?> aClass = classLoader.loadClass("com.wenzhen.interview.basics.reflection.Cat");

// 5. 包装类
Class<Integer> type = Integer.TYPE; // 此时获取的是 int.class
Class<Integer> integerClass = Integer.class; // 这个才是真正的包装类的class

java.lang.reflect.Field

代表类的成员变量,Field对象表示某个类的成员变量
使用案例

Class<Cat> cls1 = Cat.class;
Cat cat = cls1.newInstance();//实例化
System.out.println(cat);//Cat(id=null, name=null)
//cls1.getFields() 只能获取public 修饰的属性
Field[] fields = cls1.getDeclaredFields();//获取全部声明的属性
for (Field field : fields) {
    field.setAccessible(true);//设置访问允许,//取消反射在方法调用时安全检查 破坏封装性,可以直接操作私有成员变量,提高性能
    System.out.println(field.getName());//id,name
    field.set(cat,"1");//设置属性值
}
System.out.println(cat);//Cat(id=1, name=1)

java.lang.reflect.Method

代表类的方法,Method对象表示某个类的方法
使用案例

Class<Cat> cls1 = Cat.class;
Cat cat = cls1.newInstance();//实例化
Field name = cls1.getDeclaredField("name");
name.setAccessible(true);
name.set(cat,"五花肉");//设置属性值,猫咪叫 五花肉
//cls1.getMethods() 只能获取public修饰的方法
Method[] declaredMethods = cls1.getDeclaredMethods();//获取全部方法
for (Method method : declaredMethods) {
    if(!"cry".equals(method.getName())){
        //排除非cry的方法
        continue;
    }
    method.setAccessible(true);//设置访问允许
    if(method.getParameterCount() == 0){
        //如果一个参数,执行无参方法
        Object invoke = method.invoke(cat);//五花肉: 喵喵
    }else if(method.getParameterCount() == 1){
        //如果一个参数,执行有参方法,多个参数以此类推
        Object invoke = method.invoke(cat,"hihi");//五花肉: hihi
    }
}

java.lang.reflect.Constructor

代表类的构造方法,Constructor对象表示构造器
使用案例

Class<Cat> cls1 = Cat.class;
Constructor<Cat> constructor = cls1.getConstructor();//无参构造
Cat cat = constructor.newInstance();
System.out.println(cat);//Cat(id=null, name=null)
Constructor<Cat> constructor1 = cls1.getConstructor(String.class);//有参构造(一个参数)
Cat cat1 = constructor1.newInstance("五花肉");
System.out.println(cat1);//Cat(id=null, name=五花肉)

Constructor<Cat> constructor2 = cls1.getConstructor(String.class,String.class);//有参构造(两个参数)
Cat cat2 = constructor2.newInstance("1","五花肉");
System.out.println(cat2);//Cat(id=1, name=五花肉)

常用方法介绍

Class<Cat> cls1 = Cat.class;
//getName:获取全类名
System.out.println(cls1.getName());//com.wenzhen.interview.basics.reflection.Cat
//getSimpleName 获取简单类名
System.out.println(cls1.getSimpleName());//Cat
//getPackage 以Package形式返回 包信息
System.out.println(cls1.getPackage());//package com.wenzhen.interview.basics.reflection
//getSuperClass 以Class形式返回父类信息
Class<?> superclass = cls1.getSuperclass();
System.out.println(superclass);//class com.wenzhen.interview.basics.reflection.Animal
//getInterfaces 以Class[]形式返回接口信息
Class<?>[] interfaces = cls1.getInterfaces();
for (Class<?> anInterface : interfaces) {
    System.out.println(anInterface);//interface com.wenzhen.interview.basics.reflection.Base
}
Annotation[] annotations = cls1.getAnnotations();
for (Annotation annotation : annotations) {
    //注意:Lombok 在编译时生成代码,生成的代码不包括注解信息
    System.out.println(annotation);//注解信息
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

RwTo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值