初识反射(java.lang.reflect)
什么是反射?
class是一切反射的根源,JAVA反射机制是在运行状态中,对于任和一个类,通过反射都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
反射的原理
在程序运行的时候获取到想要创造实例的类的信息,使用Class类来创建一个对应的实例。避免了使用new关键字,达到在程序运行时动态创建实例的效果。
反射提供的以下几个类,可在类中查询具体的方法
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
如何实现反射
1、获得类的信息(获得到的是类的全路径信息)
获得类的信息有三种方式:
1.使用class类的forName()
方法获取类的信息(比较推荐)
2.使用对象实例的getclass()
方法获得类的信息
3.使用类名.class
获得类的信息
Demo:
/*三种获得反射对象的方法*/
//第一种 Class.forName("全限定类名")
Class class1 = class1 = Class.forName("com.test.entity.One");
//第二种类名.class
Class class2 = One.class;
//第三种对象.getclass
One one = new One();
Class class3 = one.getClass();
System.out.println(class1);
System.out.println(class2);
System.out.println(class3);
//运行结果
class com.test.entity.One
class com.test.entity.One
class com.test.entity.One
当程序运行,第一次加载类时,先将硬盘上.class文件加载内存中,这时类加载器和JVM会根据.class文件生成.class对象,这个对象叫反射对象.一个类只有一 个反射对象.
//类的反射对象只有一个,因为当前类的class字节码文件只有一个
System.out.println(class1 == class2);
System.out.println(class2 == class3);
System.out.println(class1 == class3);
//运行结果
true
true
true
2、使用反射对象获得实例对象
//使用反射对现象获得类的实例对象
//无参构造创建实例对象
One one1 = (One) class1.newInstance();
//有参构造创建实例对象
Constructor constructor = class1.getConstructor(String.class,int.class);
One one2 = (One) constructor.newInstance("张三",20);
System.out.println(one2);
//有参构造方法创建实体类运行结果
One{name='张三', age=20}
3、使用反射对象获得类的属性(Field)
//使用反射对象获得类的私有属性
Field field2 = class1.getDeclaredField("name");
//给属性设置允许访问私有
field2.setAccessible(true);
//给属性设置值,第一个参数是要给哪个实例对象设置当前属性的值
field2.set(one1,"张无忌");
//查看设置结果
System.out.println(one1);
//运行结果
One{name='张无忌', age=0}
也可以一次性获得所有属性的数组
//获得所有私有属性
Field[] field = class1.getDeclaredFields();
for (Field field1 : field) {
System.out.println("属性名称"+field1.getName()+"属性类型"+field1.getType());
}
//运行输出结果
属性名称name属性类型class java.lang.String
属性名称age属性类型int
属性名称father属性类型class java.lang.String
获得公有属性
//获得公有属性
Field field3 = class1.getField("father");
field3.set(one,"张三丰");
//查看设置结果
System.out.println(field3.get(one));
//运行输出结果
张三丰
4、使用反射对象获得类的方法(Method)
/*使用反射对象获得方法*/
//获得私有方法
//第一个参数为方法名,第二个参数开始是参数类型,如果有多个参数,按顺序写入
Method method = class1.getDeclaredMethod("show1");
method.setAccessible(true);//设置允许访问私有
//参数含义是调用哪个实例对象的当前方法
method.invoke(one2);
调用有参方法
//获得私有有参方法
Method method1 = class1.getDeclaredMethod("show2",String.class);
method1.setAccessible(true);
//调用方法,将参数填入,如果多个参数则按顺序填入
method1.invoke(one2,"帅哥");
获得公有方法
//获得公有方法 无需设置访问权限
Method method2 = class1.getMethod("show3");
method2.invoke(one);
反射的用法举例
在这个demo中我有两个类,两个类中各有一个方法
此时如果项目中我是用的是XXX
这个类的方法,但是由于业务需求需要更换成XXXX
中的方法,如果使用常规方法,此时你可能需要修改代码,然后重新编译运行,才能达到效果
package com.test.entity;
public class XXX {
public void X(){
System.out.println("这是XXX的方法");
}
}
package com.test.entity;
public class XXXX {
public void X(){
System.out.println("这是XXXX的方法");
}
}
public static void main(String[] args){
// XXX xxx = new XXX;
// xxx.X();
//重新修改代码
XXXX xxxx = new XXXX();
xxxx.X();
}
但是如果使用反射,则会方便快捷许多
首先准备一个properties配置文件,里面写上两个属性,一个是类名,一个是方法名
classname=com.test.entity.XXXX
methodname=X
然后在测试类中这样写
package com.test.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
File configfile = new File("D:\\IDEACode\\yanjiang\\src\\com\\test\\config\\configfile.properties");
Properties properties = new Properties();
//加载配置文件
properties.load(new FileInputStream(configfile));
//读取配置文件信息
String classname = properties.getProperty("classname");
String methodname = properties.getProperty("methodname");
//获得反射对象
Class clazz = Class.forName(classname);
//使用反射对象获得方法
Method method = clazz.getDeclaredMethod(methodname);
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
method.invoke(obj);
}
}
//运行结果
这是XXXX的方法
此时我们如果要更换类和方法只需要在配置文件中更改即可,无需重新new
对象
其他常用方法
方法 | 含义 |
---|---|
getDeclaredMethods()/getMethods | 获取本类所有的方法(包括私有方法)/获取所有的方法(包括父类的方法) |
getReturnType() | 获得方法的返回值类型 |
getParameterTypes() | 获得方法的传入参数类型 |
getDeclaredMethod(“方法名”,参数类型.class,……) | 获得特定的方法 |
构造方法关键字 | |
getDeclaredConstructors() | 获取所有的构造方法 |
getDeclaredConstructor(参数类型.class,……) | 获取特定的构造方法 |
父类和父接口 | |
getSuperclass() | 获取当前类的父类 |
getInterfaces() | 获取其类实现的接口 |