1.反射的定义
反向探知,在程序运行过程中动态的获取类的相关属性
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制.就叫做JAVA的反射机制
简洁明了的介绍一下反射的优缺点:
优点 增加程序的灵活性,避免固有逻辑写死到程序中 代码相对简洁,可以提高程序的复用性
缺点 相比于直接调用,反射有比较大的性能消耗 内部暴露和安全隐患
反射到底慢在哪里?
1.调用了native方法 2.每次都会做安全检查 比较耗时
反射的使用场景:
1.jdbc封装
2.SpringIOC
3.JdbcTemplate
4.Mybatis
…
2.反射的操作
2.1基本操作
2.1.1.获取类对象的四种方式
假设我们有一个实体类 User
代码语言:javascript复制 // 获取类对象的四种方式
Class<User> class1 = User.class;
Class<?> class2 = Class.forName("类路径名");
Class<? extends User> class3 = new User().getClass();
Class<?> class4 = Demo03.class.getClassLoader().loadClass("类路径名");
2.1.2.基本信息操作
代码语言:javascript复制System.out.println(clazz1.getModifiers()); // 获取类的修饰符(二进制的int值)
System.out.println(clazz1.getPackage());//获取包名
System.out.println(clazz1.getName());//获取类名
System.out.println(clazz1.getSuperclass());//获取父类
System.out.println(clazz1.getClassLoader());//获取类加载器
System.out.println(clazz1.getSimpleName());//获取简单名称
System.out.println(clazz1.getInterfaces().length); // 获取类型实现的所有的接口
System.out.println(clazz1.getAnnotations().length);//获取注解信息
值得一提的是获取类修饰符这个方法的返回值是一个int类型的数据,其解析请看我的这一篇文章 Java反射机制——getModifiers()方法的返回值.
2.2字段的操作
新建一个User类
利用Field对类的字段进行操作
代码语言:javascript复制 /**
* Field操作
* @param args
*/
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
// 获取User对象
User user = userClass.newInstance();
// 获取类型中定义的字段 公有的字段以及父类中公有的字段
//getFields()与getDeclaredFields()方法的区别
Field[] fields1 = userClass.getFields();
for(Field f:fields1){
System.out.println(f.getModifiers() " " f.getName());
}
System.out.println("--------------------");
// 可以获取私有的字段 只能够获取当前类中
Field[] fields2 = userClass.getDeclaredFields();
for(Field f:fields2){
System.out.println(f.getModifiers() " " f.getName());
}
// 获取name字段对应的Field
Field nameField = userClass.getDeclaredField("name");
// 如果要修改私有属性信息那么我们需要放开权限
nameField.setAccessible(true);
nameField.set(user,"小明");
System.out.println(user.getName());
// 如果对静态属性赋值
Field addressField = userClass.getDeclaredField("address");
addressField.set(null,"湖南长沙");
System.out.println(User.address);
}
2.3 类中的方法操作
还是那个User类
代码语言:javascript复制 public static void main(String[] args) throws Exception {
User user = new User();
Class<User> userClass = User.class;
// 可以获取当前类及其父类中的所有的共有的方法
Method[] methods = userClass.getMethods();
for (Method m : methods) {
System.out.println(m.getModifiers() " " m.getName());
}
System.out.println("**********");
// 获取本类中的所有的方法 包括私有的
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method m:declaredMethods){
System.out.println(m.getModifiers() " " m.getName());
}
Method jumpMethod = userClass.getDeclaredMethod("jump");
// 放开私有方法的调用
jumpMethod.setAccessible(true);
jumpMethod.invoke(user);
Method sayMethod = userClass.getDeclaredMethod("say", String.class);
// 静态方法调用
sayMethod.invoke(null,666");
}
2.4 构造器的操作
代码语言:javascript复制 /**
* 构造器的操作
* @param args
*/
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
// 获取所有的公有的构造器
Constructor<?>[] constructors = userClass.getConstructors();
for (Constructor c:constructors){
System.out.println(c.getModifiers() " " c.getName() );
}
System.out.println("************************");
// 获取所有的构造器
Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor c:declaredConstructors){
System.out.println(c.getModifiers() " " c.getName() );
}
// 1.直接通过newInstance创建对象
User user = userClass.newInstance();
// 2.获取对应的Construcator对象获取实例
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
// 私有的构造器调用需要放开权限
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor.newInstance("小明","男"));
}
3.单例的漏洞
产生的原因是:反射可以调用私有的构造器造成的
代码语言:javascript复制public class PersonSingle {
private static PersonSingle instance;
private PersonSingle(){
if(instance != null){
throw new RuntimeException("实例已经存在了,不允许再创建...");
}
}
public static PersonSingle getInstance(){
if(instance == null){
instance = new PersonSingle();
}
return instance;
}
}
解决方案:在私有构造其中加入逻辑判断结合RuntimeException
处理即可
public static void main(String[] args) throws Exception {
PersonSingle p1 = PersonSingle.getInstance();
PersonSingle p2 = PersonSingle.getInstance();
PersonSingle p3 = PersonSingle.getInstance();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
// 通过反射获取实例
Constructor<? extends PersonSingle> declaredConstructor = p1.getClass().getDeclaredConstructor();
declaredConstructor.setAccessible(true);
System.out.println( declaredConstructor.newInstance());
}
4.反射的应用 SpringIOC
IOC 控制反转 就是一种设计思想,容器 管理对象
代码语言:javascript复制try {
// 创建对应IOC容器对象
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
// 配置文件中的<bean> 会被解析封装为一个 BeanDefinition
this.loadBeanDefinitions(beanFactory);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " this.getDisplayName(), var5);
}
代码语言:javascript复制// 加载配置问题 SAX
Document doc = this.doLoadDocument(inputSource, resource);
// 配置文件解析 BeanDefinition
return this.registerBeanDefinitions(doc, resource);
代码语言:javascript复制public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
// 创建IOC容器对象 BeanFactory 同时解析配置文件
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
// 单例对象的实例化
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
代码语言:javascript复制 public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
} catch (InstantiationException var3) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", var3);
} catch (IllegalAccessException var4) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var4);
} catch (IllegalArgumentException var5) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var5);
} catch (InvocationTargetException var6) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", var6.getTargetException());
}
}