概念
将类的各个组成部分封装成其他对象,这就是反射机制
好处
在程序运行过程中操作这些对象 可以解耦,提高程序的可扩展性
反射机制的含义及其功能
含义:
反射是被视为动态语言的关键,反射机制能够让程序在执行期间借助Reflection API获取任何类的内部信息,并能直接操作任意对象的内部属性和方法
功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用一个对象的成员变量和方法
生成动态代理
处理流程图
反射相关API
java.lang.Class : 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field: 代表类的成员变量
java.lang.reflect.Constuctor: 代表类的构造方法
Class类
反射可以得到的信息: 某个类的属性,方法和构造器,某个类到底实现了哪些接口. 对于每个类而言,JRE都为其保留一个不变的Class对象, 一个Class对象包含了特定某个类的相关信息
Class本身也是一个类
Class对象只能由系统建立对象
一个类在JVM中只会有一个实例
一个Class对象对应的是一个加载到JVM中的一个.class文件(每个类在编译后会生成一个.class文件)
每个类的实例都会记得自己是由哪个Class实例生成的
通过Class可以完整得到一个类中的完整结构
获取class对象的方式
1.class.forName(“全类名”): 将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中。 读取文件,加载类 全类名: 包名.类名 会抛出ClassNotFoundException的异常
2.类名.class: 通过类名的属性class获取 多用于参数传递
3.对象.getClass(): getClass()方法在Object类中定义
多用于对象的获取字节码的方式
注意
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的class对象都是同一个
演示
package test;
public class main1 {
public static void main ( String[ ] args) throws Exception {
Class cls1 = Class. forName ( "test.main1" ) ;
System. out. println ( cls1) ;
Class cls2 = main1. class ;
System. out. println ( cls2) ;
main1 m= new main1 ( ) ;
Class cls3 = m. getClass ( ) ;
System. out. println ( cls3) ;
System. out. println ( cls1== cls2) ;
System. out. println ( cls1== cls3) ;
System. out. println ( cls2== cls2) ;
}
}
获取一个类的父类和接口
package reflect;
public class main {
public static void main ( String[ ] args) throws Exception {
Class cl1 = Class. forName ( "reflect.stu" ) ;
System. out. println ( cl1. getName ( ) ) ;
Class cl2 = cl1. getSuperclass ( ) ;
System. out. println ( cl2. getName ( ) ) ;
Class[ ] interfaces= cl1. getInterfaces ( ) ;
for ( Class c : interfaces)
System. out. println ( c. getName ( ) ) ;
}
}
获取一个类的构造方法
Constructor[ ] con= cl1. getConstructors ( ) ;
for ( Constructor c: con)
{
System. out. println ( "修饰符:" + c. getModifiers ( ) + " 构造方法:" + c. getName ( ) ) ;
Class[ ] paramClass= c. getParameterTypes ( ) ;
for ( Class c1 : paramClass)
{
System. out. println ( "构造方法: " + c. getName ( ) + " 参数类型: " + c1. getName ( ) ) ;
}
}
System. out. println ( "--------------------------------------------------------" ) ;
Constructor[ ] con1= cl1. getDeclaredConstructors ( ) ;
for ( Constructor c: con1)
{
System. out. println ( "修饰符: " + c. getModifiers ( ) + " 构造方法:" + c. getName ( ) ) ;
Class[ ] paramClass= c. getParameterTypes ( ) ;
for ( Class c1 : paramClass)
{
System. out. println ( "构造方法: " + c. getName ( ) + " 参数类型: " + c1. getName ( ) ) ;
}
}
通过反射创建一个对象
Class cl1 = Class. forName ( "reflect.stu" ) ;
Object obj= cl1. newInstance ( ) ;
stu s= ( stu) obj;
System. out. println ( s. name+ " " + s. age) ;
System. out. println ( "-----------------------------" ) ;
Constructor c= cl1. getConstructor ( String. class , int . class ) ;
stu s2= ( stu) c. newInstance ( "小朋友" , 19 ) ;
System. out. println ( s2. name+ " " + s2. age) ;
System. out. println ( "-----------------------------" ) ;
Constructor c3= cl1. getDeclaredConstructor ( int . class ) ;
c3. setAccessible ( true ) ;
stu s5= ( stu) c3. newInstance ( 100 ) ;
System. out. println ( s5. name+ " " + s5. age) ;
获取一个类的方法
获取到类的所有共有方法
Class cl1 = stu. class ;
Method[ ] mt= cl1. getMethods ( ) ;
for ( Method m: mt)
{
System. out. println ( "方法名: " + m. getName ( ) ) ;
System. out. println ( "返回值类型: " + m. getReturnType ( ) ) ;
System. out. println ( "修饰符: " + m. getModifiers ( ) ) ;
Class[ ] pcs= m. getParameterTypes ( ) ;
if ( pcs!= null&& pcs. length> 0 )
{
for ( Class pc : pcs)
{
System. out. println ( "参数类型: " + pc. getName ( ) ) ;
}
}
}
获取到类的所有方法,包括共有和私有方法,不包括继承方法
Class cl1 = stu. class ;
Method[ ] mt= cl1. getDeclaredMethods ( ) ;
for ( Method m: mt)
{
System. out. println ( "方法名: " + m. getName ( ) ) ;
System. out. println ( "返回值类型: " + m. getReturnType ( ) ) ;
System. out. println ( "修饰符: " + m. getModifiers ( ) ) ;
Class[ ] pcs= m. getParameterTypes ( ) ;
if ( pcs!= null&& pcs. length> 0 )
{
for ( Class pc : pcs)
{
System. out. println ( "参数类型: " + pc. getName ( ) ) ;
}
}
}
获取一个类的属性和包
获取类的所有公有属性,包含父类的公有属性
stu s = new stu ( ) ;
Class c = s. getClass ( ) ;
Field[ ] fs = c. getFields ( ) ;
for ( Field f : fs)
{
System. out. println ( "修饰符: " + f. getModifiers ( ) ) ;
System. out. println ( "属性的类型: " + f. getType ( ) ) ;
System. out. println ( "属性的名称: " + f. getName ( ) ) ;
}
获取类的所有属性,包括私有,但不包括继承至父类的属性
stu s = new stu ( ) ;
Class c = s. getClass ( ) ;
Field[ ] fs = c. getDeclaredFields ( ) ;
for ( Field f : fs)
{
System. out. println ( "修饰符: " + f. getModifiers ( ) ) ;
System. out. println ( "属性的类型: " + f. getType ( ) ) ;
System. out. println ( "属性的名称: " + f. getName ( ) ) ;
}
获取包名
stu s = new stu ( ) ;
Class c = s. getClass ( ) ;
Package p= c. getPackage ( ) ;
System. out. println ( p. getName ( ) ) ;
反射机制调用指定方法
Class c = Class. forName ( "reflect.stu" ) ;
Constructor con= c. getConstructor ( ) ;
Object obj= con. newInstance ( ) ;
Method m= c. getMethod ( "display" ) ;
m. invoke ( obj) ;
System. out. println ( "--------------------" ) ;
Method m1= c. getMethod ( "display" , String. class ) ;
String ret= ( String) m1. invoke ( obj, "大忽悠" ) ;
System. out. println ( "返回值打印:" + ret) ;
System. out. println ( "--------------------" ) ;
m= c. getDeclaredMethod ( "show" ) ;
m. setAccessible ( true ) ;
m. invoke ( obj) ;
System. out. println ( "--------------------" ) ;
m1= c. getDeclaredMethod ( "show" , String. class ) ;
m1. setAccessible ( true ) ;
ret= ( String) m1. invoke ( obj, "小朋友" ) ;
System. out. println ( "返回值打印:" + ret) ;
反射机制调用指定属性
Class c = Class. forName ( "reflect.stu" ) ;
stu s= ( stu) c. newInstance ( ) ;
Field f= c. getField ( "name" ) ;
f. set ( s, "大忽悠" ) ;
String name= ( String) f. get ( s) ;
System. out. println ( "name属性值: " + name) ;
System. out. println ( "-----------------" ) ;
f= c. getDeclaredField ( "age" ) ;
f. setAccessible ( true ) ;
f. set ( s, 18 ) ;
System. out. println ( "私有属性age值: " + f. get ( s) ) ;
JAVA动态代理
其实动态代理很好理解,就是有些情况下我们不能直接对目标类进行一个访问,这个时候就需要中间商,也就是代理对象,我们通过Proxy里的newProxyInstance,指定目标对象的父类接口,它就会根据这个接口里的抽象方法,隐含的在底层实现一个代理类,这个时候肯定有人会问,那实现了代理类,里面重写的方法咋办?,,其实代理类并没有重写接口里的那些方法,是直接通过反射对目标对象里的方法进行的调用,在此基础之上,还可以添加一些额外的非业务逻辑代码,例如日志信息、验证啊啥的,下面是我话的一张草图,希望有助于大家理解。
举例:
一个java项目,有100个类,每个类有10个方法,一共1000个方法 现在要求在每个方法执行前后加上两句话
testDemo接口 :
package reflect;
public interface testDemo {
void test1 ( ) ;
void test2 ( ) ;
}
test实现testDemo接口:
package reflect;
public class test implements testDemo {
@Override
public void test1 ( )
{
System. out. println ( "test1方法执行中..." ) ;
}
@Override
public void test2 ( ) {
System. out. println ( "test2方法执行中...." ) ;
}
}
proxyDemo实现代理类接口:
package reflect;
import java. lang. reflect. InvocationHandler;
import java. lang. reflect. Method;
public class proxyDemo implements InvocationHandler {
Object obj;
proxyDemo ( Object obj)
{
this . obj= obj;
}
@Override
public Object invoke ( Object proxy, Method method, Object[ ] args) throws Throwable {
System. out. println ( method. getName ( ) + "开始执行" ) ;
Object ret= method. invoke ( obj, args) ;
System. out. println ( method. getName ( ) + "执行完毕" ) ;
return ret;
}
}
主函数:
package reflect;
import java. lang. reflect. InvocationHandler;
import java. lang. reflect. Proxy;
public class main {
public static void main ( String[ ] args) throws Exception
{
test t= new test ( ) ;
InvocationHandler handler= new proxyDemo ( t) ;
testDemo t1= ( testDemo) Proxy. newProxyInstance ( handler. getClass ( ) . getClassLoader ( ) , t. getClass ( ) . getInterfaces ( ) , handler) ;
t1. test1 ( ) ;
System. out. println ( "----------------------" ) ;
t1. test2 ( ) ;
}
}
注意
如果一个对象想要通过Proxy.newProxyInstance方式被代理,那么这个对象的类一定要有相应的接口,就像本例中的testDemo接口和test实现接口的类一样
案例
写一个框架,可以帮助我们创建任意类的对象,并且执行其中任意的方法
实现:
配置文件 反射
步骤:
将需要创建的对象的全类名和需要执行的方法定义在配置文件中 在程序中加载读取配置文件 使用反射技术来加载类文件进内存 创建对象 执行方法
代码:
main:
package reflect;
import java. io. InputStream;
import java. lang. reflect. Method;
import java. util. Properties;
public class main {
public static void main ( String[ ] args) throws Exception
{
Properties pro= new Properties ( ) ;
ClassLoader classLoader= main. class . getClassLoader ( ) ;
InputStream is= classLoader. getResourceAsStream ( "pro.properties" ) ;
pro. load ( is) ;
String className= pro. getProperty ( "className" ) ;
String methodName= pro. getProperty ( "methodName" ) ;
Class cls = Class. forName ( className) ;
Object obj= cls. newInstance ( ) ;
Method method= cls. getMethod ( methodName) ;
method. invoke ( obj) ;
}
}
stu类:
package reflect;
public class stu
{
String name;
public void show ( )
{
System. out. println ( "学生的姓名:" + name) ;
}
}
pro.properties配置文件:
className= reflect. stu
methodName= show