Java反射应用广泛, 能够配置 : 类的全限定名、方法和参数, 完成对象的初始化, 甚至是反射某些方法. 这样就可以大大增强Java的可配置性, Spring IoC的基本原理也是如此.
反射可以调用私有变量和私有方法
反射机制, 会先拿到目标对象的类对象, 然后通过类对象获取 “构造器对象”, 再通过构造器对象创建一个对象
获取类对象
获取类对象时, 会导致类属性被初始化; 无论什么途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。(除了直接使用 Class c = A.class 这种方式,这种方式不会导致静态属性被初始化)
获取类对象的三种方式
public class A{
}
CLass cl1=Class.forName("com.test.A");
Class cl2=A.class;
class cl3=new A().getClass();
通过反射构建对象
在Java中允许通过反射配置信息构建对象,
ReflectServiceImpl类
package com.IDEA_Project.reflect;
public class ReflectServiceImpl {
public void sayHello(String name){
System.out.println("Hello "+name);
}
//通过反射去构建对象
public ReflectServiceImpl getInstance(){
//用反射产生一个对象, 然后将其返回
ReflectServiceImpl object = null;
try {
object = (ReflectServiceImpl)Class.forName("com.IDEA_Project.reflect").newInstance();
//给类加载器注册了一个类ReflectServiceImpl的全限定名, 然后通过newInstance方法初始化了一个类对象
/* object = (ReflectServiceImpl)Class.forName("com.IDEA_Project.reflect.ReflectServiceImpl").getConstructor().newInstance();
*通过上述方法也可以通过反射创建一个对象
* 会抛出的错误: NoSuchMethodException、InvocationTargetException
*/
}catch (ClassNotFoundException | InstantiationException | IllegalAccessException e){
e.printStackTrace();
}
return object;
}
}
上述类是无参数类, 下面来写有参数的类如何使用反射生成对象
ReflectServiceImpl2类
package com.IDEA_Project.reflect;
import java.lang.reflect.InvocationTargetException;
public class ReflectServiceImpl2 {
private String name;
public ReflectServiceImpl2(String name){
this.name =name;
}
public void sayHello(){
System.out.println("hello"+name);
}
public ReflectServiceImpl2 getInstance(){
ReflectServiceImpl2 object = null;
try {
object = (ReflectServiceImpl2)Class.forName("com.IDEA_Project.reflect.ReflectServiceImpl2")
.getConstructor(String.class)
.newInstance("小王");
/*
先通过forname加载到类的加载器, 然后通过Constructor方法(参数可以是多个,
此处代表有且只有一个参数类型为string的构造方法,通过这个方法可以对重名方法进行排除)
再使用newInstance方法生成对象, 实际效果等于object = new ReflectServiceImpl2("小王");
*/
}catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | NoSuchMethodException
| SecurityException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
return object;
}
}
反射优点 : 配置就可以生成对象, 可以解除程序的耦合度, 比较灵活.
反射缺点 : 运行比较慢
在大部分情况下为了灵活度, 降低程序的耦合度, 我们还是会使用反射 , 比如Spring IoC 容器
反射方法
还是以ReflectServiceImpl类为例
package com.IDEA_Project.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectServiceImpl {
public void sayHello(String name){
System.out.println("Hello "+name);
}
//通过反射去构建对象
public ReflectServiceImpl getInstance(){
//用反射产生一个对象, 然后将其返回
ReflectServiceImpl object = null;
try {
object = (ReflectServiceImpl)Class.forName("com.IDEA_Project.reflect.ReflectServiceImpl").newInstance();
//给类加载器注册了一个类ReflectServiceImpl的全限定名, 然后通过newInstance方法初始化了一个类对象
}catch (ClassNotFoundException | InstantiationException | IllegalAccessException e){
e.printStackTrace();
}
return object;
}
public Object reflectMethod(){
Object returnObj = null;
ReflectServiceImpl target = new ReflectServiceImpl();
try{
Method method = ReflectServiceImpl.class.getMethod("sayHello", String.class);
//第一个参数是方法名称, 第二个参数是参数类型(列表类型)多个参数可以编写多个类型, 这样就能获得反射的方法对象
//target.getClass().getMethod("sayHello", String.class);当不知道具体实现类是哪个时, 也可以使用本行方法
returnObj = method.invoke(target,"小王");
//反射, 使用target对象调用方法,而小王是参数 相当于target.SayHello("小王");
//如果有多个参数method.invoke(target,obj1,obj2,obj3,...);
}catch (NoSuchMethodException| SecurityException
| IllegalAccessException | IllegalArgumentException
| InvocationTargetException e){
e.printStackTrace();
}
return returnObj;
}
}