Java 反射机制总结
关于反射:
part1:备用知识:一般认同的定义是:程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。Perl,Python,Ruby是动态语言,而java和c++、c#是静态语言。但是不同于c++,java有一个非常突出的动态机制,就是反射。
part2:两个术语:
Reflection反射。 我们可以于运行时加载、探知、使用编译期间完全未知的classes。即Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods 定义),并生成其对象实体、或对其fields设值、或唤起其methods。
introspection反省,内省。the ability of the program to examine itself。是一种看透自己的能力。
part3:一般流程:获得类型类->通过类型类获取当前运行的类的相关信息(获得相应方法、字段、或者实例)
1.获得某个类的类型类:
class<?> type=对象.getClass()=类.class=Class.ForName("包.类");
tips:所有类的对象其实都是Class的实例
2.通过类型类获取该类型的相关信息:
类型类.getName() 获得此类运行时的类名
.getSuperclass() 获得此类运行时的父类类型类
.getInterfaces()获得此类运行时的所拥有的接口类型类
Class<?> demo=Class.forName( "Reflect.Person" );
Person per=(Person)demo.newInstance();
注意要用无参数的构造函数必须保证有无参数的构造函数。比如:你写了一个有参数的构造函数,默认构造函数就被覆盖了,所以要再自己写一个无参构造函数。
否则报错:
b.通过有参数的构造函数,需要提取他的构造函数
public Object newInstance(String className, Object[] args) throws Exception {
Class newoneClass = Class.forName(className);
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
Constructor cons = newoneClass.getConstructor(argsClass);
return cons.newInstance(args);
}
part3:用途:spring ,struts,hibernate中都有用到,通过配置文件改进Class.ForName("path")中每次都要改动类的所在路径(包名+类名),而改变代码的麻烦。实现不用修改源码来改变代码的功能。
没用反射前(工厂模式):
interface fruit{ public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } } // 构造工厂类 class Factory{ public static fruit getInstance(String fruitName){ fruit f=null; if("Apple".equals(fruitName)){ f=new Apple(); } if("Orange".equals(fruitName)){ f=new Orange(); } return f; } } class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Orange"); f.eat(); } }
用了反射后:
package Reflect; interface fruit{ public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } } class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance();//ClassName在配置文件中取出来 }catch (Exception e) { e.printStackTrace(); } return f; } } class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Reflect.Apple"); if(f!=null){ f.eat(); } } }
plus:
1.Class 、Field 、Constructor 等类中的getModifiers() 方法: 以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符.public为3,private、protected都有对应的值 。可以用Modifier.isPublic(Classname.getModifiers())来判断修饰符是否是哪个。
2.invoke方法:通过函数名反射相应的函数
public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
//返回值Object是指meshodName的返回值
Class ownerClass = owner.getClass();
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName,argsClass); //argsClass是所对应参数类型的类类型
return method.invoke(owner, args); //若owner换成null,则表示取出静态方法。args为参数值
}