一、什么是反射:
看了张老师的视频,第一次发现java中还有这么一个有意思的东西。第一次接触反射就深深的吸引了我。它就像研究黑匣子的工具一样,可以一点一点的挖掘出黑匣子中未知的东西。
查了反射的历史后,才发现,原来反射很早就出现了!它的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。
在计算机科学中,反射被赋予了新的概念。它是指一类应用,它们能够自描述和自控制。
那么反射到底是什么东西呢?还是张老师的总结经典:
反射就是把java类中各种成分映射为相应的java类!!!
二、Java反射中必须学会的类:
如果说反射是攻破黑匣子的工具箱的话,它的工具就是其中的类了。
Java的类反射所需要的类并不多,它们分别是:Class 、Field、Constructor、Method、Object,
Class类:
Class类代表Java类,它的各个实例对象对应各个类在内存中的字节码,
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?他们都属于类类型。
在反射中有三种方法得到各个字节码对应的实例对象(Class类型)
1.类名.class,例如,System.class //需要类已经加载进内存 2.对象.getClass(),例如,new Date().getClass() //需要有类的实例对象 3.Class.forName("类名"),例如,Class.forName("java.util.Date"); //比较常用的方法,相当于做了两件事,把类加载进内存,再得到字节码。得到了字节码, 怎么操作这些字节码呢?表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等。
Field类:
Field类代表某个类中的一个成员变量
根据某个实例对象得到某个类中的一个字段的方法是:Field field = obj.getClass().getField("x");//x为字段名称, //即使字段x是私有的,我们依然有办法得到它,称为暴力反射。Field field = obj.getClass().getDeclaredField("x");field.setAccessible(true);field.get(obj);//用来得到某个对象上x字段的值
Constructor类:
Constructor类代表某个类中的一个构造方法
//得到某个类所有的构造方法例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors(); //得到某一个构造方法例子: Constructorconstructor= Class.forName(“java.lang.String”).getConstructor(StringBuffer.class); //获得方法时要用到类型
得到了构造方法,我们就可以用之创建实例对象:
通常方式:String str = new String("abc"); 反射方式: String str = (String)constructor.newInstance("abc"); //调用获得的方法时要用到上面相同类型的实例对象此时,我们就发现了一个问题,为了搞到一个对象,就这么麻烦,这显然不是我们想要的。而这个问题java的设计人员也帮我们解决了:
Class.newInstance()方法:可以通过字节码直接获得一个类的实例对象
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
其实该方法内部也是先得到默认的构造方法,然后用该构造方法创建实例对象。但是:需要注意的是:该方法只能调用类中无参的构造方法,而如果类里面没有空参的构造方法,就会抛出异常,而此时我们就只能使用第一种方法了。
Method类:
有了对象,我们就该研究下这个对象有什么功能了。那么Method类代表某个类中的一个成员方法
得到类中的某一个方法例子:
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class); //有了这个方法,又怎么调用它呢? // 通常方式:System.out.println(str.charAt(1)); //反射方式: System.out.println(charAt.invoke(str, 1)); //通过Method类中的invoke方法来调用反射出来的方法
注:如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法.
三、反射在开发中的应用
使用反射技术开发框架的原理:
反射的作用-->实现框架功能:因为在写程序时无法知道要被调用的类名,所以在程序中无法直接new某个实例对象,要用反射方式来获取。
框架与工具类的区别,工具类被用户的类调用,而框架则是调用用户提供的类。
用类加载器的方式管理资源和配置文件:
注意:开发时要使用绝对路径,但是绝对路径不是硬编码,应该是运算出来的。
1.使用io读取流读取。
InputStream ips = new FileInputStream("路径");
2.使用类加载器加载。
InputStream ips = ReflectPoint.class.getClassLoaderAsStream("路径");
类提供的简便方法加载: InputStream ips = ReflectPoint.class.getResourceAsStream("name");