目录
1.平台无关性(Complie Once,Run Anywhere)如何实现?
2.JVM如何加载.class文件?
3.谈谈ClassLoader
一、平台无关性(Complie Once,Run Anywhere)如何实现?
Java源码首先被翻译成字节码,在由不同平台的JVM进行解析,Java语言在不同平台上运行时不需要重新编译,Java虚拟机咋执行字节码时,把字节码转换成具体平台上的机器指令。
- 深入一层:为什么JVM不直接将源码解析成机器码去执行?
1.字节码更便于虚拟机读取,不用在解析字符串,所以运行速度比直接解析源代码快。
2.语法是会变的,而源代码中没有版本信息,而字节码中不但有版本信息,还可以经由编译过程抹平一些语言层面的变化(即语言语法虽然有变化,但字节码依然遵照原来的规则即可)。
3.字节码也可以由其他语言生成,如Groovy,Clojure,Scala。需要注意的事,既然这些语言可以编译成字节码,也就可以被Java或其他JVM语言调用。
4.然而归根到底,没有必须这么设计的绝对理由,很多事物之所以会这样,只是因为被设计成这样。
- java机制可以说是中庸之道
- 小tap:javap可以反编译.class文件
二、JVM如何加载.class文件?
1.JVM虚拟机主要包括四个部分:
(1).Class Loader
(2).Runtime Data Area
(3).Execution Engine
(4).Native Interface
- Class Loader:依据特定格式将.class文件加载进内存
- Execution Engine:对命令进行解析
- Native Interface:融合不同开发语言的原生库为java所用
- Runtime Data Area:jvm内存空间结构模型
ClassLoader在java中有着非要重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流,它是java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责将Class文件里的二进制数据流装载进系统,然后交给java虚拟机进行连接,初始化等操作。
深入一步,联系反射:
什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。
反射就是把java类中的属性映射成java对象
写一个反射的例子:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class rc = Class.forName("Robot");
Robot r = (Robot) rc.newInstance();
System.out.println("class name is:" + rc.getName());
Method gethello = rc.getDeclaredMethod("throwHello",String.class);
gethello.setAccessible(true);//把私有方法设置为可访问
Object str = gethello.invoke(r,"Bob");
System.out.println("get" + str);
Method sayhi = rc.getMethod("sayHi", String.class);//只能获取public方法
sayhi.invoke(r,"Welcome");
Field name = rc.getDeclaredField("name");
name.setAccessible(true);
name.set(r,"alice");
sayhi.invoke(r,"welcome");
}
}
三、谈谈ClassLoader
1.先谈谈编译过程:
编译器先将.java源文件编译为.class字节码文件
classloader将字节码转换为jvm中的class<?>对象
jvm利用class<?>去实例化对象
2.再谈谈ClassLoader
- ClassLoader在java中有着非常重要的作用,它主要工作的class装载的加载阶段,其作用是从系统外部获得class二进制数据流。它是java的核心组件,所有的class都是由ClassLoader进行加载的,ClassLoader负责通过将class文件里的二进制数据流装载进系统,然后交给java虚拟机进行连接、初始化等操作。
ClassLoader的种类:
(1).BootStrapClassLoader:C++编写,加载核心库java.✳️
(2).ExtClassLoader:java编写,加载拓展库javax.✳️(java.ext.dirs)
(3).AppClassLoader:java编写,加载程序所在目录
(4).自定义ClassLoaader:java编写,定制化加载
下面实现一个定制化的类加载器Demo
1.MyClassloader.java
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.rmi.server.ExportException;
public class MyClassloader extends ClassLoader {
private String path;
private String classLoaderName;
public MyClassloader(String path,String classLoaderName){
this.path=path;
this.classLoaderName=classLoaderName;
}
//用于寻找类文件
public Class findClass(String name){
byte[] b = loadClassData(name);
return defineClass(name,b,0,b.length);
}
//用于加载类文件
private byte[] loadClassData(String name) {
name = path + name + ".class";
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(new File(name));
out = new ByteArrayOutputStream();
int i = 0;
while ((i = in.read()) != -1){
out.write(i);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
out.close();
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
return out.toByteArray();
}
}
2.ClassLoaderChecker.java
public class ClassLoaderChecker {
public static void main(String[] args) throws Exception {
MyClassloader m = new MyClassloader("/Users/mac/Desktop/", "myClassLoader");
Class c = m.loadClass("Wali");
c.newInstance();
}
}
3.Wali.java
public class Wali{
static {
System.out.println("Hello wali");
}
}
最后运行ClassLoaderChecker主类,输出Hello wali
证明我们成功实现了定制化的类加载器。
Comments | NOTHING