Java之反射篇

来源:互联网 发布:刀具设计软件 编辑:程序博客网 时间:2024/05/23 02:05

出处:http://blog.csdn.net/snowcoldy/article/details/6744824


1、反射的作用:
反射是一种底层编程(通用编程),利用反射可以写出非常通用的代码
日常实例:
在Eclipse中,当输入类名.方法名的一部分时,整个方法名就会出现在备选框中,这种功能就利用到了反射
 
2、反射的应用范围:
开发工具的编写(例如Eclipse之类的开发工具)
程序框架的开发(例如开发一个模仿Structs的架构)等。
 
3、反射的例子:(请考虑下面三个方法的实现)
static void printMethods(String className) throws Exception
要求:方法的参数为类名,方法的返回值为该类下所有的公开方法
static Object createObject(String className) throws Exception
要求:方法的参数为类名,返回值为一个通过该类的无参构造方法生成的对象
static void methodInvoke(Object o,String methodName) throws Exception
要求:方法的参数是对象和对象的方法名,然后在方法体内部调用该对象的相应方法
 
4、反射的关键:类对象
*类的加载:
当虚拟机要用到一个类的时候
由于虚拟机内部还没有该类的信息
因此虚拟机不知道该如何使用这个类
于是虚拟机需要首先通过classpath找到相应的类
并通过类加载器进行加载(类似于InputStream向虚拟机内部读取)
当这个类被加载到虚拟机中时,必须要保存起来
保存的方式就是:虚拟机需要创建一个该类的对象,用于封装该类的所有信息
这个被创建的该类的对象,就称作类对象
因此,类对象就是用于描述一个类,并且封装了该类内部所有信息的对象
****用于创建类对象以封装类内部信息的类就是:Class类****
 
类比:
在动物园中,认识的任何动物都只是一类动物,而不是某一只动物
例如,当不认识狼的时候,就需要在附近寻找说明牌以了解狼类
当通过了牌子认识了狼类后,以后再遇到狼类则不再需要读牌子
所以说,牌子就是封装了狼类的信息的一个具体对象,而牌子本身又是一个类
因此:一块牌子就是封装了狼类的信息的类的一个对象,而一条狼是狼类的一个对象
 
5、获得类对象的方法:
例如:ArrayList list = new ArrayList();
方法1:Class c1 = ArrayList.class;
//通过类名.class取得该类的类对象
方法2:Class c2 = list.getClass();
//通过该类的对象.getClass()取得该类的类对象
方法3:Class c3 = Class.forName("ArrayList"); (注意双引号)
//通过Class类的forName("className")方法取得该类的类对象
*若不需要返回值,forName方法也可用于强制使虚拟机加载一个类
 
6、类对象(Class)的常用方法:
(Object) o = c.newInstance();  //创建该类的一个对象
String name = c.getName()  //获得该类的类名,返回String对象
Class super = c.getSuperclass()  //获得该类的父类的类对象,返回Class对象
Class [] interface = c.getInterfaces()  //获得该类对象实现的所有接口,返回Class[]数组
(因为接口的信息也是封装在类对象中的)
 
-------------------用于方便阅读的华丽的分界线1-------------------
 
*与Class作用类似的类(属于Reflect包的类):
Field:用于封装某个类中所有属性信息的对象
Method:用于封装某个类中所有方法信息的对象
Constructor:用于封装某个类中所有的构造方法信息的对象
 
Field [] fields1 = c.getDeclaredFields(); //获得该类的所有属性
Field [] fields2 = c.getFields(); //获得该类的所有非private属性
 
Method[] ms1 = c.getDeclaredMethods(); //获得该类的所有方法
Method[] ms2 = c.getMethods(); //获得该类的所有非private方法

Constructor[] cons1=c.getDeclaredConstructors(); //获得该类的所有构造方法
Constructor[] cons2=c.getConstructors(); //获得该类的所有非private构造方法
 
****getDeclaredXXX()与getXXX()的区别****
以Method为例:
c.getDeclaredMethods();方法的返回值为该类中包括private修饰的所有方法,但是不包括父类中的方法
c.getMethods();方法的返回值为该类中以及父类中的所有方法,但是不包括private修饰的方法
 
-------------------用于方便阅读的华丽的分界线2-------------------
 
Method m = c.getDeclaredMethod(String methodName);
//获得类对象c中方法名为methodName,参数为空的方法
Method m = c.getDeclaredMethod(String methodName, Class para);
//获得类对象c中方法名为methodName,参数为para的类的方法
 
 
7、反射例子的实现(例子见3):
1、方法的参数为类名,方法的返回值为该类下所有的公开方法
实现:static void printMethods(String className) throws Exception {
  Class c = Class.forName(className);  //取得该类的类对象
  Method [] ms = c.getDeclaredMethods();  //获得该类所有方法的数组
  for (Method m : ms) {
     System.out.println(m);
  }  //遍历该数组
}
 
2、方法的参数为类名,返回值为一个通过该类的无参构造方法生成的对象
实现:static Object createObject(String className) throws Exception {
  Class c = Class.forName(className);  //取得该类的类对象
  return c.newInstance();  //调用方法创建出该类的一个对象
}
 
3、方法的参数是对象和对象的方法名,然后在方法体内部调用该对象的相应方法
实现:static void methodInvoke(Object o, String methodName, Object parameter) throws Exception {
  Class c = o.getClass();  //获得该对象的类对象

  Method m1 = c.getDeclaredMethod(methodName); //获得类对象内的无参方法m1
  m1.invoke(o);  //调用o中的m1方法
 
  Method m2 = c.getDeclaredMethod(methodName, parameter.class);  //获得类对象内参数为parameter的方法m2
  m2.invoke(o, parameter);  //调用o中的m2方法,并传入参数parameter
}
 
8、反射作为底层技术的最大优势:
由于反射是一种特别底层的技术,而信息的隐藏是构建于反射层面之上的,因此反射可以直接破坏信息的隐藏,例如;
//强制调用TestClass中用private修饰的hidden()方法:
class TestClass {
  private void hidden() {}  //设置此方法为只有该类自身能够访问
}
 
public class TestReflect {
  public static void main (String [] args) {
    TestClass t = new TestClass();  //获得TestClass的对象
    Class c = o.getClass();  //获得TestClass的类对象
    Method m = c.getDeclaredMethod("hidden");  //获得TestClass中的hidden()方法
    m.setAccessible(true);  //强制设置该方法为可访问
    m.invoke(o);  //强制访问t中的该方法
  }
}
 
9、反射滥用的缺点:
-1、破坏了信息隐藏
-2、降低了程序的运行效率以及可读性
-3、让程序中的异常由编译时抛出推迟到了运行时抛出,降低了程序的安全性(即:把编译器应当做的工作让虚拟机去做)

0 0
原创粉丝点击