java虚拟机
参考网站:java语言和虚拟机规范 https://docs.oracle.com/javase/specs/index.html
java虚拟机概念
- java优势:“一次编译到处执行”,可轻松地跨平台运行(虚拟机的功劳,虚拟机可以跨平台)
- java虚拟机的功能:负责其硬件和操作系统独立性、编译代码以及保护用户免受恶意程序侵害的 能力
- java虚拟机是一种抽象计算机(像计算机一样,具有指令集并运行时操作各种内存区域)
- java虚拟机与java无关,只知道特定的二进制格式即
class
文件格式- java编译成class文件后,虚拟机能对其中的
指令集(字节码)、符号表、其他辅助信息
进行处理
- java编译成class文件后,虚拟机能对其中的
- 为安全期间,java虚拟机对class文件中的代码施加了强大的语法和结构约束。但是,任何具有可以用有效的class文件【本地,网络地址】表示的功能的语言都可以由java虚拟机托管
class文件概念
- class结构
- 魔数(magic)
- 副版本号(minor_version)
- 主版本号(major_version)
- 常量池计数器(constant_pool_count)
- 常量数据区
- 访问标志(access_flags)
- 类索引(this_class)
- 父类索引(super_class)
- 接口计数器(interfaces_count)
- 接口信息器
- 字段计数器(fields__count)
- 字段信息数据区
- 方法计数器(methods_count)
- 方法信息数据区
- 属性计数器(attribute_count)
- 属性信息数据区
- 什么是类加载
- 将class文件加载到虚拟机运行内存,生成对应的class对象的过程
- 编译器【java->class】->类加载->运行期 class对象的过程
- 一个java文件 对应 一个class文件 对应 一个class对象
- 类加载过程步骤
- 加载:将class文件加载到虚拟机的过程,class文件 -> class对象
- 连接:
- 验证:验证class文件格式是否正确
- 准备:为静态变量开辟空间,给定对应的默认值
- 解析:将父类和接口的引用指向具体的父类和接口的内存地址
- 初始化:给静态变量声明值,然后调用静态代码块
- java文件、class文件、class对象的区别
- 相同:内容都相同只是体现的形式不同
- 不同:
- java文件包含程序员看懂代码和程序员编写的区域
- class文件是为jvm虚拟机能够读懂
- class对象是将class文件加载到虚拟机运行内存中的体现,
- class对象也成为模板对象,包含声明类的信息,反射技术需要依赖class对象
- 类加载时机:每个类只会被加载一次,生成一个类模板对象
- 遇到创建new时
- 遇到静态方法时
- 遇到访问静态字段(属性)时
- 子类初始化会触发父类的初始化
- 接口定义了方法,直接或间接实现该接口类的初始化,会触发接口的初始化
- 使用反射API对某个类进行反射调用时,初始化这个类
- 虚拟机启动时,初始化用户指定的主类
- java实例化对象
- new创建【编译器】
- 在编译器确定实例类型和方法属性调用位置
- 程序运行时无法动态修改
- new实例化动作底层依赖当前class模板
- 程序主要对象实例化方法
- Reflect反射【运行期】
- 是一种动态机制,运行时能根据class模板完成类的实例化及属性方法的操作
- 能通过方法打破修饰符的限制
类外访问私有方法
- 三方工具和框架都大量使用反射,保证框架的灵活和可拓展性,通过配置童泰实例不同类
- 数据库框架MyBatis支持动态查询,返回结果可以动态指定
- 反射速度慢
- new创建【编译器】
- 反射学习内容:动态实例化对象、动态操作对象属性、动态操作对象方法、打破限制符
class
- 获取Class方法使用
- 类名.class属性
- 对象.getClass()
- Class.forNorName(“类的全限定符 包 类名”) ```java // 获取类的模板对象 Class Student.class; Class new Student().getClass(); Class Class.forName(“com.radiate.Student”);
T newInstance(); // 反射创建对象
// 查看 // 包获取 Package getPackage(); // 获取包信息
// 类获取 String getName(); // 获取类的完全名 Class<? super T> getSuperclass(); // 获取父类
// 接口获取 Class<?>[] getInterfaces(); // 获取所有实现父接口
// 构造器获取
Constructor<?>[] getConstructors(); // 公有(public)构造器
Constructor<?>[] getDeclaredConstructors() // 所有构造器
Constructor
// 方法获取 Method getMethod(String name, Class<?>…parameterTypes);// 指定公有方法名,可选方法形参对象 Method getDeclaredMethod(String name, Class<?>…parameterTypes); // 所有方法名 Method[] getMethods(); // 所有公有(public)方法对象 Method[] getDeclaredMethods(); // 所有方法对象(含父类) Parameter[] Constructor.getParameters(); // 该构造器的参数对象
// 属性、字段获取 Field[] getFields(); // 公有字段对象数组 Field[] getDeclaredFields(); // 所有字段对象数组 Field getField(String name); // 指定公有字段对象 Field getDeclaredFields(String name) // 指定字段对象
// 参数获取 int getParameterCount(); // 获取参数数量 Parameter[] Constructor.getParameters(); // 该构造器的参数对象 Parameter[] getParameters(); // 获取参数信息 Class<?> getReturnType(); // 获取返回值 int getModifiers(); // 获取修饰符编号 // Modifier.toString(getModifiers()) // 编号转字符串英文名
// 反射调用 T Constructor.newInstance(Object…ages); // 调用构造器 void setAccessible(boolean flag); // 设置访问权限(用于修改private权限) void set(Object obj, Object value); // 设置字段值(静态方法obj能使用null) Object invoke(Object, obj, Object…args); // obj: 调用底层方法的对象(静态方法可以直接null) // args: 方法调用所需的参数 // return: 获取并返回方法原有的返回值,Object类型需要判断和转换
<a name="rO6k5"></a>
#
class指令集查看(java反编译)
```java
> javac test.java
> javap -c test.class