Java基础—反射机制


【以TestBean类为例:源码地址 下的 demo-reflect分支】

1、反射介绍

1.1 概念

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象,即反射模板,而解剖使用的就是 Class 类中的方法。所以先要获取到每一个字节码文件对应的 Class 类型的对象。

【注:字节码文件是经过编译器预处理过的一种文件,是Java的执行文件存在形式,它本身是二进制文件,但是不可以被系统直接执行,而是需要虚拟机解释执行,由于被预处理过,所以比一般的解释代码要快,但是仍然会比系统直接执行的慢】

1.2 作用

① 反编译:.class --> .java
② 通过反射机制访问 java 对象的属性、方法和构造方法(即构造器)等

1.3 sun提供的反射机制中的类

java.lang.Class;

java.lang.reflect.Constructor; 

java.lang.reflect.Field;

java.lang.reflect.Method;

java.lang.reflect.Modifier; 【Modifier 修饰器】

注:反射的api在java.lang.reflect包提供


2、具体功能实现

2.1 获取/加载反射模板

在运行的时候,通过对象得到它的字节码,用于操作对象

  • 方式一
/*
① 语法:类.class
即:使用"类名.class"的方式,Object的getClass()方法,返回与该类对应的Class对象 (java中每个类型都有class属性)
*/
Class clazz1 = TestBean.class;

优点:这个方法可以直接获得与指定类关联的Class对象,而并不需要有该类的对象存在。

  • 方式二
/*
② 语法:对象.getClass()
即:Object的 getClass() 方法,返回所封装的类的名称 (java语言中任何一个java对象都有getClass方法)
*/
TestBean testBean = new TestBean(); // 调用了TestBean类得到空构造器
Class clazz2 = testBean.getClass();

  • 方式三
/*	③ 语法:Class.forName()
	即:著名的static方法
*/
Class<?> clazz3 = Class.forName("com.entity.TestBean");

注:1) 该方法会抛出异常,声明抛出ClassNotFoundException异常;
2) forName( )方法需要重点掌握,因为它可以在类不确定的情况下实例化Class,更具灵活性。

小结:
(1) Object -> Class -> 类 -> 对象 ,所有的对象都是 Objec t的子类
(2) Class表示字节码、对象、也表示当前的类,所有的字节码都是Class的对象
(3) 打印出来的形式均是:Class + 类的信息
(4) 也可以使用泛型,如 Class<?> clazz = TestBean.class;
(5) 其他方法:
// getSimpleName() 返回源代码中给出的底层类的简称,如果底层类是匿名,返回一个空字符串;
// getPackage() 得到这个类的包,此方法返回类的包名,或者null(如果没有包的对象是由这个类的类加载器创建的,则返回null )
// getName() 返回Class对象所表示的实体(类,接口,数组类,基本类型或void)的名字,作为一个字符串
// getType() 返回当前实例的运行时类型


2.2 通过反射模板创建对象

语法:反射模板对象.newInstance()
返回值类型:Object

解析:创建此Class对象所表示的类的一个新实例,即获取(或调用)无参构造器;

在面向对象的编程中,通常把用类创建对象的过程称为实例化。多数语言中,实例化一个对象 就是为对象开辟内存空间,或者是不用声明,直接使用

TestBean testBean = (TestBean) clazz.newInstance();

/* 上句代码等效于下面:
* Object obj=clazz.newInstance();
* TestBean testBean=(TestBean) obj;
 */

注:newInstance和new对比:
①newInstance:弱类型,低效率,只能调用无参构造方法
②new:强类型,相对高效,能调用任何public构造方法


2.3 获取属性

2.3.1 获取单一属性

  1. 获取公共的属性:反射对象名.getField(String);
    注:属性对象名.set(类对象名,值); //给哪个对象设置这个属性的值
    属性对象名.get(类对象名); //从哪个对象取这个属性的值

  2. 获取所有的(公共和非公共)属性:反射对象名.getDeclaredField(String);
    补充:访问非公共的属性需要涉及暴力访问
    A. 访问非public的属性需要设置暴力访问,即setAccessible(true);
    B. 访问完成以后再关闭,即setAccessible(false);
    C. 在访问之前应先获取,即boolean bl=对象.isAccessible();
    【isAccessible()值为 true,则指示反射的对象在使用时应该取消 Java 语言访问检查;值为 false 则指示反射的对象应该实施 Java 语言访问检查。实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问。】

  3. 获取公共静态的属性:使用时不用传对象,传null;如果传入对象,会被忽略为null

2.3.2 获取多个属性

  1. 获取模板上所有公共的属性:clazz.getFields()
  2. 获取模板上所有的(公共和非公共)属性:clazz.getDeclaredFields()

2.4 获取方法

2.4.1 获取单一方法

  1. 获取public方法:反射对象名.getMethod(方法名,[该方法的参数类型(可以多个)]);

  2. 获取非公共的方法:反射对象名.getDeclaredMethod(方法名)

  3. 获取public static(公共的静态的)方法:同1

2.4.2 获取所有的方法

  1. 获取该模板的【public方法】和【父类继承的公共的方法】:clazz.getMethods()

  2. 获取该模板所有的,但【不】包括父类继承的方法:clazz.getDeclaredMethods()
    注:方法名.getReturnType() // 获取返回类型


2.5 获取构造器

【见下表】


| 方法关键字 | 描述 |

| getDeclaredField() | 获取所有的方法 |
| getReturnType() | 获取方法的返回类型 |
| getParametr4Types() | 获取方法的传入参数类型 |
| getDeclaredMethod(“方法名”, 参数类型.class, …) | 获取特定的方法 |

| 构造方法关键字 | 描述 |
| getDeclaredConstructors() | 获取所有的构造方法 |
| getDeclaredConstructor(参数类型.class, …) | 获取特定的构造方法 |

| 父类和父接口 | 描述 |
| getSuperclass() | 获取某类的父类 |
| getInterface() | 获取某类实现的接口 |


3、应用场景

JDBC加载驱动
Spring IOC

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值