Java反射
重要的事情说三遍,反射真的很重要,很重要,很重要!之前我们在讲类加载的时候提到过一点反射,因此大家可以猜到又要和jvm打打交到了。 关于反射这个概念,其实我从很早之前就开始看了,但是一直处于知道概念,知道怎么用的阶段,还是那句话,学知识最重要的其实还是知道怎么来的,以及它解决了什么问题。按我理解,反射其实可以帮助我们动态的构建耦合性低的代码,说白了就是很灵活。但是,反射也有一些问题,我觉得对于java的封装性是一个挑战(个人意见,我也不确定自己是否完全领悟到了精髓)。好了,我们开始这段神奇的旅程吧!!!
反射:java反射机制就是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用方法的功能称作java反射机制。
看了这么一大段定义,是不是感觉脑袋有点懵,其实我给大家的重点就在动态二字。那我们如何动态的实现这些功能的呢?以及这些功能有什么用呢?别急,慢慢来。
对于反射,其实中间有一个桥梁,在类加载的时候的主角——Class对象,不知道这是什么的先回去看看类加载。(以下内容纯属我胡编乱造,大神勿喷)
给大家提个问题,为什么这个机制叫作反射而不是正向映射呢?如果我们把映射看作一种正向过程,反射看作一种逆向过程,那么结合类加载,我们似乎可以这样来想:
当我们第一次new()一个对象时,大概会有这样的一个过程: 通过类信息来构建Class对象,并用于之后的实例创建。如果我们把这看做正向映射,那么反射就是不通过实际的类和对象调用方法和属性,而是直接获取Class对象,并且Class对象也是一个类信息的接口,那么我们只要获得了Class对象,就可以获得类的属性和方法啦!感觉就有点像反向获取,而且获取的方法和属性都是以对象的形式存在的。 那下面我们目标就很简单了,如何获取Class对象!!
三种方式:
1.类名.class;
2.object.getClass();
3.Class.forName(String classname);
我们反射本身就是不要用实际的类和对象嘛,所以第一种和第二种其实没有太大的意义。常见的是第三种,是不是很眼熟=.=!
Class.forName("com.mysql.jdbc.Driver"),当时我们说这是在加载jdbc驱动,那么现在你应该有更深的理解了吧!!
好了,我们有什么用呢?看代码:
Shape getShape(String shape) {
// TODO Auto-generated method stub
if(shape == null){
return null;
}
if(shape.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shape.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}
return null;
}
这是Java里面关于工厂模式的一段代码,我们都知道工厂模式的好处,它可以帮助我们新建对象而不用自己去new了,你只需要告诉它你要什么就可以了。问题是什么呢?在java里面我们采用迭代开发的时候是不希望修改以前的代码,不能牵一发而动全身,而要追求的是,你要扩展什么,只需要横向扩展自己的代码就好了,不能够修改上层代码。这就是我一直也在强调的,代码要依赖于接口而不能依赖于具体实现。这样就是不能扩展的代码,现在是圆和矩形,那么我们再加一个三角形,那么这段代码就必须修改,这是不允许的。所以我们可以采用:
public static <T> T getClass(Class<? extends T> clazz) {
T obj = null;
try {
obj = (T) Class.forName(clazz.getName()).newInstance();
// obj = (T)clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
那么这段代码的好处是什么呢,我们只需要传入我们要new的对象,比如:Circle.class,Rectangle.class,Triangle.class。这样我们不管再加入什么形状的,只要它继承了共同的接口并且已经完成类加载,我们就可以这样用,不需要修改上面的代码。是不是就有点动态的感觉了呢?
那么,现在你是不是应该去查一下new()和newInstance()的区别呢?我这就不多说,网上说的很多。
之前说过反射是可以动态获取方法和属性的,我们已经看了一个newInstance()静态方法了,还有什么呢?其实方法和属性都被封装成对象了,比如:
Field[] fieldArray = stuClass.getDeclaredFields();
for(Field f:fieldArray){
System.out.println(f);
}
这就能获取所有的声明过的字段了,stuClass是Student对象的Class对象。
方法是一样的,Method[] methodArray=stuClass.getDeclaredMethods();如果要获取某一方法,调用stuClass.getMethod(String name,Class<?> parameterTypes),然后通过调用invoke()方法传入实参就可以了。
其他的如越过泛型检查之类的就不细说了,需要一些泛型知识,有机会再更吧。