Java动态性

Java动态性

动态语言

程序运行时可以改变程序结构或变量类型。典型动态语言:Python、ruby、javascript等

C/C++、Java不是动态语言,但Java可称为“准动态语言”,它有一定动态性,Java的动态性让编程更加灵活。

反射机制

  • 指的是可以于运行时加载、探知、使用编译期间完全未知的类。
  • 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
    Class c = Class.forName("com.bjsxt.test.User");
  • 加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

Class类

javalang.Class类十分特殊,用来表示java中类型(class/interface/enum/annotation/primitive type/void)本身。

  • Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个Class对象。

  • 当一个class被加载,或当加载器(class loader)的defineClass()被 JVM调用,JVM便自动产生一个Class对象。

  • Class类是Reflection的根源。针对任何您想动态加载、运行的类,唯有先获得相应的Class对象

Class类获取

Class clazz = 对象引用.getClass();
Class clazz = 类名.class;
Class clazz = Class.forName("包名.类名");

一个类被加载后,JVM会加载一个对应该类的Class对象,类的整个结构信息会放到该Class对象中。一个类只对应一个反射对象,加载多次也只是那一个。

Class类成员获取

  • 获取成员变量

    import java.lang.reflect.Field;//获取成员变量需导入该包
    
    Field[] fileds = clazz.getFields();//该方法只能获取public属性
    Field[] fileds = clazz.getDeclareFields();//该方法能获取所有属性
    Field[] filed = clazz.getDeclareField("属性名");//该方法能获取指定属性
    
  • 获取类方法

    import java.lang.reflect.Method;//获取类方法需导入该包
    
    Method methods = clazz.getMethods();//该方法只能获取public类方法
    Method methods = clazz.getDeclareMethods();//该方法能获取所有类方法
    Method method = clazz.getDeclareMethod("方法名", 参数类型.class);//该方法能获取指定类方法
    
  • 获取构造器

    import java.lang.reflect.Constructor;//获取构造器需导入该包
    
    Constructor constructors = clazz.getMethods();//该方法只能获取public构造器
    Constructor constructors = clazz.getDeclareMethods();//该方法能获取所有构造器
    Constructor constructor = clazz.getDeclareMethod(参数类型.class);//该方法能获取指定构造器
    

动态操作

  • 动态实例化类对象

    Class<Test> clazz = (Class<Test>)Class.forName("kiang.test.Test");//如果在此处不写泛型,则下面每次实例化都需要强制类型转换
    Test t = clazz.newInstance();//实际上是调用了类的无参构造器(此方法已弃用)
    Test t = clazz.getDeclaredConstructor(int.class, int.class, String.class).newInstance(1,2,"kiang");//现在一般这么用
    
    • 这里有个傻逼问题,至今无解
  • 动态调用普通方法

    Test t = clazz.getDeclaredConstructor(int.class, int.class, String.class).newInstance(1,2,"kiang");
    Method m = clazz.getDeclaredMethod("setName", String.class);
    m.invoke(t, "fuck");
    
  • 动态操作属性

    Test t = clazz.getDeclaredConstructor(int.class, int.class, String.class).newInstance(1,2,"kiang");
    Field field = clazz.getDeclaredField("name");
    field.setAccessible(true);//禁止执行访问安全检查
    field.set(t, "fuck");
    
    • 反射调用会比普通调用更加耗时,禁止执行访问安全检查可以提速几倍,但仍比不上普通调用。

动态编译

Java 6.0引入了动态编译机制。

动态编译的应用场景:

  • 可以做一个浏览端编写Java代码,上传服务器编译和运行的在线测评系统。
  • 服务器动态加载某些类文件。

动态编译的两种做法:

  • 通过Runtime调用javac,启动新的进程去操作。
  • 通过JavaCompiler动态编译。

通过JavaCompiler动态编译

public static int compileFiles(String sourceFile){
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    int result = compiler.run(null, null, null, sourceFile);
    System.out.println(result == 0 ? "编译成功" : "编译失败");
    return result;
}

run方法的四个参数:

  1. 为Java编译器提供参数
  2. 得到Java编译器的输出信息
  3. 接收编译器的错误信息
  4. 可变参数能传入一个或多个(使用String数组)Java源文件
  5. 返回值:0表示编译成功,非0表示编译失败。
posted @   AncilunKiang  阅读(311)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示