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来着tools\1
//代表dog类的class实例 dog来着tools\1
//load3
//代表sample类的class实例 sample来着tools\3
//代表dog类的class实例 dog来着tools\3

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();
}
}

JVM实践的更多相关文章

  1. JVM - 堆外内存

    看了不少资料,总结下: 堆外内存 / 直接内存(Direct Memory)JDK1.4中引入的NIO类,基于channel和Buffer的I/O方式,可用Native库直接分配堆外内存,然后利用一个 ...

  2. [转帖]支撑双11每秒17.5万单事务 阿里巴巴对JVM都做了些什么?

    支撑双11每秒17.5万单事务 阿里巴巴对JVM都做了些什么? https://mp.weixin.qq.com/s?__biz=MzA3OTg5NjcyMg==&mid=2661671930 ...

  3. 五分钟学Java:如何学习Java面试必考的JVM虚拟机

    原创声明 本文首发于微信公众号[程序员黄小斜] 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 本文思维导图 为什么要学习JVM虚拟机 最近的你有没有参加Java面试呢?你有没有发现,Java ...

  4. java jvm学习笔记五(实践自己写的类装载器)

     欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和 ...

  5. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  6. java之jvm学习笔记五(实践写自己的类装载器)

    java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...

  7. 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载

    <深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...

  8. JVM性能参数调优实践,不会执行Full GC,网站无停滞

    原文来自:http://bbs.csdn.net/topics/310110257 本文只做整理记录,供个人学习. 1 JVM参数调优是个很头痛的问题,设置的不好,JVM不断执行Full GC,导致整 ...

  9. 《深入理解Java虚拟机:JVM高级特性与最佳实践》读书笔记

    第一部分 走进Java 一.走进Java 1.概述 java广泛应用于嵌入式系统.移动终端.企业服务器.大型机等各种场合,摆脱了硬件平台的束缚,实现了“一次编写,到处运行”的理想 2.java技术体系 ...

随机推荐

  1. mongodb 权限设置--用户名、密码、端口

    转自:http://www.cnblogs.com/valor-xh/p/6369432.html 一.关于权限的默认配置 在默认情况下,mongod是监听在0.0.0.0之上的,任何客户端都可以直接 ...

  2. 总结:JDK1.5-JDK1.8各个新特性

    JDK1.5-JDK1.8各个新特性 JDK各个版本的新特性 要了解一门语言,最好的方式就是要能从基础的版本进行了解,升级的过程,以及升级的新特性,这样才能循序渐进的学好一门语言.以下介绍一下JDK1 ...

  3. Matlab 根号的输入

    二次根号: sqrt(a)或a^0.5 三次根号: x^(1/3)或者x.^(1/3) 根据x的数据结构类型 矩阵.数组需要.^

  4. [Error] 未发现相关 less 编译器配置,请检查wepy.config.js文件

    此错误是由于缺少包引起的 npm install less -d 直接装包即可

  5. DNS协议总结

    1.DNS用于根据域名返回ip地址. 2.一般情况下,DNS-server是通过在UDP协议与客户端之间交互的,UDP端口号是53. 特别注意.DNS有时会使用TCP 53端口与客户端进行交互,所以, ...

  6. [20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt

    [20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt --//链接:http://www.itpub.net/thread-2100456-1-1.html.自己 ...

  7. WPF:验证登录后关闭登录窗口,显示主窗口的解决方法

    http://www.27ba.com/post/145.html WPF:验证登录后关闭登录窗口,显示主窗口的解决方法 最近想做一个基于Socket的通讯工具,想模仿QQ那样,需要先登录,登录成功后 ...

  8. sql server 数据导出(入)方法总结

    我们都知道日常在面对数据需求时需要导出数据,比较少量的数据导出我们一般是通过查询后另存即可,当面对数据量比较大的时候我们应该怎么处理?我搜索总结一些几个方法:1.bcp 导出.2.数据库本身自带的导入 ...

  9. 进程间通信——LINUX

    1.编写一段程序,使用系统调用fork( )创建两个子进程,再用系统调用signal( )让父进  程捕捉键盘上来的中断信号(即按ctrl+c键),当捕捉到中断信号后,父进程用系统调用kill( )向 ...

  10. 改变javascript函数内部this指针指向的三种方法

    在查了大量的资料后,我总结了下面的三条规则,这三条规则,已经可以解决目前我所遇到的所有问题.规则0:函数本身是一个特殊类型,大多数时候,可以认为是一个变量. function a() { alert( ...