读书人

学习Spring必学的Java基础知识(一)-反

发布时间: 2012-11-06 14:07:00 作者: rapoo

学习Spring必学的Java基础知识(1)----反射
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”。以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助。):

[1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081
[2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293
[3] 属性编辑器,即PropertyEditor-->Spring IoC:http://www.iteye.com/topic/1123628
[4] XML基础知识-->Spring配置:http://www.iteye.com/topic/1123630
[5] 注解-->Spring配置:http://www.iteye.com/topic/1123823
[6] 线程本地变更,即ThreadLocal-->Spring事务管理:http://www.iteye.com/topic/1123824
[7] 事务基础知识-->Spring事务管理:http://www.iteye.com/topic/1124043
[8] 国际化信息-->MVC:http://www.iteye.com/topic/1124044
[9] HTTP报文-->MVC:http://www.iteye.com/topic/1124408




Java语言允许通过程序化的方式间接对Class进行操作,Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数、属性和方法等。Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能,这就为使用程序化方式操作Class对象开辟了途径。

简单实例

我们将从一个简单例子开始探访Java反射机制的征程,下面的Car类拥有两个构造函数、两个方法以及三个属性,如代码清单3-9所示:

代码清单3-9 Car

package com.baobaotao.reflect;public class Car {private String brand;private String color;private int maxSpeed;         //①默认构造函数public Car(){}          //②带参构造函数public Car(String brand,String color,int maxSpeed){ this.brand = brand;this.color = color;this.maxSpeed = maxSpeed;}     //③未带参的方法public void introduce() {        System.out.println("brand:"+brand+";color:"+color+";maxSpeed:" +maxSpeed);}     //省略参数的getter/Setter方法     …}

一般情况下,我们会使用如下的代码创建Car的实例:
Car car = new Car();car.setBrand("红旗CA72");

或者:
Car car = new Car("红旗CA72","黑色");


以上两种方法都采用传统方式的直接调用目标类的方法,下面我们通过Java反射机制以一种更加通用的方式间接地操作目标类:

代码清单3-10 ReflectTest
package com.baobaotao. reflect;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class ReflectTest {public static Car  initByDefaultConst() throws Throwable{//①通过类装载器获取Car类对象ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("com.baobaotao.reflect.Car");           //②获取类的默认构造器对象并通过它实例化CarConstructor cons = clazz.getDeclaredConstructor((Class[])null); Car car = (Car)cons.newInstance();                   //③通过反射方法设置属性Method setBrand = clazz.getMethod("setBrand",String.class);       setBrand.invoke(car,"红旗CA72");Method setColor = clazz.getMethod("setColor",String.class);setColor.invoke(car,"黑色");Method setMaxSpeed = clazz.getMethod("setMaxSpeed",int.class);setMaxSpeed.invoke(car,200);return car;}public static void main(String[] args) throws Throwable {Car car = initByDefaultConst();car.introduce();}}

运行以上程序,在控制台上将打印出以下信息:
public class ClassLoaderTest {public static void main(String[] args) {ClassLoader loader = Thread.currentThread().getContextClassLoader();System.out.println("current loader:"+loader);System.out.println("parent loader:"+loader.getParent());System.out.println("grandparent loader:"+loader.getParent(). getParent());}}
运行以上代码,在控制台上将打出以下信息:


每一个类在JVM中都拥有一个对应的java.lang.Class对象,它提供了类结构信息的描述。数组、枚举、注解以及基本Java类型(如int、double等),甚至void都拥有对应的Class对象。Class没有public的构造方法。Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动构造的。

Java反射机制

Class反射对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类在java.reflect包中定义,下面是最主要的三个反射类:
? Constructor:类的构造函数反射类,通过Class#getConstructors()方法可以获得类的所有构造函数反射对象数组。在JDK5.0中,还可以通过getConstructor(Class... parameterTypes)获取拥有特定入参的构造函数反射对象。Constructor的一个主要方法是newInstance(Object[] initargs),通过该方法可以创建一个对象类的实例,相当于new关键字。在JDK5.0中该方法演化为更为灵活的形式:newInstance (Object... initargs)。? Method:类方法的反射类,通过Class#getDeclaredMethods()方法可以获取类的所有方法反射类对象数组Method[]。在JDK5.0中可以通过getDeclaredMethod(String name, Class... parameterTypes)获取特定签名的方法,name为方法名;Class...为方法入参类型列表。Method最主要的方法是invoke(Object obj, Object[] args),obj表示操作的目标对象;args为方法入参,代码清单3 10③处演示了这个反射类的使用方法。在JDK 5.0中,该方法的形式调整为invoke(Object obj, Object... args)。此外,Method还有很多用于获取类方法更多信息的方法: 1)Class getReturnType():获取方法的返回值类型;
2)Class[] getParameterTypes():获取方法的入参类型数组;
3)Class[] getExceptionTypes():获取方法的异常类型数组;
4)Annotation[][] getParameterAnnotations():获取方法的注解信息,JDK 5.0中的新方法;? Field:类的成员变量的反射类,通过Class#getDeclaredFields()方法可以获取类的成员变量反射对象数组,通过Class#getDeclaredField(String name)则可获取某个特定名称的成员变量反射对象。Field类最主要的方法是set(Object obj, Object value),obj表示操作的目标对象,通过value为目标对象的成员变量设置值。如果成员变量为基础类型,用户可以使用Field类中提供的带类型名的值设置方法,如setBoolean(Object obj, boolean value)、setInt(Object obj, int value)等。
此外,Java还为包提供了Package反射类,在JDK 5.0中还为注解提供了AnnotatedElement反射类。总之,Java的反射体系保证了可以通过程序化的方式访问目标类中所有的元素,对于private或protected的成员变量和方法,只要JVM的安全机制允许,也可以通过反射进行调用,请看下面的例子:

代码清单3-12 PrivateCarReflect
package com.baobaotao.reflect;public class PrivateCar {       //①private成员变量:使用传统的类实例调用方式,只能在本类中访问   private String color;         //②protected方法:使用传统的类实例调用方式,只能在子类和本包中访问   protected void drive(){   System.out.println("drive private car! the color is:"+color);   }}

color变量和drive()方法都是私有的,通过类实例变量无法在外部访问私有变量、调用私有方法的,但通过反射机制却可以绕过这个限制:

代码清单3-13 PrivateCarReflect
…public class PrivateCarReflect {   public static void main(String[] args) throws Throwable{   ClassLoader loader = Thread.currentThread().getContextClassLoader();   Class clazz = loader.loadClass("com.baobaotao.reflect.PrivateCar");   PrivateCar pcar = (PrivateCar)clazz.newInstance();      Field colorFld = clazz.getDeclaredField("color");        //①取消Java语言访问检查以访问private变量   colorFld.setAccessible(true);    colorFld.set(pcar,"红色");      Method driveMtd = clazz.getDeclaredMethod("drive",(Class[])null);        //Method driveMtd = clazz.getDeclaredMethod("drive"); JDK5.0下使用               //②取消Java语言访问检查以访问protected方法   driveMtd.setAccessible(true);         driveMtd.invoke(pcar,(Object[])null);  }}

运行该类,打印出以下信息:
顶一个 讲的挺不错!

读书人网 >编程

热点推荐