• java-java动态性之反射,动态编译,动态执行js及动态字节码操作


    反射图示:

    简单上代码了解一下:

    1.实体类

     1 package com.reflection;
     2 
     3 public class Student {
     4     //学生实体类,包含编号,名字,所属班级的属性
     5     private int id;
     6     private String name;
     7     private String cname;
     8 
     9     public Student() {
    10         super();
    11     }
    12     //构造器
    13     public Student(int id, String name, String cname) {
    14         super();
    15         this.id = id;
    16         this.name = name;
    17         this.cname = cname;
    18     }
    19 
    20     public int getId() {
    21         return id;
    22     }
    23     public void setId(int id) {
    24         this.id = id;
    25     }
    26 
    27     public String getName() {
    28         return name;
    29     }
    30     public void setName(String name) {
    31         this.name = name;
    32     }
    33     
    34     public String getCname() {
    35         return cname;
    36     }
    37     public void setCname(String cname) {
    38         this.cname = cname;
    39     }
    40     
    41 }

    2.方法示例:

      1 package com.reflection;
      2 
      3 import java.lang.reflect.Constructor;
      4 import java.lang.reflect.Field;
      5 import java.lang.reflect.InvocationTargetException;
      6 import java.lang.reflect.Method;
      7 import java.lang.reflect.ParameterizedType;
      8 import java.lang.reflect.Type;
      9 import java.util.ArrayList;
     10 import java.util.List;
     11 
     12 import javax.script.ScriptEngine;
     13 import javax.script.ScriptEngineManager;
     14 import javax.script.ScriptException;
     15 import javax.tools.JavaCompiler;
     16 import javax.tools.ToolProvider;
     17 
     18 import com.sun.javafx.collections.MappingChange.Map;
     19 
     20 /*
     21  * Java动态性:
     22  * 动态语言:
     23  * 程序运行时,可以改变程序结构或变量类型,Java并非动态语言,但其拥有动态性,利用反射机制以及字节码操作获得类似动态语言的特性.
     24  * 一.反射机制:可以于运行时加载,探知,使用编译期间完全未知的类。 
     25  *  (1)PS:程序在运行状态中,可以动态的加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性
     26  *  (2)操作方式:Class c=Class.forName("com.reflection.Reflect");
     27  *  (3)反射:加载完类之后,在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象),该对象包含了完整的类的结构信息,通过这个对象可以看到类的结构,这便是反射。
     28  *  (4)Class类是Reflection的根源:针对任何想要动态加载,运行的类,唯有先获得相应的Class对象。
     29  *  (5)获取Class对象的三种方式: getClass(),Class.forName(),.class语法
     30  *  (6)反射机制的常见作用:
     31  *  动态加载类,动态获取类的信息(属性,方法,构造器)/动态构造对象/动态调用类和对象的任意方法及构造器/
     32  *  动态调用和处理属性/获取泛型信息/处理注解
     33  *  (7)反射机制的性能问题:
     34  *  利用反射执行类方法执行速度大概为类普通方法执行速度的1/30,也就是很慢,效率低,加上setAccessible()后可提高效率
     35  *  setAccessible():启用和禁用访问安全检查的开关,值为true,则表示取消访问安全检查,反之
     36  * 
     37  * 二.动态编译:
     38  * 动态编译的两种做法:
     39  * (1)通过Runtime调用javac,启动新的进程去操作
     40  * ->Runtime run=Runtime.getRuntime();
     41  *   Process process=run.exec("java -cp +类文件绝对路径");
     42  * (2)通过JavaCompiler动态编译
     43  * ->JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
     44  *   int result=compiler.run(null,null,null,sourceFile);
     45  *   第一个参数:为java编译器提供参数  InputStream
     46  *   第二个参数:得到java编译器的输出信息 OutputStream
     47  *   第三个参数:接收编译器的错误信息  
     48  *   第四个参数:可变参数(为String数组)能传入一个或多个java源文件
     49  *   返回值:1表示编译成功,0表示编译失败
     50  * 
     51  * 三.动态执行JavaScript代码:
     52  * Java脚本引擎:
     53  *  使得java的应用程序可以通过一套固定的接口与各种脚本引擎交互,从而达到在Java平台上调用各种脚本语言的目的。
     54  *  可以把一些复杂异变的业务逻辑交给脚本语言处理,大大提高开发效率
     55  *  (1)获得脚本引擎对象:
     56  *  ScriptEngineManager sem=new ScriptEngineManager();
     57  *  ScriptEngine engine=sem.getEngineByName("javascript");
     58  *  功能:
     59  * (1)获取脚本程序输入,通过脚本引擎运行脚本并返回运行结果,这是最核心的接口。 JS使用了Rhino
     60  * (2)通过脚本引擎的运行上下文在脚本和Java平台间交换数据。
     61  * (3)通过Java应用程序调用脚本函数。
     62  *  
     63  * 四.动态字节码操作:
     64  * 功能:动态生成新的类,动态改变某个类的结构(增加,删除,修改 新的属性/方法 )
     65  * 优势:比反射的开销小,性能高,Javassist性能高于反射,低于ASM
     66  * 常见的字节码操作类库:
     67  * BCEL:在实际的JVM指令层次上进行操作,拥有丰富的JVM指令级支持
     68  * ASM:是一个轻量级java字节码操作框架,直接涉及到JVM底层的操作和指令
     69  * CGLIB:是一个强大的,高性能,高质量的code生成类库,基于ASM实现
     70  * Javassist:是一个开源的分析,编辑和创建字节码的类库,性能较ASM差,较cglib差不多,使用简单
     71  * ->最外层的API和JAVA反射包中的API颇为相似:
     72  * 主要由CtClass,CtMethod以及CtField几个类组成,
     73  * 用以执行和JDK反射API中java.lang.Class,java.lang.reflect.Method
     74  * 以及java.lang.reflect.Method.Field相同的操作
     75  * 
     76  * 局限性:
     77  * 不支持泛型,枚举,不支持注释修改,但可以通过底层的javassist类解决
     78  * 不支持数组的初始化,内部类和匿名类,不支持continue,break语句还有部分继承关系
     79  * 
     80  */
     81 
     82 @SuppressWarnings("all")
     83 public class Reflect {
     84 
     85     public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ScriptException {
     86 
     87         try {
     88             getInfoByReflect();
     89             useConstructorByReflect();
     90             useReflectMethod();
     91             getTypeAll();
     92             /*testComplier();*/
     93             scriptEngine();
     94         } catch (ClassNotFoundException e) {
     95             e.printStackTrace();
     96         }
     97 
     98     }
     99 
    100     //通过反射获取Class对象里面对应类的属性
    101     public static void getInfoByReflect() throws ClassNotFoundException {
    102         //获取Student类的Class对象
    103         Class c=Class.forName("com.reflection.Student");
    104         //通过该Class对象获取该类的具体名字(包含包名)及类名
    105         String realName=c.getName();
    106         String name=c.getSimpleName();
    107         System.out.println("具体名字:"+realName+" 类名:"+name);
    108 
    109         //获取类的属性
    110         //Field[] field=c.getFields();//只能获取public的属性
    111         Field[] fields=c.getDeclaredFields();
    112         //获取所有属性
    113         for(Field f:fields) {
    114             System.out.println("属性:"+f);
    115         }
    116         /*获取类所有的方法
    117         PS:如果方法有参,则必须参数类型对应的Class对象
    118         Method m1=c.getDeclaredMethod("getName", null);
    119         Method m2=c.getDeclaredMethod("setName", String.class);*/
    120         Method[] methods=c.getMethods();
    121         for(Method m:methods) {
    122             System.out.println("方法:"+m);
    123         }
    124         //获取类所有的构造器
    125         Constructor[] constructors=    c.getConstructors();
    126         for(Constructor con:constructors) {
    127             System.out.println("构造器:"+con);
    128         }
    129     }
    130 
    131     //通过反射调用构造方法,构造对象,创建记录并将其放入集合中,然后打印出来
    132     public static void useConstructorByReflect() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    133         Class c=Class.forName("com.reflection.Student");
    134         Constructor<Student> cr=c.getConstructor(int.class,String.class,String.class);
    135         Student s1=cr.newInstance(123,"张三","软件一班");
    136         Student s2=cr.newInstance(456,"李四","软件二班");
    137         List<Student> list=new ArrayList<Student>();
    138         list.add(s1);
    139         list.add(s2);
    140         System.out.println("编号:"+list.get(0).getId()+" 姓名:"+list.get(0).getName()+" 班级:"+list.get(0).getCname());
    141         System.out.println("编号:"+list.get(1).getId()+" 姓名:"+list.get(1).getName()+" 班级:"+list.get(1).getCname());
    142     }
    143 
    144     //利用对象里面的方法来对 Student实体类进行初始化数据操作
    145     public static void useReflectMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
    146         Class c2=Class.forName("com.reflection.Student");
    147         Student s3=(Student)c2.newInstance();
    148         //先获取Class对象里面的方法
    149         Method m2=c2.getDeclaredMethod("setName", String.class);
    150         //使用该方法
    151         m2.invoke(s3, "王五");
    152         System.out.println("方法实现后获取值为:"+s3.getName());
    153     }
    154 
    155     //对包含泛型的方法进行处理
    156     public static void getTypeAll() throws NoSuchMethodException, SecurityException {
    157         //获取指定方法泛型参数信息
    158         Method m3=Reflect.class.getMethod("test01",Map.class,List.class);
    159         Type[] types=m3.getGenericParameterTypes();
    160         for(Type t:types) {
    161             System.out.println("#"+t);
    162             if (t instanceof ParameterizedType) {
    163                 Type[] generalType=((ParameterizedType) t).getActualTypeArguments();
    164                 for(Type gtype:generalType) {
    165                     System.out.println("泛型类型为:"+gtype);
    166                 }
    167             }
    168         }
    169         //获取指定方法泛型返回值信息
    170         Method m4=Reflect.class.getMethod("test02", null);
    171         Type returnType=m4.getGenericReturnType();
    172         if(returnType instanceof ParameterizedType) {
    173             Type[] generalType=((ParameterizedType) returnType).getActualTypeArguments();
    174             for(Type gtype:generalType) {
    175                 System.out.println("返回值泛型类型为:"+gtype);
    176             }
    177         }
    178     }
    179 
    180     //动态编译方法实现
    181     public static void testComplier() {
    182         JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
    183         int result=compiler.run(null,null,null,"");
    184         System.out.println(result==0?"编译成功":"编译失败");
    185     }
    186 
    187     //构造一个带泛型参数的方法
    188     public void test01(Map<String,Student> map,List<Student> stu){
    189         System.out.println("测试");
    190     }
    191     //构造一个带泛型返回值的方法
    192     public Map<String,Student> test02(){
    193         return null;
    194     }
    195 
    196     //脚本引擎简单使用
    197     public static void scriptEngine() throws ScriptException {
    198         //获取脚本引擎对象
    199         ScriptEngineManager sem=new ScriptEngineManager();
    200         ScriptEngine engine=sem.getEngineByName("javascript");
    201         //定义变量存储到脚本引擎的上下文中
    202         engine.put("msg", "我很喜欢敲代码!");
    203         System.out.println("获取到的信息为:"+engine.get("msg"));
    204 
    205         String str="var user= {name:'张三',age:18};";
    206         str +="print('用户名:'+user.name);";
    207         //执行脚本
    208         engine.eval(str);
    209         //利用脚本引擎执行javascript的函数
    210         String st="function time() { var a=10,b=a*10;print('最终结果为:'+b);}; time();";
    211         engine.eval(st);           
    212     }
    213 }

    效果截图:

     

    ps:文章待完善,如存在不正之处欢迎大佬指出。

  • 相关阅读:
    [转]Asp.Net 备份和恢复SQL SERVER 数据库
    alert 的封装
    using(sqlConnection conn=new sqlConnection) 中using的作用
    dotnet 上传大文件的配置的方法
    allowDefinition='MachineToApplication'
    转 Server Application Error报错信息的解决方案
    url 自动加入链接
    MVC中使用RadioButtonFor
    linux iptables squid 透明代理
    linux iptables网关配置,端口转发
  • 原文地址:https://www.cnblogs.com/weekstart/p/10838717.html
Copyright © 2020-2023  润新知