1:动态语言:
在运行时,能够改变程序结构和类型。(java不行,如:python,js,ruby)
c,c++,java却可以通过反射,操作字节码获得类似动态的特性。
2.反射机制:
可以在运行时,加载,探索,使用编译期间未知的类型。
在运行时,加载一个只知道类名的类,便能知道这个类的属性和方法,可以用来生成对象,对于对象可以调用其方法和属性。
(加载类,其实就是在堆内存中生成一个Class类型的对象(jvm通过加载器),并且每个类型都只会有一个Class对象。所以Class对象是反射的根源)
3.获取Class:
Class string = Class.forName("com.me.test.reflect.User");//一般用类全名(即包括包名)(之所可以不用,是import了 Class string2 = "stirng".getClass();//通过对象获取 Class string3 = String.class;//通过类型获取
a.数组是不同的维度对应不同的Class
b.像class interface enu void type private等这些关键词代表的意义也是Class类型
4.功能作用:
特别注意对于一些方法对于可变参数(即数组)而言,数组参数要转成Object,如果参数本身就是数组,不转换会该参数的元素被误认为,是多个参数的封装到数组了。
Object object = f.invoke(null, (Object) new String[] { "a", "b" },(Object) new String[] { "aa", "ab" });
获取属性,方法 ,构造器的时候,带declared的方法名才能获取所有范围的,否则只能获取public修饰的。比如:declaredField()和getField()。
Class userClass =Class.forName("com.me.test.reflect.User"); 1.// 获取属性,只能是public修饰的 Field field = userClass.getField("id");// 否则找不到,异常 // 可以是任意范围 Field declaredField = userClass.getDeclaredField("pId"); // public int com.me.test.reflect.User.id----private int // com.me.test.reflect.User.pId System.out.println(field + "----" + declaredField); // 只能获取public属性 Field[] fields = userClass.getFields(); // 所有属性 Field[] declaredF = userClass.getDeclaredFields(); // [public int com.me.test.reflect.User.id] System.out.println(Arrays.toString(fields)); // [private int com.me.test.reflect.User.pId, // public int com.me.test.reflect.User.id, // protected java.lang.String com.me.test.reflect.User.proName] System.out.println(Arrays.toString(declaredF)); 2.//获取无参方法可以不写参数类型 Method getName = userClass.getMethod("getName"); Method setName = userClass.getMethod("setName", String.class); Method declaredsetName = userClass.getDeclaredMethod("setName", String.class); Method[] methods = userClass.getMethods(); Method[] declaredMethods = userClass.getDeclaredMethods(); 3.//获得构造器 Constructor[] constructors = userClass.getConstructors(); Constructor[] declaredconstructors2 = userClass.getDeclaredConstructors(); Constructor<User> constructor = userClass.getConstructor(int.class,String.class); Constructor<User> declaredconstructor2 = userClass.getDeclaredConstructor(int.class,String.class); 4.//创建有参数的对象需要先获得构造器 User newInstance = userClass.newInstance();//无参的字节码对象直接创建 User newInstance2 = constructor.newInstance(1,"大王"); 5.//设置用属性,首先获得属性对象,以及属性所属的对象 field.setAccessible(true);//true表示不进行安全检查, 对于私有属性和方法才能操作 field.set(newInstance,11 ); 6.//调用方法,首先获得方法对象,以及调用方法的对象 declaredsetName.invoke(newInstance, "三王");
5.反射执行效率低于正常执行,比如执行10亿次getName()方法
普通大约:2258ms 1倍
反射大约:62687ms 30倍
不安全检查的反射:14305ms 6倍
6.反射获取泛型:java的泛型只存在编译期,所以为了得到泛型,java提供了一些不属于Class的类型来获取泛型。下面类型和Class类型同属Type的子类型
public void test1(Map<String, User> map, List<User> l) {} public Map<String, User> test2() {return new HashMap<String, User>();} Method test1 = ReflectTest.class.getMethod("test1", Map.class, List.class); // 获得方法的参数类型数组 Type[] genericParameterTypes = test1.getGenericParameterTypes(); // [java.util.Map<java.lang.String, com.me.test.reflect.User>, // java.util.List<com.me.test.reflect.User>] System.out.println(Arrays.toString(genericParameterTypes)); for (Type gType : genericParameterTypes) { // 判断是否是泛型参数 if (gType instanceof ParameterizedType) { // 获得泛型参数中的泛型类型 Type[] actualTypeArguments = ((ParameterizedType) gType).getActualTypeArguments(); // 第一次循环: [class java.lang.String, class com.me.test.reflect.User] // 第二次循环: [class com.me.test.reflect.User] System.out.println(Arrays.toString(actualTypeArguments)); } } Method test2 = ReflectTest.class.getMethod("test2"); // 获得返回类型 Type genericReturnType = test2.getGenericReturnType(); // [java.util.Map<java.lang.String, com.me.test.reflect.User>, // java.util.List<com.me.test.reflect.User>] System.out.println(genericReturnType); // 返回类型是否是泛型 if (genericReturnType instanceof ParameterizedType) { // 获得泛型参数中的泛型类型 Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); // 输出: [class java.lang.String, class com.me.test.reflect.User] System.out.println(Arrays.toString(actualTypeArguments)); }
7.反射获取注解:
8.动态编译:动态的加载一些类文件进行编译。
java1.6引入了动态编译机制之前的类似效果的方式:
Runtime runtime = Runtime.getRuntime(); runtime.exec("javac -cp d:/mytest/ Hello.java");//编译 Process process = runtime.exec("java -cp d:/mytest/ Hello");//运行 //可以从输入流中读取到打印的信息 InputStream inputStream = process.getInputStream();
java6引入了javaCompile类(如果想编译一个字符串的程序,可以考虑先弄成.java文件。)
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler(); // 四个参数in, out, err, arguments,前三个默认是标准输入,输出,错误输出 // 会在同位生成字节码文件,返回0表示成功 int run = systemJavaCompiler.run(null, null, null, "d:/mytest/ Hello.java");
可以通过反射运行字节码:
URL[] urls = new URL[] { new URL("file:/" + "d:/mytest/") };//url不仅可以封装链接,还可以是文件目录(感觉用的少) URLClassLoader classLoader = URLClassLoader.newInstance(urls);// 获得加载器 Class<?> hello = classLoader.loadClass("Hello");// 加载字节码生成Class对象 Method f = hello.getDeclaredMethod("f", String[].class);// void f(String[] s){..} // 对于静态方法可以所属对象可以是null // 特别注意为什么要转成Object,对于可变参数(即数组)而言, // 如果参数本身就是数组,不转换会该参数的元素被误认为,是多个参数的封装到数组了。 Object object = f.invoke(null, (Object) new String[] { "a", "b" });
9.java脚步引擎(1.6引入),通过一套固定的接口,实现和脚步引擎交互,从而可以将一些复杂业务逻辑交给脚本语言处理。比如用js运行字符串“12+3-3*/5=”的计算。
java6中将Rhino(由java语言编写可以实现js)引擎集成了
原文:http://www.cnblogs.com/straybirds/p/6254835.html