package JVMLoad;
public class Demo01 {
static{
System.out.println("Demo01类的静态初始化");
}
public static void main(String[] args) throws Exception{
System.out.println("Demo01的main方法");
// 主动引用
// new A();
// System.out.println(A.width);
// Class.forName("JVMLoad.A");
// 被动引用,不会发生类的初始化
// System.out.println(A.MAX);
// A[] as = new A[10];
System.out.println(B.width); // 通过子类的对象调用父类的静态变量时,子类不会被初始化
}
}
class B extends A{
static {
System.out.println("B类的静态初始化");
}
}
class A extends A_Father{
public static int width = 100;
public static final int MAX = 123;
static {
System.out.println("A类的静态初始化");
}
public A(){
System.out.println("A类的构造方法初始化");
}
}
class A_Father{
static {
System.out.println("A_Father类的静态初始化...");
}
}
主动引用
被动引用
被动引用之通过子类对象调用父类静态变量(B extends A)
package JVMLoad;
public class Demo02 {
public static void main(String[] args) {
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(ClassLoader.getSystemClassLoader().getParent());
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
System.out.println(System.getProperty("java.class.path"));
}
}
Idea运行
自定义加载器
命令行编译带包的java原文件
FileSystemClassLoader
package JVMLoad;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 自定义文件系统类加载器
*/
public class FileSystemClassLoader extends ClassLoader{
private String rootDir;
public FileSystemClassLoader(String rootDir){
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
// 先查询有没有加载过这个类.如果已经加载,则直接返回加载好的类.如果没有,则加载
if (c!=null){
return c;
}else {
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); // 委派给父类加载
}catch (Exception e){
}
if (c!=null){
return c;
}else {
// 将指定的class文件转换成byte数组
byte[] classData = getClassData(name);
if (classData == null){
throw new ClassNotFoundException();
}else {
c = defineClass(name, classData, 0, classData.length);
}
}
}
return c;
}
private byte[] getClassData(String classname){
String path = rootDir + "/" + classname.replace(".", "/") + ".class";
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
byte[] buffer = new byte[1024];
int temp = 0;
while ((temp=is.read(buffer))!=-1){
baos.write(buffer, 0, temp);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Demo03
package JVMLoad;
/**
* 测试自定义的FileSystemClassLoader
*/
public class Demo03 {
public static void main(String[] args) throws Exception{
FileSystemClassLoader loader = new FileSystemClassLoader("/home/sweetheart");
FileSystemClassLoader loader2 = new FileSystemClassLoader("/home/sweetheart");
Class<?> c1 = loader.loadClass("JVMLoad.Test");
Class<?> c2 = loader.loadClass("JVMLoad.Test");
Class<?> c3 = loader2.loadClass("JVMLoad.Test");
Class<?> c4 = loader2.loadClass("java.lang.String");
Class<?> c5 = loader2.loadClass("JVMLoad.Demo01");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode()); // 用一个类,被不同的加载器加载,JVM认为也是不相同的类
System.out.println(c3.getClassLoader()); // 自定义加载器
System.out.println(c4.getClassLoader()); // 引导类加载器
System.out.println(c5.getClassLoader()); // 系统默认的类加载器
}
}
网络类加载器
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* 网络类加载器
*/
public class NetClassLoader extends ClassLoader{
private String rootUrl;
public NetClassLoader(String rootDir){
this.rootUrl = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
// 先查询有没有加载过这个类.如果已经加载,则直接返回加载好的类.如果没有,则加载
if (c!=null){
return c;
}else {
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); // 委派给父类加载
}catch (Exception e){
}
if (c!=null){
return c;
}else {
// 将指定的class文件转换成byte数组
byte[] classData = getClassData(name);
if (classData == null){
throw new ClassNotFoundException();
}else {
c = defineClass(name, classData, 0, classData.length);
}
}
}
return c;
}
private byte[] getClassData(String classname){
String path = rootUrl + "/" + classname.replace(".", "/") + ".class";
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
URL url = new URL(path);
is = url.openStream();
byte[] buffer = new byte[1024];
int temp = 0;
while ((temp=is.read(buffer))!=-1){
baos.write(buffer, 0, temp);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
加密解密类加载器
加密工具类
package JVMLoad;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 加密工具类
*/
public class EncrptUtil {
public static void encrpt(String src, String dest){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(dest);
int temp = -1;
while ((temp=fis.read())!=-1){
fos.write(temp^0xff); // 取反操作
}
}catch (IOException e){
e.printStackTrace();
}finally {
if (fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
加载文件系统中加密后的class字节码的类加载器
package JVMLoad;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 加载文件系统中加密后的class字节码的类加载器
*/
public class DecrptClassLoader extends ClassLoader{
private String rootDir;
public DecrptClassLoader(String rootDir){
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> c = findLoadedClass(name);
// 先查询有没有加载过这个类.如果已经加载,则直接返回加载好的类.如果没有,则加载
if (c!=null){
return c;
}else {
ClassLoader parent = this.getParent();
try {
c = parent.loadClass(name); // 委派给父类加载
}catch (Exception e){
}
if (c!=null){
return c;
}else {
// 将指定的class文件转换成byte数组
byte[] classData = getClassData(name);
if (classData == null){
throw new ClassNotFoundException();
}else {
c = defineClass(name, classData, 0, classData.length);
}
}
}
return c;
}
private byte[] getClassData(String classname){
String path = rootDir + "/" + classname.replace(".", "/") + ".class";
InputStream is = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
int temp = -1;
while ((temp=is.read())!=-1){
baos.write(temp^0xff); // 取反操作
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Demo04
package JVMLoad;
/**
* 测试简单加密解密(取反操作)
*/
public class Demo04 {
public static void main(String[] args) throws Exception{
int a = 3; // 00000011
System.out.println(Integer.toBinaryString(a^0xff));
// EncrptUtil.encrpt("/home/sweetheart/JVMLoad/Test.class", "./src/JVMLoad/Test.class");
// FileSystemClassLoader loader = new FileSystemClassLoader("./src");
//
// Class<?> c = loader.loadClass("JVMLoad.Test");
// System.out.println(c);
DecrptClassLoader loader = new DecrptClassLoader("./src");
Class<?> c = loader.loadClass("JVMLoad.Test");
System.out.println(c);
}
}
当用之前普通的类加载器加载时,出现ClassFormatError错误
利用对应的解密类加载器
线程上下文类加载器
package JVMLoad;
public class Demo05 {
public static void main(String[] args) throws Exception{
ClassLoader loader = Demo05.class.getClassLoader();
System.out.println(loader);
ClassLoader loader2 = Thread.currentThread().getContextClassLoader();
System.out.println(loader2);
Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("./"));
System.out.println(Thread.currentThread().getContextClassLoader());
Class<Demo01> c = (Class<Demo01>) Thread.currentThread().getContextClassLoader().loadClass("JVMLoad.Demo01");
System.out.println(c);
System.out.println(c.getClassLoader());
}
}
Tomcat服务器的类加载机制
OSGI