• JVM实践


    package com.lsw.classloader;

    import java.io.FileInputStream;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;

    class Parent{
    public static int a=3;
    public int b = 4;
    static {
    System.out.println("Parent static block");
    }
    }
    class MyClassLoader extends ClassLoader {
    private String name = ""; //类加载器的名字
    private String path = "";

    public MyClassLoader(String name) {
    super(); //让系统类加载器成为该类的父加载器
    this.name = name;
    }
    public MyClassLoader(ClassLoader parent,String name){
    super(parent); //显示指定该类加载器的父加载器
    this.name = name;
    }

    private byte[] loadByte(String name) throws Exception {

    String[] names = name.split("\.");

    FileInputStream fis = new FileInputStream(path + names[3] + ".class");
    int len = fis.available();
    byte[] data = new byte[len];
    fis.read(data);
    fis.close();
    return data;

    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
    try {
    byte[] data = loadByte(name);
    return defineClass(name, data, 0, data.length);
    } catch (Exception e) {
    e.printStackTrace();
    throw new ClassNotFoundException();
    }
    }
    public String getPath() {
    return path;
    }
    public void setPath(String path) {
    this.path = path;
    }
    }
    public class Test {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException{
    //初始化流程 1.给类的静态变量赋默认值 a=0 执行静态代码块
    // 2.给静态变量赋初始值a=3
    System.out.println(Parent.a);
    //static方法没有this的方法,在static方法内部不能调用非静态方法,反过来可以
    //而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法,这实际上是static方法的主要用途
    //静态变量和非静态变量的区别:静态变量被所有对象共享,在内存这种只有一个副本,在类初次加载的时候初始化。非静态变量是对象拥有,在对象创建的时候被初始化,存在多个副本
    /*System.out.println(Parent.b); 这种写法可以,因为类没有创建*/
    //连续创建两个Parent对象,静态代码块还是执行一次。说明静态代码块已在内存区域存在(存储在哪里?堆、栈)
    System.out.println(new Parent().b);
    System.out.println(new Parent().b);
    System.out.println("***********************");
    //java.lang.String 由根加载器进行加载 bootstrap
    Class clazz = Class.forName("java.lang.String");
    System.out.println(clazz.getClassLoader()); //结果为null
    //系统加载器或应用加载器加载
    clazz = Class.forName("com.lsw.classloader.Parent");
    System.out.println(clazz.getClassLoader());

    System.out.println("********自定义类的加载***********");
    //应用类加载器 调用默认的构造方法 默认的构造函数父类加载器是应用类加载器
    //父类是系统类加载器 ->扩展类加载器->根类加载器
    MyClassLoader loader1 = new MyClassLoader("loader1");
    loader1.setPath("E:\tools\1\");
    //父类加载器是loader1
    MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");
    loader2.setPath("E:\tools\2\");
    //父类加载器是bootstrap
    MyClassLoader loader3 = new MyClassLoader(null,"loader3");
    loader3.setPath("E:\tools\3\");
    //加载路径解析
    //bootstrap 加载路径从系统属性sun.boot.class.path所指定的目录中加载类库
    //extension jre/lib/ext或者从系统属性java.ext.dirs
    //system 从环境变量 classpath或者系统属性java.class.path
    test(loader1);
    //loader2 加载流程 1.首先委托loader1进行加载 2.loader1发现还有父类-系统类加载器 委托系统类加载器加载
    //3. 系统类依次查找 扩展类加载器加载 根类加载器加载
    //4. 根类加载器没有查找到类,扩展类加载查找,系统类查找,loader1查找到了,loader1进行加载
    //被加载的加载器被称为定义类加载器 所有的加载器可以称为初始类加载器
    test(loader2);
    test(loader3);

    //解析:loader1和loader3在各自的命名空间之中都存在sample类和dog类
    //堆区 方法区
    //load1
    //代表sample类的class实例 sample来着tools1
    //代表dog类的class实例 dog来着tools1
    //load3
    //代表sample类的class实例 sample来着tools3
    //代表dog类的class实例 dog来着tools3

    System.out.println(loader2.getParent());
    ClassLoader loader = ClassLoader.getSystemClassLoader();
    while(loader !=null){
    loader = loader.getParent();
    System.out.println(loader);
    }
    //由于根类加载器是C/C++编写的 所以打印不出任何东西

    //反射
    System.out.println("-----------------------");
    //cls 引用变量 引用的是堆区的myclassloader对象
    Class cls = loader1.loadClass("com.lsw.classloader.Sample");
    //object 引用变量 引用的是堆区的sample类的class对象 指向方法区内的sample二进制数据结构
    Object object = cls.newInstance(); //创建一个sample类的对象
    System.out.println(object);
    //field 引用变量 引用的是堆区的sample对象
    Field field = object.getClass().getField("v1");
    // field = cls.getField("v1");
    int i = field.getInt(object); //the object to extract the int value from
    System.out.println(i);

    }
    public static void test(ClassLoader loader) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
    Class clazz2 = loader.loadClass("com.lsw.classloader.Sample");
    Object obj = clazz2.newInstance();
    }
    }

  • 相关阅读:
    linux一些配置
    tomcat启动后,页面无法访问
    利用jmeter实现多IP压测
    java操作数据库
    excle中表头分割单元格
    常用的最大流算法 Dinic 和 最小费用最大流SPFA写法
    [kuangbin]带你飞之'网络流'专题
    (留坑以后再看)一般图'最大匹配' 带花树 算法
    二分图'多重匹配'
    二分图'最大匹配' HK 算法
  • 原文地址:https://www.cnblogs.com/mutong1228/p/8970888.html
Copyright © 2020-2023  润新知