1.JVM虚拟机中运行的是class字节码文件,我们编写的 .java源码文件需要java编译器编译成.class文件才能在JVM虚拟机中运行
在黑窗口中输入的 javac ###.java 命令就是将###.java文件编译成字节码文件.
2.可以更进一步的理解,不管是哪种语言编写的字节码文件,只要是一个合法的符合要求的字节码文件,JVM都会跑起来,所以JVM并不是我们想象的只与java语言紧紧的捆绑在一起.就是因为有Java虚拟机(JVM)的存在,java才实现了程序与操作系统的分离.
3.JVM的生命周期
JVM虚拟机有着一个明确的生命周期,java程序开始运行,JVM启动,java程序结束运行,JVM关闭.
任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点
main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程
当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出
4.JVM的运行数据区划分
栈:运行时的单位,解决程序的运行问题,即程序如何运行,如何处理数据
堆:储存的单位,解决数据储存的问题,数据怎么放 放在哪
方法区:java的字节码文件会加载到方法区中
本地方法栈:此区是java语言调用操作系统有关方法的地方
PC寄存器:此区是与操作CPU有关的地方
5.在java中,参数传递是值的传递还是引用的传递呢?
基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的
对象作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数
6.java对象的大小
基本数据类型的大小是固定的
空Object的大小是8byte
Object o = new Object();
它所占用的空间为:4byte(栈) + 8byte(堆)
Class Dog {
int
count;
boolean
flag;
Object ob;
}
其大小为:空对象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小(4byte)=17byte
但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte的最接近8的整数倍的是24,因此此对象的大小为24byte
7.JVM实例和JVM执行引擎实例
JVM实例对应了一个独立运行的java程序,它是进程级别.
JVM执行引擎实例对应了java运行程序中的线程,它属于线程级别
8.JVM内部体系中的三部分
1).类装载器(ClassLoader)子系统
作用:用来装载.class文件
2).执行引擎
作用:执行字节码或者执行本地方法
3).运行时数据区
方法区 堆 栈 PC寄存器 本地方法栈
这里写一个简单的ClassLoader例子
自定义一个MyClassLoader继承ClassLoader抽象类,
public class MyClassLoader extends ClassLoader{
//重写ClassLoader中的findClass方法,将一个字节数组转化为Class类的实例
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bs = null;
try {
bs = loadClassData(name);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return defineClass("classloader_demo.TestClass", bs, 0,bs.length);//从byte[]数组中还原出一个Class对象
}
//将给定路径的.class文件转换为字节数组
private byte[] loadClassData(String filepath) throws Exception {
int n = 0;
BufferedInputStream bInputStream =
new BufferedInputStream(new FileInputStream(new File(filepath)));
//创建一个字节数组缓冲区来接收读取到的字节
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while((n = bInputStream.read()) != -1) {
bos.write(n);
}
bInputStream.close();
bos.close();
return bos.toByteArray();
}
}
自定义类
public class TestClass {
int age;
String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试类
public class Test {
public static void main(String[] args) throws Exception {
MyClassLoader mLoader = new MyClassLoader();
Class c = mLoader.findClass("C:\\Users\\admin\\Desktop\\TestClass.class");
Object object = c.newInstance();
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
};
}
这里首先将TestClass.java文件转化为TestClass.class文件,将字节码文件转换为字节数组,再把字节数组转换为类文件,最后使用反射读取类文件中的所有公共方法,图中就看到输出的log信息啦!