反射
通过集成开发环境(IDE
)创建程序时,可以通过.
检查可用的方法,并返回方法名;通过远程方法调用(RMI)
允许将一个Java程序对象分布到多台机器上.反射机制
为上述功能实现保证.
来看看什么是反射机制.
Java代码在计算机中经历三个阶段:Source
源代码阶段,Class
类对象阶段,Runtime
运行时阶段
Person类的Java源程序
Person.java首先通过javac
编译与平台无关的字节码文件
Person.class,通过类加载器ClassLoader
加载到内存.内存中的Class类对象
包含成员变量
,构造方法
,成员方法
. Runtime运行时阶段
,通过new Person()创建Person对象.
反射机制,将类中的各个组成部分封装为其他对象,可以在程序运行过程中,操作这些对象,实现解耦
,提高程序的可扩展性
.
Class类
与java.lang.reflect
类库一起对反射机制进行支持,该类库包含了Field
,Method
,Constructor
类,这些类在JVM运行时创建,用以表示未知类里对应的成员.
获取Class对象的方式:
Source源代码
阶段:Class.forName("全类名")
多用于配置文件
,将类名定义在配置文件中,读取文件,加载类Class类对象
阶段: 通过类名的属性class获取
多用于参数传递
运行时
阶段: 对象.getClass()
方法在Object类中定义
多用于对象
的获取字节码方式
public static void main(String[] args) throws ClassNotFoundException {
Class cls1 = Class.forName("Test.Person");
System.out.println(cls1);
Class<Person> cls2 = Person.class;
System.out.println(cls2);
Person person = new Person();
Class cls3 = person.getClass();
System.out.println(cls3);
}
cls1,cls2,cls3是同一个对象.同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
Class对象功能:
获取功能:
1.获取成员变量
Field[ ] getFields()
获取public修饰的成员变量
Field getField(String name)
获取所有成员变量
Field[ ] getDeclaredFields()
Field getDeclaredField(String name)
2.获取构造方法
Constructor<?>[ ] getConstructors()
Constructor<T>[ ] getConstructors(类<?> parameterTypes)
Constructor<?>[ ] getDeclaredConstructors()
Constructor<T>[ ] getDeclaredConstructors(类<?> parameterTypes)
3.获取成员方法
Method[ ] getMethods()
Method getMethod(String name,类<?> parameterTypes)
Method[ ] getDeclaredMethods()
Method getDeclaredMethod(String name,类<?> parameterTypes)
4.获取类名
String getName()
Field成员变量获得全类名
操作
1.设置值
void set(Object obj,Object value)
2.获取值
get(Object obj)
3.忽略权限修饰符的安全检查(暴力反射)
setAccessible(true)
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class;
Field[] fields = personClass.getFields();
for (Field field:fields){
System.out.println(field);
}
Field a = personClass.getField("a");
Person person = new Person();
Object o = a.get(person);
System.out.println(o);
a.set(person,"Mark");
System.out.println(person);
}
Constructor构造方法
创建对象
T newInstance(Object...initargs)
可以使用空参构造器:使用Class对象的newInstance()方法
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class;
Constructor constructor =personClass.getConstructor(String.class,int.class);
//创建对象
Object obj=constructor.newInstance("张三",23);
Constructor constructor1 =personClass.getConstructor();
//创建对象
Object obj1=constructor1.newInstance();
//空参构造器
Object obj2=PersonClass.newInstance();
}
Method方法对象
Object invoke(Object obj,Object...args)
执行方法
String getName()
获取方法名
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class;
Method eat = personClass.getMethod("eat");
Person person = new Person();
eat.invoke(person);
}
public static void main(String[] args) throws Exception {
Class<Person> personClass = Person.class;
Method[] methods = personClass.getMethods();
for (Method method:methods){
System.out.println(method);
}
}
案例
需求:写一个框架,可以帮我们创建任意类的对象,并且执行其中任意方法
实现:1.配置文件 2.反射
步骤:将需要创建的对象的全类名和需要执行的方法定义在配置文件中
public static void main(String[] args) throws Exception {
//创建properties
Properties pro = new Properties();
//获取class目录下的配置文件
ClassLoader classLoader = ReflectDemo04.class.getClassLoader();
//获取配置文件对应的字节流
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//获取配置文件中定义的数据
String className = pro.getProperty("className");
String method = pro.getProperty("methodName");
//加载该类进内存
Class cls = Class.forName(className);
//创建对象
Constructor constructor = cls.getConstructor();
Object o = constructor.newInstance();
//获取对象方法
Method method1 = cls.getMethod(method);
//执行方法
method1.invoke(o);
}