在我们生活中,车上或者路上有时候会遇到一种很讨厌的人——“小偷”,趁我们不注意或者疏忽的时候拿走属于我们的东西。更有甚者,趁我们不在家的时候,手持一把万能钥匙,打开我们的房门,悠闲的查看房间的布置,翻找着他们需要的东西,惬意的时候也许会躺在客厅的沙发上,喝着冰箱里的饮料,俨然一副真正主人的样子。在JAVA中就有这样一个存在——“反射”,这是JDK提供的一把万能钥匙,任何人都可以使用它来获取本不应该属于自己的东西。

  在刚学习JAVA的时候,我们就知道,JAVA提供了private,protected,public,default四种修饰符,这四种修饰符象征着我们的使用权限。就好像我们的房子,房子是我们自己的,但是可以被子孙们继承,因此,房子可以被修饰为protected。房子里有的东西是我私人的,只属于我自己,谁都不能用,这可以被修饰为private。当然有的东西,亲戚朋友来了,都可以用,可以吃,那么可以被定义为default。看门外没有垃圾桶,个人本着爱护环境的初衷,放了一个垃圾桶在外面,谁都可以用,垃圾桶自己就可以被修饰为public。但是“小偷”就是没有这种限制,管你东西是不是私人的,他仗着手上的万能钥匙就是可以把这种访问权限糟蹋掉。尤其这把钥匙还是JDK出品的,很无奈!

  那下面就看看JDK提供的这把万能钥匙到底能干些什么吧。

  1、创建House类,代码如下:

package person.lb.reflect;

/**
* 房子
* @author noboudns
*
*/
public class House { //拥有者
private String owner = "nobounds";
//房间数
private int roomNum = 3;
//垃圾桶
public String dustbin = "垃圾桶"; public String getDustbin() {
return dustbin;
} private void turnOnTV() {
System.out.println("打开电视……");
} }

  2、创建KeyDemo 类,代码如下:

package person.lb.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class KeyDemo { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, SecurityException, NoSuchFieldException {
Class<?> clazz = Class.forName("person.lb.reflect.House");
String className = clazz.getName();
System.out.println("户主是:" + className); Field[] fields = clazz.getDeclaredFields();
System.out.println("看看家里都有什么东西:");
for(Field field : fields ) {
System.out.println("类型:" + field.getType() + ",名称:" + field.getName() + ",使用权限:" + Modifier.toString(field.getModifiers()));
} System.out.println("再看看家里有什么好玩的:");
Method[] methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println("名字:" + method.getName()
+ ",需要的东西:" + method.getParameterTypes().toString()
+ ",得到什么:" + method.getReturnType().toString());
System.out.println("用用看效果怎么样,嘿嘿!");
//设置为可访问的
method.setAccessible(true);
method.invoke(clazz.newInstance());
}
System.out.println("心情不错,把房子据为己有吧!");
House house = (House) clazz.newInstance();
Field field = clazz.getDeclaredField("ownerName");
field.setAccessible(true);
field.set(house, "thief");
System.out.println("现在房子的主人是:" + house.getOwnerName() );
}
}

结果为:

户主是:person.lb.reflect.House
看看家里都有什么东西:
类型:class java.lang.String,名称:ownerName,使用权限:private
类型:int,名称:roomNum,使用权限:private
类型:class java.lang.String,名称:dustbin,使用权限:public
再看看家里有什么好玩的:
名字:getOwnerName,需要的东西:[Ljava.lang.Class;@3d4b7453,得到什么:class java.lang.String
用用看效果怎么样,嘿嘿!
名字:getDustbin,需要的东西:[Ljava.lang.Class;@1cc2ea3f,得到什么:class java.lang.String
用用看效果怎么样,嘿嘿!
名字:turnOnTV,需要的东西:[Ljava.lang.Class;@40a0dcd9,得到什么:void
用用看效果怎么样,嘿嘿!
打开电视……
心情不错,把房子据为己有吧!
现在房子的主人是:thief

  当然了,JDK中不止提供了这么多功能,如果有兴趣可以自己私下去查找相关资料,本文就不多说什么了。

  之前因为点儿事随笔写到了这里就发出去了,博友对内容有质疑,因此在这里稍微补充一下。

  我把反射冠名为“反射是小偷的万能钥匙”,虽然听着不好听,但是像这种有特殊能力的人或事物必然有它存在的道理以及特殊性,就像盗墓贼为了私利被称为“贼”,如果被国家收编,那么也能成为一个出色的考古学家。如果专门盗取别人私密数据以及搞破坏的出色黑客弃暗投明,那么很大概率上也能成为一个优秀的安全专家。小偷擅长偷盗,但是做起反偷盗的事情来也是一把好手。在JAVA中反射就被用在很多的框架以及产品中,例如Struts1/2,hibernate,Spring,Tomcat等使用反射不仅很大程度上提高了程序的灵活性,并对框架在加载以及管理Class的时候提供了很大的便利性,以及提供在程序运行时动态更改程序的行为的能力,进而提供丰富的功能,这也更方面了我们开发者。Spring的核心功能IOC和AOP的实现也都应用了JAVA提供的反射功能。那么下面就贴上两段Spring依靠注解注入依赖的源码见识一下。

  org.springframework.util.ReflectionUtils类(反射工具类):

……
  //如果类中的属性不是public修饰或者是final修饰并且属性是不可访问的,那么设置字段为可访问
  public static void makeAccessible(Field field) {
if ((!Modifier.isPublic(field.getModifiers()) ||
!Modifier.isPublic(field.getDeclaringClass().getModifiers()) ||
Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
field.setAccessible(true);
}
} /**
* Make the given method accessible, explicitly setting it accessible if
* necessary. The {@code setAccessible(true)} method is only called
* when actually necessary, to avoid unnecessary conflicts with a JVM
* SecurityManager (if active).
* @param method the method to make accessible
* @see java.lang.reflect.Method#setAccessible
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) ||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
method.setAccessible(true);
}
} /**
* Make the given constructor accessible, explicitly setting it accessible
* if necessary. The {@code setAccessible(true)} method is only called
* when actually necessary, to avoid unnecessary conflicts with a JVM
* SecurityManager (if active).
* @param ctor the constructor to make accessible
* @see java.lang.reflect.Constructor#setAccessible
*/
public static void makeAccessible(Constructor<?> ctor) {
if ((!Modifier.isPublic(ctor.getModifiers()) ||
!Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) {
ctor.setAccessible(true);
}
}
……

  org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor类(@Autowired注解处理类):

……
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement { private final boolean required; private volatile boolean cached = false; private volatile Object cachedFieldValue; public AutowiredFieldElement(Field field, boolean required) {
super(field, null);
this.required = required;
} @Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
try {
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);
}
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
//设置字段访问权限为可访问
ReflectionUtils.makeAccessible(field);
//对字段进行赋值
field.set(bean, value);
}
}
catch (Throwable ex) {
throw new BeanCreationException("Could not autowire field: " + field, ex);
}
}
}
……

我对java的理解(二)——反射是小偷的万能钥匙的更多相关文章

  1. Java基础学习笔记二十三 Java核心语法之反射

    类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任 ...

  2. JAVA基础 (二)反射 深入解析反射机制

    在谈论到反射这个问题时,你是否有例如以下疑问? 不管是在.NET还是Java中反射的原理和机制是一样的,理解了一种还有一种就能够迎刃而解,想要理解反射首先须要了解底层的一些概念和执行.理解了反射有助于 ...

  3. 大白话说Java泛型(二):深入理解通配符

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型(二):深入理解通配符> 上篇文章<大白话说Java泛型(一):入门.原理.使用>,我们讲了泛型的产生缘由以及 ...

  4. 【转】java提高篇(二)-----理解java的三大特性之继承

    [转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...

  5. java反射(二)--反射应用案例

    一.反射实例化对象 经过一系列的分析之后发现虽然可以获取Class类的实例化对象,但是依然觉得这个对象的获取意义不是很大,因此可以通过以下几个案例去理解反射的核心意义--反射实例化对象:获取Class ...

  6. 深入理解Java AIO(二)—— AIO源码解析

    深入理解Java AIO(二)—— AIO源码解析 这篇只是个占位符,占个位置,之后再详细写(这个之后可能是永远) 所以这里只简单说一下我看了个大概的实现原理,具体的等我之后更新(可能不会更新了) 当 ...

  7. Java初始化理解与总结 转载

    Java的初始化可以分为两个部分: (a)类的初始化 (b)对象的创建 一.类的初始化 1.1 概念介绍: 一个类(class)要被使用必须经过装载,连接,初始化这样的过程. 在装载阶段,类装载器会把 ...

  8. java学习:用反射构造bean

    先贴一些反射的基本知识:-------------------------------------------------------------------- 一.什么是反射:反射的概念是由Smit ...

  9. 反射那些事儿——Java动态装载和反射技术

    一直以来反射都是只闻其声,却无法将之使用,近日尽心下来学习下,发现了很多精妙之处. Java动态装载和反射技术 一.类的动态装载 1.Java代码编译和执行的整个过程包含了以下三个重要的机制: ● J ...

随机推荐

  1. 再理解 as3.0接口

    As3.0 接口的理解与运用 1.把接口当作"类"来理解.你easy接受她. 我们看她的标准结构: package 包路径{ public interface 接口名称{ func ...

  2. php_screw加密安装

    php_screw的安装与使用 1.下载:http://sourceforge.net/projects/php-screw/files/ php文件通常以文本格式存贮在服务器端, 很容易被别人读到源 ...

  3. 使用3DES+Base64来加密传输iOS应用数据

    本文转载至 http://www.erblah.com/post/objective-c/shi-yong-3des-base64lai-jia-mi-chuan-shu-iosying-yong-s ...

  4. 【BZOJ2790】[Poi2012]Distance 筛素数+调和级数

    [BZOJ2790][Poi2012]Distance Description 对于两个正整数a.b,这样定义函数d(a,b):每次操作可以选择一个质数p,将a变成a*p或a/p, 如果选择变成a/p ...

  5. 测试站如何最快获取正式站的最新数据: ln -s

    针对静态数据, 比如图片/js等文件, 测试站如何获取最新的呢? ln -s /alidata/www/mysite/uploads /alidata/www/mysite_test/uploads ...

  6. php数据类型的true和false

  7. php本周、本月的第一天 / 最后一天的时间

    //week $time1 = mktime(0, 0, 0, date("m"), date("d") - date("w") + 1, ...

  8. c++操作flash

    c++操作falsh,忘了原文在哪了,自己尝试了,直接贴代码 // SDK版本 //////////////////////////////////////////////////////////// ...

  9. Linux里的发消息

    1.给指定用户发送消息 语法: write 用户名 说明: 1.用户是在线的 2.执行过程 a.敲完命令按回车,进入写信模式 b.写信的时候如果写错了Ctrl+退格 删除字符 c.写完以后Ctrl+D ...

  10. 【Prometheus】第三篇:配置alertmamager

    监控系统中非常重要的一环,就是告警,系统得在故障发生的第一时间将事件发送出来,通知干系人,prometheus提供了alertmanager来实现这个功能. 第一步:prometheus.yml配置文 ...