目录

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证明我们成功实现了定制化的类加载器。


且视他人之疑目如盏盏鬼火,大胆去走自己的夜路。