一、反射是什么
反射,指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法。这种动态获取信息,以及动态调用对象方法的功能,叫做java语言的反射机制;简而言之,反射就是获取Class类对象及其内部信息(方法,属性,构造函数)以及反向控制实例对象的能力
二、反射原理
- 我们编写的java项目,在运行前会编译源文件成为一个个.class文件(字节码文件)
- 在运行时,这些字节码文件会被ClassLoader加载器加载到JVM中,然后通过jvm指令运行起来;此时JVM会在内存中创建一个Class对象
- 我们可以通过Class对象获取Field(成员变量),Methos(成员方法),Constructor(构造函数)
三、反射使用
1.Class对象的获取
class对象的获取一般有三种
System.out.println(Test.class);
System.out.println(new Test().getClass());
System.out.println(Class.forName("com.atguigu.test8.Test"));
运行结果:
2.获取类的成员变量信息
方法 | 用途 |
---|---|
getField(String name) | 获得某个公有属性对象 |
getFields() | 获得所有公有属性对象 |
getDeclaredField(String name) | 获得某个属性对象(public和非public) |
getDeclaredFields() | 获得所有属性对象(public和非public) |
public class Test {
private String name;
public String email;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public static void main(String[] args) throws Exception {
Class clz = Class.forName("com.atguigu.test8.Test");
Test test = (Test) clz.newInstance();
Field[] fields = clz.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
}
}
打印结果
3.获取类的方法
方法 | 用途 |
---|---|
getMethod(String name,Class…<?>parameterTypers) | 获得该类的某个公有方法 |
getMethods() | 获得该类的所有公有方法 |
getDeclaredMethod(String name,Class…<?>parameterTypers) | 获得该类的某个方法(public和非public) |
getDeclaredFields() | 获得所有属性对象(public和非public) |
public class Test {
private String name;
public String email;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public static void main(String[] args) throws Exception {
Class clz = Class.forName("com.atguigu.test8.Test");
Test test = (Test) clz.newInstance();
Method[] methods = clz.getMethods();
for(Method method : methods){
System.out.println(method);
}
}
}
打印结果
3.获取类的构造函数
方法 | 用途 |
---|---|
getConstructor(Class…<?>parameterTypers) | 获得类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class…<?>parameterTypers) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
public class Test {
private String name;
public String email;
public Test(String name,String email){}
public Test(){}
public static void main(String[] args) throws Exception {
Class clz = Class.forName("com.atguigu.test8.Test");
Test test = (Test) clz.newInstance();
Constructor[] constructors = clz.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor);
}
Constructor constructor = clz.getConstructor(String.class,String.class);
Test test1 = (Test) constructor.newInstance("小明","123@qq.com");
System.out.println(test1);
}
打印结果
四、反射实例
这里介绍一下Spring的IOC原理
1、Spring 在项目启动的时间通过读取xml中配置的bean的路径,
2、然后通过Class.forName 读取class 到类加载器,
3、然后通过反射创建所有的bean实例并保存到容器中,启动容器之后,
4、在项目中可以直接获取bean对象。
下面是大概实现此过程的代码
public class ClazzTest {
public static void main(String[] args){
try {
Map<String,Object> container = new HashMap<>();
//1.读取配置
InputStream in = ClazzTest.class.getResourceAsStream("/beans.properties");
Properties property = new Properties();
property.load(in);
//2.反射创建对象
Set<Object> keySet = property.keySet();
for (Object key : keySet) {
// 2.1 获取类的全路径
String classStr = (String) property.get(key);
// 2.2 加载class 到虚拟机
Class<?> beanClazz = Class.forName(classStr);
// 2.3 获取缺省的构造函数
Constructor<?> declaredConstructor = beanClazz.getDeclaredConstructor();
// 2.4 创建实例
Object o = declaredConstructor.newInstance();
container.put((String) key,o);
}
// 3.获取实例
Npc npc = (Npc) container.get("npc");
System.out.println(npc == null);
} catch (Exception e) {
e.printStackTrace();
}
}
}